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

Xamarin.ios UILabel在设备旋转之前不在UITableView中包装(iOS8),xamarin.ios,mvvmcross,Xamarin.ios,Mvvmcross,我有一个与MvxStandardTableViewSource关联的自定义MvxTableViewCell。然后将该源应用于UITableView。自定义表格单元的定义没有任何故事板或NIB。它在代码中布局并使用自动布局 this.searchResultsTable = new UITableView(); this.searchResultsTable.AccessibilityIdentifier = "SearchView_SearchResultsTable"; this.search

我有一个与MvxStandardTableViewSource关联的自定义MvxTableViewCell。然后将该源应用于UITableView。自定义表格单元的定义没有任何故事板或NIB。它在代码中布局并使用自动布局

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();
var set=this.CreateBindingSet();
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在单元格中布局各种UIView

下面是我的布局中的一些大型单元格示例,请参见 人员“ThisispatientWitha-”(注意这是测试数据,不是真实的人员数据)

单元格的初始显示

相同的单元格,但设备已旋转

设备旋转回原始位置后,仍保留相同的单元格

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

我看不到在数据绑定发生时调用的事件或方法,该事件或方法允许我有效地告诉自定义单元格“您现在已经用绑定数据填充了子视图,因此需要重新绘制它们”

这个表格还有一个问题,这个问题涉及到了这个问题

在Github上进行简单复制


MvvmCross中的标准表视图可以追溯到iOS4,而新的
UITableViewAutomaticDimension
大小调整直到最近才真正添加(iOS8?)

大多数真正的应用程序倾向于使用自定义单元格,而不是标准单元格,但如果您确实想使用标准单元格,那么我想您可以尝试向单元格中的设置器添加一些代码,这将触发重新调整大小的计算,例如,向单元格中的设置器添加代码


我猜,在那里明智地放置调用以请求布局recalc将导致父单元格和表重新绘制。

更新:

我已经完成了你的GitHub项目并提交了一个请求。但这是我对你的项目的更新

首先,您使用FluentLayout作为约束。事实上,这没什么错,但这是一些可以告诉别人的好信息

Second,为了让
UITableView.AutomaticDimension
在TableView单元格上工作,必须定义足够的自动布局约束,以便单元格计算单元格的高度<代码>UITableView。自动尺寸取决于正确的自动布局约束

因为您使用FluentLayout抽象iOS自动布局约束,所以这并不明显,因为应用程序输出窗口中没有警告。虽然FluentLayout在技术上是正确的,但它不足以让
UITableView.AutomaticDimension
自动计算每个单元格的高度

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

第三个,这几乎可以实现,但是如果旋转到横向,您会注意到长名称单元格会更大,并且有额外的填充。为了解决这个问题,我创建了另一个名为AutoLayoutLabel的类,该类继承自UILabel。我重写了
Bounds
属性,以便在旋转到横向并返回到纵向时将
PreferredMaxLayoutWidth
更改为正确的宽度。然后需要使用AutoLayoutLabel而不是UILabel。对于所有需要包装的标签,都需要使用此选项。我不确定如何在代码中将
PreferredMaxLayoutWidth
设置为自动,但这是如何通过编程实现的(这也适用于iOS 7)


好吧,那就行了

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

/// <summary>
/// Lays out subviews.
/// </summary>
public override void LayoutSubviews()
{
    base.LayoutSubviews();
    this.nameLabel.PreferredMaxLayoutWidth = this.nameLabel.Frame.Size.Width;
}
//
///布局子视图。
/// 
公共覆盖无效布局子视图()
{
base.LayoutSubviews();
this.namelab.PreferredMaxLayoutWidth=this.namelab.Frame.Size.Width;
}

我不再看到标签没有包装(万岁!)但是我看到了一个看起来像细胞重用的问题。一旦我从屏幕顶部滚动所有单元格,我就可以将其重新滚动,并且它已恢复到与所有其他单元格相同的高度。我可以看到标签仍在包装,但单元格高度错误。

问题是我没有使用标准单元格,我使用的是带有自动布局和数据绑定的自定义单元格。没有明显的地方可以插入布局recalc调用。我是否错过了“BindingValueUpdated”事件:-)对不起-我不明白。也许可以尝试编辑问题以添加更多细节,或者尝试问一个新问题-有时(经常)很难理解评论对话。更新了更多细节。当数据绑定到UILabelsNow添加的屏幕截图时,我基本上看不到如何插入重画调用!答案将取决于您是只支持iOS 8,还是需要支持iOS 8和iOS 7(o)
/// <summary>
/// Lays out subviews.
/// </summary>
public override void LayoutSubviews()
{
    base.LayoutSubviews();
    this.nameLabel.PreferredMaxLayoutWidth = this.nameLabel.Frame.Size.Width;
}