0

When I add a subview to a prototype table cell, let's say an UITextView, then there is no left margin by default. I would like it to use the same margin that iOS uses internally for built-in standard cell layouts. In case I'm missing the obvious, where is the "use device/iOS defaults" flag? Otherwise, my preferred solution would be a way to query the device for its device-dependent and iOS version dependent UI metrics. For the purpose of this question, we can limit this to only the metrics of the UITableView control and its UITableCell descendants.

This is how I generate my custom cell:

    internal class UITextSingleline : UITableViewCell
    {
        UILabel headingLabel;
        UITextView textBox;
        int MultiHeight;
        public bool secure; 

        public UITextSingleline() : this(null, 1) { }
        public UITextSingleline(int multiheight) : this(null, multiheight) { }
        public UITextSingleline(NSString cellId, int multiheight) : base(UITableViewCellStyle.Default, cellId) 
        {
            MultiHeight = multiheight;
            SelectionStyle = UITableViewCellSelectionStyle.None;            
            headingLabel = new UILabel()
            {
                Font = UIFont.SystemFontOfSize(16),
                TextColor = UIColor.DarkTextColor,
                BackgroundColor = UIColor.Clear
            };

            textBox = new UITextView()
            {                
                ClipsToBounds = true,
                Font = UIFont.SystemFontOfSize(16),
                TextColor = UIColor.DarkTextColor
            };

            if (multiheight == 1) textBox.TextContainer.MaximumNumberOfLines = 1;
            textBox.Layer.CornerRadius = 10.0f;
            textBox.Layer.BorderColor = UIColor.DarkTextColor.CGColor;
            textBox.Layer.BorderWidth = 1f;
            ContentView.AddSubviews(new UIView[] { headingLabel, textBox });               
        }

        public override void LayoutSubviews()
        {
            base.LayoutSubviews();
            headingLabel.Frame = new CGRect(16, 8, ContentView.Bounds.Width - 32, 20);
            textBox.Frame = new CGRect(16, 32, ContentView.Bounds.Width - 32, 36 * MultiHeight); /* see? magic numbers all over the place */
        }

        public void UpdateCell(string caption, string text)
        {            
            headingLabel.Text = caption;
            textBox.Text = text;                   
        }

        public string Text
        {
            get
            {
                return textBox?.Text;
            }
            set
            {
                if (textBox != null) textBox.Text = value;
            }
        }
    }

And this is how it is linked to the containing table view:

public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
    switch (indexPath.Section)
    {
        case 0:
            /* area/workplace */
            switch (indexPath.Row)
            {
                case 0:
                    /* area picker (omitted) */
                case 1:
                    /* workplace text input (single-line) */
                    if (txtWorkplace == null)
                    {
                        txtWorkplace = new UITextSingleline();
                        txtWorkplace.UpdateCell("Workplace", Data.Instance.Payload.report.workplace);
                    }
                    return txtWorkplace;
            }
            break;
        case 1:
            /* rest ommitted for brevity */
            break;
    }
    return null;
}

I have searched SO and the internet for an equivalent to systemmetrics, there is lots for colors and fonts but I found only little information about dimensions, margins, insets, corner radii, and the like:

  • This question deals with the opposite, getting rid of any margin, and does not mention how to replicate the iOS defaults.
  • This page from apple dev mentions the separatorInset property of the whole TableView, which seems to work for the left indentation, but I'm somewhat sceptical about applying a metric for one part of the layout to another part.

Hardcoded magic numbers are not an option. We tested on iPhone and iPad and noticed varying inset defaults even on the same device with only the iOS version different. I'd be happy with objective-C and Swift hints and solutions too, as long as they work in xamarin once properly translated.

Cee McSharpface
  • 8,493
  • 3
  • 36
  • 77

1 Answers1

1

If you want to use default margin depending on different devices or different versions, Why not try autolayout? NSLayoutAttribute.LeadingMargin means the default leading edge of the element's margin. In your UITextSingleline modify the LayoutSubviews() from hard code to autolayout:

Let's assume the cell only has one label to show some text:

