这个问题已在here和其他地方得到解决,但没有一个建议的解决方案对我有用。大多数答案是为布局事件附加侦听器和执行测量的变体,直到返回的值有意义,然后删除附加的侦听器。问题是如果没有滚动状态变化,孩子在测量时总是返回零维度。
这是我最接近解决方案的方法:
public class CustomListViewRenderer : ListViewRenderer, IOnScrollListener, IOnLayoutChangeListener
{
public CustomListViewRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.ListView> e)
{
base.OnElementChanged(e);
Control.SetOnScrollListener(this);
Control.AddOnLayoutChangeListener(this);
Task.Run(() =>
{
Device.BeginInvokeOnMainThread(() =>
{
// Scrolls the ListView to an arbitrary position different than the top.
// Otherwise MeasuredHeight returns zero.
Control.SetSelectionFromTop(1, 0);
});
});
}
public void OnScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount)
{
}
public void OnScrollStateChanged(AbsListView view, ScrollState scrollState)
{
Debug.WriteLine("OnScrollStateChanged");
Debug.WriteLine(Control.GetChildAt(0)?.MeasuredHeight);
}
public void OnLayoutChange(global::Android.Views.View view, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom)
{
Debug.WriteLine("OnLayoutChange");
Debug.WriteLine(Control.GetChildAt(0)?.MeasuredHeight);
}
}
我的猜测是,有一些内部优化会导致MeasuredHeight返回零,即使子视图已经布局,除非滚动状态发生变化。这就是为什么OnElementChanged
安排Control.SetSelectionFromTop(1, 0);
在绘制ListView之后更改滚动位置的原因(大概)。
修改
当ListView处于其初始滚动位置时,或者之后滚动到该位置时,打印出子视图的类显示它们属于类ListViewRenderer_Container
。其余的子视图属于类ConditionalFocusLayout
。