Center selected item on scroll in listview

ivsaltiivsalti ✭✭Member ✭✭

I want the selected item to be constantly in the center of the list, even when scrolling.

I can determine in which direction the scrolling is going by tracking the current index in the ItemAppearing event and trying to set the SelectedItem to the previous item at 3 positions, but this is very inaccurate and varies depending on the screen resolution. Also, if I add ScrollTo to center the current item, it just scrolls constantly until it reaches the last item.
It is like a Picker Control, but I can't use picker because it opens a dialog window for the list, but I need to display this list on the page

This is my ListView in xaml

<ListView 
    x:Name="HoursList"
    ItemsSource="{Binding Hours}"
    ItemAppearing="ListView_ItemAppearing_Hour">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                <StackLayout>
                    <Label Text="{Binding .}"></Label>
                </StackLayout>
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

And here is ItemAppearing handler
private void ListView_ItemAppearing_Hour(object sender, ItemVisibilityEventArgs e)
{
HoursItemsList = new List(ViewModel.Hours);
var currentIdx = HoursItemsList.IndexOf((int)e.Item);

    if (currentIdx > CurrentHourIndex)
    {
        // Direction = "Up"
        currentIdx -= IndexModificator;
    }
    else
    {
        // Direction = "Down"
        currentIdx += IndexModificator;
    }

    ((ListView)sender).SelectedItem = currentIdx;
    //((ListView)sender).ScrollTo(e.Item, ScrollToPosition.Center, true);
    CurrentHourIndex = currentIdx;
}
Tagged:

Answers

  • ColeXColeX Xamurai Member, Xamarin Team Xamurai
    edited August 26

    ItemAppearing method works for all the items not a single item , so the Scrolling is inaccurate .

    You could refer to the native android solution (like this one) and use custom renderer to implement it .

  • ivsaltiivsalti ✭✭ Member ✭✭

    Thank you! This is exactly what i need.

    I was able to implement a scroll, but it turns out that now I need to redo the way the selected item is set on scroll. I can’t find how to determine the current item in the middle of the list to make it selected.

    Right now my custom renderer looks like this
    class AndroidWheelListViewRenderer : ListViewRenderer, IOnScrollListener, IOnLayoutChangeListener
    {
    Context _context;

        private Android.Views.View SelectedFromList { get; set; }
        public int CurrentPosition { get; private set; }
    
        public AndroidWheelListViewRenderer(Context context) : base(context)
        {
            _context = context;
        }
    
        protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.ListView> e)
        {
            base.OnElementChanged(e);
    
            Control.SetOnScrollListener(this);
            Control.AddOnLayoutChangeListener(this);
    
            Control.ItemSelected += (object sender, AdapterView.ItemSelectedEventArgs ev) =>
            {
                SelectedFromList = Control.GetChildAt(ev.Position);
                CurrentPosition = ev.Position;
            };
        }
    
        public void OnScrollStateChanged(AbsListView view, ScrollState scrollState)
        {
            System.Diagnostics.Debug.WriteLine("OnScrollStateChanged");
    
            SelectCenteredItem();
    
            try
            {
                Control.SmoothScrollBy(SelectedFromList.Top - (Control.Height / 2) + (SelectedFromList.Height / 2), 1500);
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine("No item selected");
            }
        }
    
        private void SelectCenteredItem()
        {
            throw new NotImplementedException();
        }
    }
    

    }`

Sign In or Register to comment.