0

This question has been addressed here and in other places, but none of the suggested solutions has worked for me. Most answers are variations of attaching a listener for layout events and performing measurements until the returned value makes sense, then remove the attached listener. The problem is that if there are no scroll state changes, the children always return zero dimension when measured.

This is the closest I've got to a solution:

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

My guess is that there are some internal optimizations that cause MeasuredHeight to return zero even when the child views have already been laid out, unless there is a change in the scroll state. That's why OnElementChanged schedules Control.SetSelectionFromTop(1, 0); to change the scroll position after the ListView have been drawn (presumably).

Edit

Printing out the class of the child views shows they are of class ListViewRenderer_Container when the ListView is in its initial scroll position, or if it's scrolled to that position afterwards. The rest of the time child views are of the class ConditionalFocusLayout.

rraallvv
  • 2,875
  • 6
  • 30
  • 67

0 Answers0