参考地址:https://www.cnblogs.com/devin_zhou/p/9979382.html
参考代码:
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,
}
经过测试我发现LoadStatusProperty并没有触发,所以底部的状态没有呈现出来,我做了如下小改动
public class LoadMoreListView : ListView
{
#region 全局变量
private int totleCount = 0;
private object LastItem;
private readonly StackLayout LoadingContent;
private readonly StackLayout LoadMoreContent;
private readonly StackLayout NoDataContent;
public static readonly BindableProperty LoadMoreCommandProperty = BindableProperty.Create(nameof(LoadMoreCommand), typeof(ICommand), typeof(LoadMoreListView), default(ICommand));
/// <summary>
/// 加载状态改变事件
/// 未触发,未知原因,先放着
/// </summary>
public static readonly BindableProperty LoadStatusProperty = BindableProperty.Create(nameof(LoadStatus), typeof(LoadMoreStatus), typeof(LoadMoreListView), LoadMoreStatus.StatusDefault, propertyChanged: OnLoadStatusChanged);
#endregion
#region 构造函数
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;
// this.Footer = LoadMoreContent;
}
#endregion
#region 加载更多
public ICommand LoadMoreCommand
{
get { return (ICommand)GetValue(LoadMoreCommandProperty); }
set { SetValue(LoadMoreCommandProperty, value); }
}
private void LoadMoreListView_ItemAppearing(object sender, ItemVisibilityEventArgs e)
{
IList items = ItemsSource as IList;
if (items != null && e.Item == items[items.Count - 1])
{
// UserDialogs.Instance.ShowLoading();
if (LoadMoreCommand != null && LoadMoreCommand.CanExecute(null) && LastItem != e.Item)
{
totleCount = items.Count;
this.Footer = LoadingContent;
System.Threading.Tasks.Task.Delay(500).ContinueWith((t) => {
Device.BeginInvokeOnMainThread(() => {
this.Footer = null;
LastItem = e.Item;
LoadMoreCommand.Execute(null);
if(totleCount == items.Count)
this.Footer = NoDataContent;
});
});
}
// UserDialogs.Instance.HideLoading();
if(items.Count < 20)
{
this.Footer = NoDataContent;
}
}
}
#endregion
#region 生成Footer
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,
TextColor = Color.DimGray
});
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;
}
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 LoadMoreStatus LoadStatus
{
get { return (LoadMoreStatus)GetValue(LoadStatusProperty); }
set { SetValue(LoadStatusProperty, value); }
}
#endregion
}
public enum LoadMoreStatus
{
StatusDefault = 0,
StatusLoading = 1,
StatusHasData = 2,
StatusNoData = 3,
}
我之前没有加状态显示部分,直接在LoadMoreListView_ItemAppearing中
UserDialogs.Instance.ShowLoading();
if (LoadMoreCommand != null && LoadMoreCommand.CanExecute(null) && LastItem != e.Item)
{
LastItem = e.Item;
LoadMoreCommand.Execute(null);
}
UserDialogs.Instance.HideLoading();
效果没有添加底部的好,有点卡顿
记录一下,备忘