Creating a custom view using a xib

Based on my experience in obj-c code, I will try the following code:

var views = NSBundle.MainBundle.LoadNib(nibName, this, null); // (1)
MyCustomView myView = Runtime.GetNSObject(views.ValueAt(0)) as MyCustomView; // (2)

(1) allows you to load the xib file

(2) allows you to convert to convert an IntPtr into an appropriately typed NSObject (sub-)type.

Once you have myView you can add it as a traditional view. Check if you have set up the outelt for your view correctly.

P.S. If you provide some other details we could help you. Furthermore, check the code because I've written by hand.


A very very nice question, but it is more about how XIBs work and what we can do about it.

The issue is when you add an object to a XIB and set it to be of a custom class, you just instruct the UIKit to create an instance of this object. The fact you see in IB as a view, a button or a whateverish control is just how IB draws it for you. This way the responsibility for creating the outlook falls completely on your class.

In Objective-C we can do a nice cheat to have XIBs with custom views and still add them to IB by setting the class name of the added view. This is possible because you can return any instance from the -init method of your class in Objective-C, which is not possible with C#.

However, you can still ease your life by doing the following:

  1. Let's define XIB to be a XIB which contains your custom view's content; Placement to be a XIB where you want to add you custom view.
  2. Create you custom view class and a XIB to lay the internals of it
  3. Handle AwakeFromNib method to actually load your XIB
  4. After having loaded your XIB just add the internals of it to your instance as subviews.
  5. Put a regular view and set it class to your own into Placement
  6. Enjoy!

You have, however, to accept that your XIB would contain a root view or something, which would be added as a subview onto the instance of your class put into Placement.

This way, you should have something like:

XIB with your custom view contents:

XIB with your custom view contents

Placement where you add your XIB:

Placement where you add your XIB

As the view instance added to your placement is the same as File Owner in your XIB you can set outlets and actions in both XIB and Placement. Just don't forget you root view in your XIB is not the instance UIKit will create to place into Placement.

For convenience purposes, please find my code below which is base class to ease the creation of such views:

using System;

using MonoTouch.ObjCRuntime;
using MonoTouch.Foundation;
using MonoTouch.UIKit;

namespace Member.iOS.Base.Views {

    /// <summary>
    /// XibView is a Xib-backed UIView subclass which enables easy customization and custom
    /// behavior addition.
    /// </summary>
    public class XibView : UIView {

        /// <summary>
        /// Exception thrown when a loaded XIB doesn't contain any views inside it.
        /// </summary>
        class EmptyXibException : Exception {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Member.iOS.Base.Views.XibView"/> class.
        /// </summary>
        /// <param name='handle'>
        /// Handle.
        /// </param>
        public XibView(IntPtr handle) : base(handle) {
        }

        /// <summary>
        /// Upon loading from a containing XIB, takes care of replacing the current instance (which acts as a stab) with
        /// a real view loaded from its XIB.
        /// </summary>
        public override void AwakeFromNib() {
            base.AwakeFromNib();

            NSArray views = NSBundle.MainBundle.LoadNib(GetType().Name, this, new NSDictionary());

            if (views.Count == 0) {
                throw new EmptyXibException();
            }

            UIView rootView = Runtime.GetNSObject(views.ValueAt(0)) as UIView;
            rootView.Frame = new System.Drawing.RectangleF(0, 0, Frame.Width, Frame.Height);
            AddSubview(rootView);
        }

    }
}