1. 程式人生 > >Xamarin.Forms 中ListView實現到底載入更多

Xamarin.Forms 中ListView實現到底載入更多

Xamarin.Forms 中ListView實現到底載入更多

在移動應用開發中,為了更好的使用者體驗,ListView控制元件的分頁效果通常是利用ListView到底載入來實現。

在Xamarin.Forms中ListView如何實現到底載入呢?

通過利用ListView的ItemAppearing來判斷最後一條資料是否展示出來,如果已經展示那麼說明ListView已經滾動到底部了。

來看看完整程式碼示例:

public class LoadMoreListView : ListView
{
    private readonly StackLayout LoadingContent;
    private readonly StackLayout LoadMoreContent;
    private readonly StackLayout NoDataContent;

    public LoadMoreListView() : base(ListViewCachingStrategy.RecycleElement)
    {
        Xamarin.Forms.PlatformConfiguration.iOSSpecific.ListView.SetSeparatorStyle(this, Xamarin.Forms.PlatformConfiguration.iOSSpecific.SeparatorStyle.FullWidth);
        LoadingContent = CreateFooter("正在載入中...",true);
        LoadMoreContent = CreateFooter("上拉載入更多",false);
        NoDataContent = CreateFooter("已載入全部資料",false);
        ItemAppearing += LoadMoreListView_ItemAppearing;
    }

    private void LoadMoreListView_ItemAppearing(object sender, ItemVisibilityEventArgs e)
    {
        if (ItemsSource is IList items && e.Item == items[items.Count - 1])
        {
            if (CanLoadMore && LoadStatus == LoadMoreStatus.StatusHasData)
            {
                if (CanLoadMore && (LoadMoreCommand?.CanExecute(null) == true))
                    LoadMoreCommand.Execute(null);
            }
        }
    }

    private StackLayout CreateFooterContent(string content,bool indicator = false)
    {
        var item = new StackLayout
        {
            Orientation = StackOrientation.Horizontal,
            HeightRequest = 50,
            VerticalOptions = LayoutOptions.CenterAndExpand,
            HorizontalOptions = LayoutOptions.CenterAndExpand,
        };
        if(indicator)
        {
            try
            {
                item.Children.Add(new ActivityIndicator
                {
                    IsRunning = true,
                    WidthRequest = 20,
                    HeightRequest = 20,
                    VerticalOptions = LayoutOptions.CenterAndExpand
                });
            }
            catch(Exception e)
            {
                Debug.WriteLine(e.Message);
            }
        }

        item.Children.Add(new Label
        {
            Text = content,
            VerticalOptions = LayoutOptions.CenterAndExpand
        });
        return item;
    }

    private StackLayout CreateFooter(string content,bool hasIndicator)
    {
        var item = new StackLayout
        {
            Orientation = StackOrientation.Horizontal,
            HeightRequest = 50,
        };
        var contentStack = CreateFooterContent(content,hasIndicator);
        item.Children.Add(contentStack);
        return item;
    }

    public static readonly BindableProperty LoadMoreCommandProperty = BindableProperty.Create(nameof(LoadMoreCommand), typeof(ICommand), typeof(LoadMoreListView), default(ICommand));

    public ICommand LoadMoreCommand
    {
        get { return (ICommand)GetValue(LoadMoreCommandProperty); }
        set { SetValue(LoadMoreCommandProperty, value); }
    }

    public static readonly BindableProperty CanLoadMoreProperty = BindableProperty.Create(nameof(CanLoadMore), typeof(bool), typeof(LoadMoreListView), false);
    public bool CanLoadMore
    {
        get { return (bool)GetValue(CanLoadMoreProperty); }
        set { SetValue(CanLoadMoreProperty, value); }
    }

    public static readonly BindableProperty LoadStatusProperty = BindableProperty.Create(nameof(LoadStatus), typeof(LoadMoreStatus), typeof(LoadMoreListView), LoadMoreStatus.StatusDefault, propertyChanged: OnLoadStatusChanged);

    public LoadMoreStatus LoadStatus
    {
        get { return (LoadMoreStatus)GetValue(LoadStatusProperty); }
        set { SetValue(LoadStatusProperty, value); }
    }

    private static void OnLoadStatusChanged(BindableObject bindable, object oldValue, object newValue)
    {
        var lv = (LoadMoreListView)bindable;
        lv.NotifyLoadStatus((LoadMoreStatus)newValue);
    }

    public void NotifyLoadStatus(LoadMoreStatus loadStatus)
    {
        switch (loadStatus)
        {
            case LoadMoreStatus.StatusDefault:
                this.Footer = null;
                break;
            case LoadMoreStatus.StatusLoading:
                this.Footer = LoadingContent;
                break;
            case LoadMoreStatus.StatusHasData:
                this.Footer = LoadMoreContent;
                break;
            case LoadMoreStatus.StatusNoData:
                this.Footer = NoDataContent;
                break;
            default:
                this.Footer = null;
                break;
        }
    }

}

public enum LoadMoreStatus
{
    StatusDefault = 0,
    StatusLoading = 1,
    StatusHasData = 2,
    StatusNoData = 3,
}

以上程式碼簡單實現了一個到底載入功能,