如何为具有与内置单元格相同的布局指标的“UITableView”提供自定义“UITableCell”?

Posted

技术标签:

【中文标题】如何为具有与内置单元格相同的布局指标的“UITableView”提供自定义“UITableCell”?【英文标题】:How can I supply a custom `UITableCell` to an `UITableView` with the same layout metrics that a built-in cell would have? 【发布时间】:2018-05-30 10:40:43 【问题描述】:

当我向原型表格单元格添加子视图时,假设是UITextView,则默认情况下没有左边距。 我希望它使用与 ios 内部用于内置标准单元格布局的相同边距。 万一我错过了明显的,“使用设备/iOS默认值”标志在哪里?否则,我首选的解决方案是查询设备的设备相关和 iOS 版本相关的 UI 指标。对于这个问题,我们可以将其限制为仅UITableView 控件及其UITableCell 后代的指标。

这就是我生成自定义单元格的方式:

    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;
            
        
    

这就是它与包含表视图的链接方式:

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;

我已经在 SO 和互联网上搜索了与 systemmetrics 等效的东西,有很多颜色和字体,但我只找到了关于尺寸、边距、插图、角半径等的少量信息:

This question 处理相反的情况,去掉任何边距,并且没有提及如何复制 iOS 默认值。 This page from apple dev 提到了整个 separatorInset 的属性 TableView,这似乎适用于左缩进,但我对将布局的一部分应用到另一部分的指标有些怀疑。

硬编码幻数不是一种选择。我们在 iPhone 和 iPad 上进行了测试,发现即使在相同的设备上,只有 iOS 版本不同,插图的默认值也会有所不同。 我也会对 Objective-C 和 Swift 提示和解决方案感到满意,只要它们在正确翻译后在 xamarin 中工作。

【问题讨论】:

【参考方案1】:

如果您想根据不同的设备或不同的版本使用默认边距,为什么不尝试自动布局? NSLayoutAttribute.LeadingMargin 表示元素边距的默认前沿。在您的UITextSingleline 中将LayoutSubviews() 从硬代码修改为自动布局:

假设单元格只有一个标签来显示一些文本:

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 );

这样,headingLabel 将具有与“标准内置单元格的 TextLabel”相同的布局。

此外,在您的情况下,您似乎也想在您的单元格中添加UITextView。我建议您在构造函数时添加约束,我提供我的约束供您参考:

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 );

使用 AutoLayout 的另一个好处是:在将 TableView 的 RowHeight 设置为 UITableView.AutomaticDimension 和 EstimatedHeight 后,如果我们设置了正确的约束,单元格将根据其内容自动计算行高。

【讨论】:

感谢您为整理这些内容所做的努力。我们按照建议做了,它就像一个魅力。 很高兴它帮助了你。

以上是关于如何为具有与内置单元格相同的布局指标的“UITableView”提供自定义“UITableCell”?的主要内容,如果未能解决你的问题,请参考以下文章

我们如何为多个 UITab 使用相同的 WKWebView

如何为具有动态高度的表格单元格添加底部阴影?

如何为集合视图单元格内的视图添加手势?

如何为具有 uilocalnotification 的单元格提供单独的颜色

如何为 UICollectionViewFlowLayout 中的每个单元格添加标题/标签补充视图?

如何为集合视图单元格使用图像选择器