ListViewRenderer ItemTap issue

Hi!

I try to implement custom ListViewControl for my Xamarin.Forms app. I try to use this code:

protected override void OnElementChanged(ElementChangedEventArgs<ListView> e)
{
    base.OnElementChanged(e);
    SetNativeControl(new CustomListView(Context));
}

But in this case all properties that assigned to the list view is disappearing. So, I try to call SetNativeControl method before base.OnElementChanged():

protected override void OnElementChanged(ElementChangedEventArgs<ListView> e)
{
    SetNativeControl(new CustomListView(Context));
    base.OnElementChanged(e);
}

In that case everything works like a charm, except one thing. I've got ItemTapped event. But when I tap on the second Item, my handler get first item. When I tap first item nothing happend at all. I expect, that problem was in my custom ListView, but when I try to use android ListView instead of my CustomListView I got just the same result. Are there any workarounds for this issue?

Answers

  • LandLuLandLu Member, Xamarin Team Xamurai

    If you want to replace the whole ListView with a native Android ListView you should place the initialized code beneath the base.OnElementChanged(e); like:

    protected override void OnElementChanged(ElementChangedEventArgs<ListView> e)
    {
        base.OnElementChanged(e);
    
        if (Control != null)
        {
            var listView = new Android.Widget.ListView(Android.App.Application.Context);
            listView.Adapter = new CustomAdapter(Context, Resource.Layout.layout);
            // More configurations
    
            SetNativeControl(listView);
        }
    }
    

    Add the item click event there as you have created a new control. The events of the original control have been overlapped.

    SetNativeControl(new CustomListView(Context));
    base.OnElementChanged(e);
    

    This code makes no sense because base.OnElementChanged(e); will call the parent's event to render the original settings you have set in the Forms.
    However, if you only want to change some properties of the original control you can manipulate the Control property of the renderer directly.
    Refer to the custom renderer for more details: https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/custom-renderer/listview
    Moreover, if you want to know how to create a native Android ListView this tutorial is helpful: https://docs.microsoft.com/en-us/xamarin/android/user-interface/layouts/list-view/

  • AntonChekalinAntonChekalin USMember ✭✭

    LandLu, thank you for your answer!

    This code makes no sense because base.OnElementChanged(e); will call the parent's event to render the original settings you have set in the Forms.

    I think it's not so. Let's have a look on Android ListViewRenderer. I take it from https://github.com/xamarin/Xamarin.Forms/blob/master/Xamarin.Forms.Platform.Android/Renderers/ListViewRenderer.cs

    if (e.NewElement != null)
            {
                AListView nativeListView = Control;
                if (nativeListView == null)
                {
                    var ctx = Context;
                    nativeListView = CreateNativeControl();
                    _refresh = CreateNativePullToRefresh(ctx);
                    _refresh.SetOnRefreshListener(this);
                    _refresh.AddView(nativeListView, new LayoutParams(LayoutParams.MatchParent, LayoutParams.MatchParent));
                    SetNativeControl(nativeListView, _refresh);
    
                    _headerView = new Container(ctx);
                    nativeListView.AddHeaderView(_headerView, null, false);
                    _footerView = new Container(ctx);
                    nativeListView.AddFooterView(_footerView, null, false);
                }
    

    In this code we can see, that instance created only if Control property is null. So I expect to have my CustomListView with assigned properties I have set in Forms. And also, if it make no changes to default behaviour it should not produced an issue with taps. I try to remove SetNativeControl and it works as expected

    My custom ListView realise swipe to delete feature. I take it from here: forums.xamarin.com/discussion/120612/swipe-to-delete-listview
    In android app it works like a charm. If i called SetNativeControl(new CustomListView(Context)) before base.OnElementChanged(e) it also works nice, but have tap issue that I described. If I called it after and assign OnItemClickListener manualy from Control property sometimes my taps missed and I notice that some methods called more times, that they should. That's why I don't want to call it after base method.

  • LandLuLandLu Member, Xamarin Team Xamurai

    https://github.com/xamarin/Xamarin.Forms/blob/master/Xamarin.Forms.Platform.Android/Renderers/ListViewRenderer.cs
    This is the source code for list view renderer which helps us create the Android.Widget.ListView. When it comes to OnElementChanged the control is definitely null and needs to be initialized.
    And we consumed the list view renderer to customize our list view. The control has been initialized as our renderer is inherited from the list view renderer.
    If you want to use your own list view you also need to call the parent OnElementChanged to finish the configurations. Then customize yours.

Sign In or Register to comment.