开发者

How can I have multiple UITableViewCell's in a single NIB file, in a MonoTouch iPhone app?

In MonoTouch, there are many examples out there where people load NIB files like this:

var customController = new MyCustomController();
NSBundle.MainBundle.LoadNib("MyCustomController", customController, null);

Based on many code samples I have seen on blog posts, people tend to do this for custom UITableViewCells which they have designed in Interface Builder.

That is all well and good - but perhaps the NIB file contains more than one custom UITableViewCell. I have found a blog post that shows a single NIB file being used that contains multiple custom table cells (in Objective-C): http://pegolon.wordpress.com/2008/11/15/using-uitableviewcell-with-interfacebuilder/

That is doing what I want!

In that Objective-C example, it becomes clear that NSBundle.Ma开发者_Go百科inBundle.LoadNib actually returns something (an NSArray) and then the returned object is iterated over: each object in the NSArray is a table cell "template".

When I try to do this in MonoTouch/C#, I am struggling to iterate over the returned NSArray. It doesn't let me access its contents with array indexers, and it won't let me loop over it.

How can I do it?


Ok, I have managed to get it working. The important thing is how to get objects from an NSArray:

NSArray nsArr = NSBundle.MainBundle.LoadNib("MyCustomController", customController, null);
UITableViewCell = (UITableViewCell)Runtime.GetNSObject(nsArr.ValueAt(0)); // gets the first item

I have also created a sample project and article about how to use custom table cells from nib files:

Custom Table Cells in MonoTouch


As mentioned in a comment to Eduardo Scoz's answer, the workflow described is not possible with XCode 4 without some adjustment. Interface Builder in XCode 4 is not able to subclass for you, you have to do that yourself. Here is the complete workflow in MonoTouch to create a subclassed view without a controller. This is useful for table view cells and other reusable views.

  1. Start by creating a new empty class in MonoTouch. Name the class anything you like.
  2. Open the newly created class file, and inherit from the class you want to. (UIView, UITableViewCell etc.)
  3. Add the attribute [Register("yourClassName")] to the class.
  4. Add the outlets you want by creating a property (It doesn't have to public) with automatic getter and setter. Add the attribute [Outlet] to the property.
  5. Add actions to the class if you want. Declare them like this: [Action("MethodName")] public void MethodName(NSObject sender) {}. I believe it's possible to declare the method private as well, but I haven't tried it.
  6. Create a constructor method with the following signature: public YourClassName(IntPtr ptr) : base(ptr) {}. If you forget this step, you'll get an exception when you try to load the XIB file from code, telling you it couldn't find this constructor.
  7. Make sure you save the file.
  8. Now add a new iPhone or iPad view to your project. (Just a view, not a view controller)
  9. Open the view in Interface Builder by double clicking the view in MonoDevelop.
  10. In Interface Builder, select the view that's already there and open the Identity Inspector.
  11. Change the class to the name of the class you created earlier. Interface Builder should autocomplete the name for you.
  12. Now, set up your view with labels, buttons, etc.
  13. Now, turn on the Assistant View in Interface Builder, if it's not already turned on.
  14. Just look at that! All the outlets and actions you made in the C# class file is in the Objective C class the Assistant is showing. Now you can connect the controls on your view to the existing outlets and actions.
  15. When you're done, make sure you save the XIB file you've been editing and go back to MonoDevelop.

To instantiate the view, you do as Dimitris wrote:

NSArray nsArr = NSBundle.MainBundle.LoadNib("YourViewName", theController, null);
YourClassName instantiatedView = (YourClassName)Runtime.GetNSObject(nsArr.ValueAt(0));

theController is the View Controller that will be set as the view's File Owner. As far as I know, you have to pass a valid View Controller to the method. If you're instantiating the view in a View Controller, you can pass this to the method. And now you can use whatever properties or methods you've defined in your view to change the appearance of the view. So if you've connected a UILabel to the outlet property Name (And it's declared as public), you can use instantiatedView.Name.Text = "John Doe"; However, you should not use this technique to get rid of the view controller in all situations. The view controller is there to seperate responsibilities. So if you need some more complex logic for the view, you should reconsider if this is the right way to go.


I confess I failed on this and took a workaround. I made my cell constructor stick a reference to itself in a static variable, and then accessed that after LoadNib.

I figured I was safe doing this as I only ever instantiated cells from the main thread, and hence I would not have any race conditions causing any problems.

public partial class OrderPrimary : UITableViewCell
{
    static OrderPrimary lastCell;

    public OrderPrimary(IntPtr handle) : base(handle)
    {
         lastCell=this;
    }

    static public OrderPrimary NewCell()
    {
         NSObject obj=new NSObject();
         NSBundle.MainBundle.LoadNib("OrderPrimary",obj,null);

         return lastCell;
    }
}

Not big or clever but works for me. I couldn't work out how to get at it any other way.. comments welcomed!

Note in this example I have just the one view in a XIB.


I haven't tried this for cell views, but I think the best way to get this to work properly is to use inheritance from interface builder when defining your cell.

Basically, you have to define a subclass of UITableCellView in IB (right click the class, and "add subclass"). Use that class to create the cell. When MonoTouch refreshes the .cs.design file in your project, it'll create partial classes for those types, which you'll have to finish the implementation (make sure your implementation inherits from UITableViewCell. After that, it should be just a matter of creating new cells with new CustomTableViewCell().

I wrote a while back about this going thru this with UIViews, but the process should be the same for cells: http://escoz.com/monotouch-tip-inherit-uiviews-all-the-time/. Hope this helps.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