我有一个与MvxStandardTableViewSource关联的自定义 MvxTableViewCell。然后将该Source应用于UITableView。定义的自定义表格单元格没有任何Storyboard或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。
以下是我布局中大单元格的一些示例,请参阅 人“THISISAPATIENTWITHA-”(注意这是测试数据不是真人的数据)
细胞的初始显示
相同的单元格,但设备已旋转
仍然将设备旋转回原始
的相同单元格如何让UILabel重绘?我们只需要支持iOS8及以上版本。
我无法看到在数据绑定发生时调用的事件或方法,这将允许我有效地告诉自定义单元格“您现在已经使用绑定数据填充了子视图,因此重绘它们”
该表还有另一个问题,Implementing cell reuse for varying height cells in UITableView
Github上的简单Repro
答案 0 :(得分:2)
<强>更新强>
我已经分叉了你的GitHub项目并提交了拉取请求。但这是我对你的项目的更新。
https://github.com/SharpMobileCode/TableCellResizeIssue
首先,您正在使用FluentLayout作为约束。实际上没有什么错,但这是告诉别人的一些好消息。 :)
第二,为了使UITableView.AutomaticDimension
能够在TableView Cells上运行,必须定义足够的自动布局约束,以便单元格计算单元格的高度。 UITableView.AutomaticDimension
取决于正确的AutoLayout约束。
由于您使用FluentLayout来抽象iOS AutoLayout约束,因此在应用程序输出窗口中不存在警告时这并不明显。尽管FluentLayout技术上是正确的,但UITableView.AutomaticDimension
自动计算每个单元格高度还不够。
所以我所做的是增加了一些限制。在pull请求(或我的github链接)中查看CustomerItemCell.CreateView()
。您可以看到我为所有底部标签添加了其他约束,以便它们向ContentView添加底部约束(就像您使用this.bornLabel
一样)。这必须应用于单元格底部的所有标签。这为AutoLayout提供了足够的信息来正确计算单元格高度。
第三次,这几乎可以正常工作,但是如果你旋转到横向,你会注意到长名称单元格会更大并且有额外的填充。为了解决这个问题,我创建了另一个名为AutoLayoutLabel的类,它继承自UILabel。我覆盖了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();
}
}
}
}
嗯,应该这样做!
答案 1 :(得分:1)
我现在有一个问题的解决方案。 @SharpMobileCode对PreferredMaxLayoutWidth的引用提示我决定让另一个去。相反,将它设置为自动(这在代码中似乎是不可能的)我将它设置为Explicitly,一旦AutoLayout完成它的事情。喜欢这个
/// <summary>
/// Lays out subviews.
/// </summary>
public override void LayoutSubviews()
{
base.LayoutSubviews();
this.nameLabel.PreferredMaxLayoutWidth = this.nameLabel.Frame.Size.Width;
}
我不再看到标签没有包裹(欢呼!)但是我看到了看起来像细胞重用的问题。一旦我从屏幕顶部滚动所有单元格,我可以将其重新滚动并恢复到与所有其他单元格相同的高度。我可以看到标签仍然是包装但是单元格高度错误。
答案 2 :(得分:0)
MvvmCross中的标准表视图可以追溯到iOS4 - 而新的UITableViewAutomaticDimension
大小调整直到最近才添加(iOS8?)
大多数真正的应用程序倾向于使用自定义单元格而不是标准单元格,但如果您确实想要使用标准单元格,那么我猜您可以尝试向单元格中的setter添加一些代码,这会触发调整大小重新计算 - 例如在https://github.com/MvvmCross/MvvmCross/blob/3.5/Cirrious/Cirrious.MvvmCross.Binding.Touch/Views/MvxStandardTableViewCell.cs#L73
中设置我会猜测明智地在那里放置调用以请求布局重新计算将导致父单元格和表格重绘。