UILabel 在设备旋转之前不包装在 UITableView 中 (iOS8)

UILabel not wrapping in UITableView until device rotate (iOS8)

我有一个与 MvxStandardTableViewSource 关联的 custom MvxTableViewCell。然后将该 Source 应用于 UITableView。自定义 table 单元格是在没有任何故事板或 NIB 的情况下定义的。它在代码中进行布局并使用 AutoLayout。

this.searchResultsTable = new UITableView();
this.searchResultsTable.AccessibilityIdentifier = "SearchView_SearchResultsTable";
this.searchResultsTable.TranslatesAutoresizingMaskIntoConstraints = false;
this.searchResultsTable.RowHeight = UITableView.AutomaticDimension;
this.searchResultsTable.EstimatedRowHeight = 44.0f;
this.searchResultsTable.RegisterClassForCellReuse(typeof(CustomerItemCell), new NSString("CustomerItemCell"));
this.searchResultsTable.AllowsMultipleSelectionDuringEditing = true;
this.searchResultsTable.TableFooterView = new UIView();

this.searchResultsTableDataSource = new MvxStandardTableViewSource(this.searchResultsTable, new NSString("CustomerItemCell"));
this.searchResultsTable.Source = this.searchResultsTableDataSource;

MVxStandardTableViewSource 数据绑定到 List

类型的 ViewModel 属性
var set = this.CreateBindingSet<SearchView, SearchViewModel>();
set.Bind(this.searchResultsTableDataSource).To(vm => vm.SearchResults);
set.Bind(this.searchBar).For(x => x.Text).To(vm => vm.CurrentSearchCriteria);
set.Apply();

一切正常,直到数据源中的某个项目在其中一个 UILabel 中引起一些文本换行,从而导致其他单元格的高度不同。

单元格高度大部分计算正确,但 UILabel 在 在设备旋转之前,单元格不会被重新绘制。我正在使用 iOS AutoLayout 来布置 Cell 中的各种 UIView。

以下是我布局中大单元格的一些示例,请参阅 person "THISISAPATIENTWITHA-"(注意这是测试数据不是真人数据)

单元格的初始显示

单元格相同但设备已旋转

设备旋转回原始状态时仍然是相同的单元格

如何让 UILabel 重绘?我们只需要支持iOS8及以上

我看不到发生数据绑定时调用的事件或方法,这些事件或方法可以让我有效地告诉自定义单元格 "You now have your subviews populated with bound data so redraw them"

table 还有另一个问题也包含在这个问题中,

Github

上的简单复制

https://github.com/munkii/TableCellResizeIssue

MvvmCross 中的标准 table 视图可以追溯到 iOS4 - 而新的 UITableViewAutomaticDimension 尺寸直到最近才真正添加(iOS8?)

大多数实际应用倾向于使用自定义单元而不是标准单元,但如果您确实想使用标准单元,那么我猜您可以尝试向单元中的设置器添加一些代码,这会触发调整大小重新计算 - 例如在 https://github.com/MvvmCross/MvvmCross/blob/3.5/Cirrious/Cirrious.MvvmCross.Binding.Touch/Views/MvxStandardTableViewCell.cs#L73

我会 猜测 明智地在其中调用以请求重新计算布局会导致父单元格和 table 重绘。

更新:

我已经分叉了您的 GitHub 项目并提交了拉取请求。但这是我对你的项目的更新。

https://github.com/SharpMobileCode/TableCellResizeIssue

首先,您正在使用 FluentLayout 作为约束。这实际上并没有错,但这是告诉其他人的一些好信息。 :)

其次,为了UITableView.AutomaticDimension在TableView Cells上工作,必须定义足够的自动布局约束,以便单元格计算单元格的高度. UITableView.AutomaticDimension 取决于适当的 AutoLayout 约束。

由于您使用 FluentLayout 来抽象 iOS AutoLayout 约束,这并不明显,因为应用程序输出中没有警告 window。尽管 FluentLayout 在技术上是正确的,但是 UITableView.AutomaticDimension 还不足以自动计算每个单元格的高度。

所以我所做的是增加了一些约束。查看拉取请求中的 CustomerItemCell.CreateView()(或我的 github link)。您可以看到我为所有底部标签添加了额外的约束,以便它们向 ContentView 添加底部约束(就像您对 this.bornLabel 所做的那样)。这必须应用于单元格底部的所有标签。这为 AutoLayout 提供了足够的信息来正确计算单元格高度。

第三,这几乎可以工作,但如果你旋转到横向,你会注意到长名称单元格会更大并且有额外的填充。为了解决这个问题,我创建了另一个 class 继承自 UILabel 的名为 AutoLayoutLabel 的方法。我覆盖了 Bounds 属性 以便它在旋转到横向并返回到纵向时将 PreferredMaxLayoutWidth 更改为适当的宽度。然后您将需要使用 AutoLayoutLabel 而不是 UILabel。所有需要包装的标签都需要这个。我不确定如何在代码中将 PreferredMaxLayoutWidth 设置为自动,但这是以编程方式进行的方法(这也适用于 iOS 7)。

public class AutoLayoutLabel : UILabel
    {
        public override CGRect Bounds
        {
            get
            {
                return base.Bounds;
            }
            set
            {
                base.Bounds = value;
                if(this.Lines == 0 && Bounds.Size.Width != PreferredMaxLayoutWidth)
                {
                    PreferredMaxLayoutWidth = Bounds.Size.Width;
                    SetNeedsUpdateConstraints();
                }
            }
        }
    }

嗯,应该可以了!

现在我的这部分问题有了解决方案。在@SharpMobileCode 对 PreferredMaxLayoutWidth 的引用提示下,我决定再试一次。而不是将其设置为自动(这在代码中似乎是不可能的)我将其设置为显式,一旦 AutoLayout 完成它的事情。像这样

/// <summary>
/// Lays out subviews.
/// </summary>
public override void LayoutSubviews()
{
    base.LayoutSubviews();
    this.nameLabel.PreferredMaxLayoutWidth = this.nameLabel.Frame.Size.Width;
}

我不再看到标签未换行(欢呼!)但是我看到了一个看起来像单元格重用的问题。一旦我将所有单元格滚动到屏幕顶部,我就可以将它滚动回来,它已经恢复到与所有其他单元格相同的高度。我可以看到标签仍在换行,但单元格高度错误。