Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How are NSTableCellViews supposed to be laid out?

I have a fairly basic MainWindow.xib with a source list-style sidebar. I created it by dragging the Source List template into the window, which already contains two NSTableCellViews: HeaderCell and DataCell.

The latter consists of an icon (using NSImageView) and a label (NSTextField). Instead, I want the label and another, smaller label underneath. In IB, this looks as follows:

Source list according to IB

If I focus on just DataCell, it highlights accordingly:

DataCell highlighted

Thing is, actually running the program, it looks nothing like the template:

Second item in live DataCell selected

Notice how the two NSTextFields just get smashed together into one. My understanding was that view-based NSOutlineViews (and view-based NSTableViews, for that matter) are supposed to be designed as a template from within IB. Instead, the dimensions from the template seem to get mostly ignored.

Here's the code that sets the view's values from the data source:

public class TourSourceListDelegate : NSOutlineViewDelegate
{
    public override bool IsGroupItem(NSOutlineView outlineView, MonoMac.Foundation.NSObject item)
    {
        return (item as TourSourceListDataSource.Item).IsHeader;
    }

    public override NSView GetView(NSOutlineView outlineView, NSTableColumn tableColumn, MonoMac.Foundation.NSObject item)
    {
        if (IsGroupItem(outlineView, item))
        {
            return outlineView.MakeView("HeaderCell", this);
        }
        else
        {
            var data = item as TourSourceListDataSource.Item;
            var dataView = outlineView.MakeView("DataCell", this);

            (dataView.Subviews[0] as NSTextField).StringValue = data.Name;
            (dataView.Subviews[1] as NSTextField).StringValue = data.Date_start.ToShortDateString();

            return dataView;
        }
    }
}

I've tried overriding GetRowHeight, but that doesn't seem to resolve the problem (it makes more room, but still doesn't let the views distribute themselves properly), nor does it seem necessary.

I've also tried playing with the various Autosizing, Autoresizes Subviews, etc. toggles in IB, but that doesn't seem to produce intuitive results, and again, it doesn't seem necessary — the view as presented in IB is exactly what I want, just with slightly longer labels in practice.

I haven't tried converting this to AutoLayout yet.

What obvious step am I missing?

Some more info that probably doesn't make a difference: this is a Xamarin.Mac/MonoMac project with Xcode 5.0, MacOSX10.8.sdk, Xamarin Studio 4.0.12, Xamarin.Mac 4.0.12, and Mono 3.2.3 (targeting Mono / .NET 4.0). I've also enabled App Sandboxing.

like image 510
Sören Kuklau Avatar asked Sep 23 '13 15:09

Sören Kuklau


1 Answers

What's important in interface builder is the view hierarchy. What kind of view is that cell? Are those labels really subviews of the cellview or not? The hierarchy should look something like:

example NSOutlineView cell hiearchy

One thing that's fishy that I see is accessing dataView.Subviews[0] and [1]. If you're adding subviews to your cells then should be creating your own NSTableViewCell subclasses, with each view connecting to the subclass' IBOutlet properties. The subclass doesn't need any code in its implementation, just the declaration of its properties in @interface, such as titleField and descriptionField, and an empty @implementation that auto-synthesizes them.

Then makeViewWithIdentifier (or apprently the glue MakeView in Xamarin) when passed the right identifier should create your NSTableViewCell subclass, and at runtime you can verify that using po dataView in the debugger. Then you access the subviews using the properties of your NSTableViewCell subclass' interface instead of assuming which view is in which position with the subview array, using dataView.titleField and dataView.descriptionField.

If your cell view has one text field then you can use NSTableViewCell without subclassing, but do connect up the textField outlet (its connected by default as long as you don't delete & recreate the cell view's label view) so you can access it through the property, again instead of having to dive into the subviews array.

All that said, it's not really clear why you're seeing what you are. It looks like those aren't the subviews you expect, and might even look like the wrong fonts as well as in the wrong positions. Using a custom subclass of NSTableViewCell and verifying its class at runtime is a good way of making sure it's creating the view you expect, but you can also dump the subview within the debugger using po [dataView _subtreeDescription].

like image 148
Pierre Houston Avatar answered Nov 06 '22 06:11

Pierre Houston