xamarin.forms使用stacklayout自定义列表及相关加载状态处理。
2016-11-21 15:15
267 查看
xamarin.forms本身有提供ListView控件,个人觉得不够灵活,而且在和ScrollView嵌套使用时,会存在内外两个滚动条问题,不好处理。
我们可以用ScrollView和StackLayout及TapGestureRecognizer做一个列表功能,可自定义每行item个数及其他的自定义动作,下边做一个单行双item列表,scrollview滚动到底部时,显示加载状态并加载数据:
1、xaml部分
2、xaml.cs
我们可以用ScrollView和StackLayout及TapGestureRecognizer做一个列表功能,可自定义每行item个数及其他的自定义动作,下边做一个单行双item列表,scrollview滚动到底部时,显示加载状态并加载数据:
1、xaml部分
//网络异常时重载按钮 <Button x:Name="btnReload" BorderWidth="0" BackgroundColor="White" HorizontalOptions="Center" IsVisible="false"></Button> //列表主体 <ScrollView x:Name="svList" Orientation="Vertical" VerticalOptions="StartAndExpand"> <Frame OutlineColor="Red" BackgroundColor="White" HasShadow="False"> <StackLayout Orientation="Vertical" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"> //筛选条件下返回数据为空时显示 <StackLayout Orientation="Horizontal"> <Label x:Name="lblNoResult"></Label> </StackLayout> //列表数据 <StackLayout x:Name="searchList" VerticalOptions="FillAndExpand"> </StackLayout> </StackLayout> </Frame> </ScrollView> //加载状态提示 <Label x:Name="lblLoading" Text="全力帮您加载中,稍等" HorizontalOptions="Center" IsVisible="false"></Label> <Label x:Name="lblLoaded" Text="已无更多" HorizontalOptions="Center" IsVisible="false"></Label>
2、xaml.cs
public partial class List : ContentPage { //这边异步锁用来防止数据重复加载,不做描述,有兴趣的请自行查找相关资料 static SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1, 1); public int PageIndex{ get; set; } public int PageSize { get; set; } public List() { InitializeComponent(); //分页初始值 this.PageIndex = 0; this.PageSize = 10; //列表初始化加载 this.Appearing += async (sender, e) => { var initResult = await BindSearchResult(); }; //滚动到底部时加载数据 svList.Scrolled += async (sender, e) => { //1、重载按钮是否为显示状态 //2、列表滚动位置计算:内容高度 - 列表高度 if (!btnReload.IsVisible && svList.ScrollY >= svList.ContentSize.Height - svList.Height) { var result = await BindSearchResult(); } }; //重载按钮事件,请求异常或者网络异常时需要重新加载数据 btnReload.Command = new Command(async () => { await BindSearchResult(); }); private async Task<bool> BindSearchResult() { //加载状态显示 lblLoading.IsVisible = true; //重载按钮隐藏 btnReload.IsVisible = false; //防止短时间内重复加载数据 await semaphoreSlim.WaitAsync(); try { //构建请求参数MultipartFormDataContent可以同时传递不同类型的请求参数:StringContent、 //StreamContent等。 var mpContent = new MultipartFormDataContent(); mpContent.Add(new StringContent(this.PageIndex.ToString(), Encoding.UTF8), "pageIndex"); mpContent.Add(new StringContent(this.PageSize.ToString(), Encoding.UTF8), "pageSize"); //Utils.PostAsync<T>()自己封装的restapi请求方法,这边不介绍,UrlConfig类为各种api请求的Url集合 var postResult = await Utils.PostAsync<SearchResult>(UrlConfig.SearchUrl, mpContent, (message) => { btnReload.Text = message + "点击重新加载"; btnReload.IsVisible = true; lblLoading.IsVisible = false; }); if (postResult != null && postResult.success) { //判断请求结果记录数 if (postResult.data.total > 0) { lblNoResult.IsVisible = false; //左边列表source var search_l = postResult.data.data.Where((d, i) => i % 2 == 0).Select(d => new { //这边为左边列表要绑定的业务数据 }).ToList(); //右边列表source var search_r = postResult.data.data.Where((d, i) => i % 2 != 0).Select(d => new { //这边为右边列表要绑定的业务数据 }).ToList(); //UI构造,这个例子为双item,所以以右边列表个数作为遍历上限 //使用Grid列表item的布局,这边以一张图片和图片名称的Label示例 for (var i = 0; i < search_r.Count(); i++) { var grid = new Grid(); var item_l = new StackLayout(); item_l.Children.Add(new Image() { Source = search_l[i].ImagePath, HeightRequest = 120 }); item_l.Children.Add(new Label() { Text = search_l[i].ImageName, HorizontalOptions = LayoutOptions.Center }); //图片ID编号,由列表进入item详情页时传递过去 item_l.Children.Add(new Label() { Text = search_l[i].ID.ToString(), IsVisible = false }); var item_r = new StackLayout(); item_r.Children.Add(new Image() { Source = search_r[i].ImagePath, HeightRequest = 120 }); item_r.Children.Add(new Label() { Text = search_r[i].ImageName, HorizontalOptions = LayoutOptions.Center }); //图片ID编号,由列表进入item详情页时传递过去 item_r.Children.Add(new Label() { Text = search_r[i].ID.ToString(), IsVisible = false }); grid.Children.Add(item_l, 0, 0); grid.Children.Add(item_r, 1, 0); //左边列表item点击事件 var tap_l = new TapGestureRecognizer(); tap_l.Tapped += (sender, e) => { //点击进入详情页 var id = ((Label)(((StackLayout)sender).Children[2])).Text; var name = ((Label)(((StackLayout)sender).Children[1])).Text; this.Navigation.PushAsync(new Info(int.Parse(id)) { Title = /*自定义详情页标题*/ }); }; item_l.GestureRecognizers.Add(tap_l); //右边列表item点击事件 var tap_r = new TapGestureRecognizer(); tap_r.Tapped += (sender, e) => { //点击进入详情页 var id = ((Label)(((StackLayout)sender).Children[2])).Text; var name = ((Label)(((StackLayout)sender).Children[1])).Text; this.Navigation.PushAsync(new Info(int.Parse(id)) { Title = /*自定义详情页标题*/ }); }; item_r.GestureRecognizers.Add(tap_r); searchList.Children.Add(grid); } //请求个数恰巧为单数时处理,逻辑同上 if (search_l.Count() > search_r.Count()) { var grid = new Grid(); var item = new StackLayout(); item.Children.Add(new Image() { Source = search_l[search_l.Count() - 1].ImagePath, HeightRequest = 120 }); item.Children.Add(new Label() { Text = search_l[search_l.Count() - 1].ImageName, HorizontalOptions = LayoutOptions.Center }); item.Children.Add(new Label() { Text = search_l[search_l.Count() - 1].ID.ToString(), IsVisible = false }); var tap = new TapGestureRecognizer(); tap.Tapped += (sender, e) => { //点击进入详情页 var id = ((Label)(((StackLayout)sender).Children[2])).Text; var name = ((Label)(((StackLayout)sender).Children[1])).Text; this.Navigation.PushAsync(new Info(int.Parse(id)) { Title = /*自定义详情页标题*/ }); }; item.GestureRecognizers.Add(tap); grid.Children.Add(item, 0, 0); searchList.Children.Add(grid); } } else { //请求返回的数据为空处理 lblNoResult.IsVisible = true; lblNoResult.Text = string.Format("抱歉,没有找到{0}的信息", /*某某某*/); } //关闭加载状态显示 lblLoading.IsVisible = false; if (!postResult.data.data.Any()) { lblLoaded.IsVisible = true; await lblLoaded.FadeTo(0, 2000); lblLoaded.Opacity = 1; lblLoaded.IsVisible = false; } //当前分页数累加 this.PageIndex++; return true; } return false; } finally { //释放锁 semaphoreSlim.Release(); } } } }
相关文章推荐
- DrawerLayout的使用 侧滑加载Listview,首页使用Fragment和处理点击触摸冲突、穿透事件和监听菜单滑动状态的改变的详细介绍
- 使用自定义的item、Adapter和AsyncTask、第三方开源框架PullToRefresh联合使用实现自定义的下拉列表(从网络加载图片显示在item中的ImageView)
- Android:使用LoadingLayout来展示加载数据时不同状态
- 使用自定义的item、Adapter和AsyncTask、第三方开源框架PullToRefresh联合使用实现自定义的下拉列表(从网络加载图片显示在item中的ImageView)
- Android第三方框架universal-image-loader[图片缓存加载]及其OOM问题处理【常用】,CardView使用[给列表中项+边框]
- 使用GCD处理非UI相关的异步任务 Object-C异步多线程加载网络图片
- xamarin forms常用的布局StackLayout详解
- android一个BaseAdapter的使用(LayoutInflater加载自定义布局)
- 使用自定义的RelateLayout实现列表布局
- 在使用updatepanel 时,上传到服务器出现如下错误: Sys.WebForms.PageRequestManagerServerErrorException: 在服务器上处理请求时出现未知错误。服务器返回的状态码为: 500
- 关于:“无法序列化会话状态。在“StateServer”或“SQLServer”模式下,ASP.NET 将序列化会话状态对象,因此不允许使用无法序列化的对象或 MarshalByRef 对象。如果自定义会话状态存储在“Custom”模式下执行了类似的序列化,则适用同样的限制。”的问题
- ASP.NET中使用AJAX后,Session丢失异常的自定义处理。
- 如何使用Openssl加载证书撤销列表
- 如何使用Openssl加载证书撤销列表
- 学习笔记--- 使用客户端脚本以自定义错误处理
- HTMLParser使用详解(5)- 扩展 HTMLParser 对自定义标签的处理能力
- 使用特性和反射输出枚举类型各项列表,并可以自定义显示文字
- .NET中一般处理程序(ashx)在Ajax中的使用--下拉列表的动态级连
- .NET中一般处理程序(ashx)在Ajax中的使用--下拉列表的动态级连
- javascript处理图片的一些相关连接,备以后使用