public override void LayoutSubviews()
{
    base.LayoutSubviews();

    var leadingConstraint = NSLayoutConstraint.Create(headingLabel, NSLayoutAttribute.Leading, NSLayoutRelation.Equal, ContentView, NSLayoutAttribute.LeadingMargin, 1.0f, 0);
    var topConstraint = NSLayoutConstraint.Create(headingLabel, NSLayoutAttribute.Top, NSLayoutRelation.Equal, ContentView, NSLayoutAttribute.TopMargin, 1.0f, 0);
    var trailingConstraint = NSLayoutConstraint.Create(headingLabel, NSLayoutAttribute.Trailing, NSLayoutRelation.Equal, ContentView, NSLayoutAttribute.TrailingMargin, 1.0f, 0);
    var bottomConstraint = NSLayoutConstraint.Create(headingLabel, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, ContentView, NSLayoutAttribute.BottomMargin, 1.0f, 0);

    ContentView.AddConstraints(new NSLayoutConstraint[] { leadingConstraint, topConstraint, trailingConstraint, bottomConstraint });
}

In this way, the headingLabel will have the same layout as the "standard built-in cell's TextLabel".

Moreover in your case, it seems you want to add a UITextView in your cell too. I recommend you to add constraints at constructor time, I provide my constrains for you referring to:

public MyTableViewCell (IntPtr handle) : base (handle)
{
    headingLabel = new UILabel()
    {
        Font = UIFont.SystemFontOfSize(17),
        TextColor = UIColor.DarkTextColor,
        BackgroundColor = UIColor.Clear,
        Lines = 0
    };

    textBox = new UITextView()
    {
        ClipsToBounds = true,
        Font = UIFont.SystemFontOfSize(16),
        TextColor = UIColor.DarkTextColor
    };

    ContentView.AddSubview(headingLabel);
    ContentView.AddSubview(textBox);

    // Disable this to enable autolayout
    headingLabel.TranslatesAutoresizingMaskIntoConstraints = false;
    textBox.TranslatesAutoresizingMaskIntoConstraints = false;

    doLayouts();
}

void doLayouts()
{

    var leadingConstraint = NSLayoutConstraint.Create(headingLabel, NSLayoutAttribute.Leading, NSLayoutRelation.Equal, ContentView, NSLayoutAttribute.LeadingMargin, 1.0f, 0);
    var topConstraint = NSLayoutConstraint.Create(headingLabel, NSLayoutAttribute.Top, NSLayoutRelation.Equal, ContentView, NSLayoutAttribute.TopMargin, 1.0f, 0);
    var trailingConstraint = NSLayoutConstraint.Create(headingLabel, NSLayoutAttribute.Trailing, NSLayoutRelation.Equal, ContentView, NSLayoutAttribute.TrailingMargin, 1.0f, 0);

    ContentView.AddConstraints(new NSLayoutConstraint[] { leadingConstraint, topConstraint, trailingConstraint });

    var boxLeading = NSLayoutConstraint.Create(textBox, NSLayoutAttribute.Leading, NSLayoutRelation.Equal, ContentView, NSLayoutAttribute.LeadingMargin, 1.0f, 0);
    var boxTop = NSLayoutConstraint.Create(textBox, NSLayoutAttribute.Top, NSLayoutRelation.Equal, headingLabel, NSLayoutAttribute.Bottom, 1.0f, 4);
    var boxTrailing = NSLayoutConstraint.Create(textBox, NSLayoutAttribute.Trailing, NSLayoutRelation.Equal, ContentView, NSLayoutAttribute.TrailingMargin, 1.0f, 0);
    var boxBottom = NSLayoutConstraint.Create(textBox, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, ContentView, NSLayoutAttribute.BottomMargin, 1.0f, 0);
    var boxHeight = NSLayoutConstraint.Create(textBox, NSLayoutAttribute.Height, NSLayoutRelation.Equal, null, NSLayoutAttribute.NoAttribute, 1.0f, 36 * MultiHeight);

    ContentView.AddConstraints(new NSLayoutConstraint[] { boxLeading, boxTop, boxTrailing, boxBottom, boxHeight });
}

Another benefit to use AutoLayout is: after setting the TableView's RowHeight to UITableView.AutomaticDimension and a EstimatedHeight, the cell will auto calculate the row height depending on its content if we set the correct constraints.

Ax1le
  • 6,563
  • 2
  • 14
  • 61