Quantcast
Channel: CSDN博客移动开发推荐文章
Viewing all articles
Browse latest Browse all 5930

Xamarin android 使用RecyclerView下拉刷新滑到底部加载更多

$
0
0

接触RecycleView有一段时间了,前段时间写了一篇关于ListView万能适配器的文章,有人就评论道“现在谁还用ListView”,挺尴尬的……,一般的需求实现功能就ok了,和用什么控件关系不大,不过说还是有一点道理的,从功能和用户体验上来看RecyclerView就好像是加强版的ListView,能实现ListView所有的功能,所以今天就来写一个在Xamarin android中RecyclerView的使用小白教程,大神勿扰。

RecyclerView小白教程关键的实现步骤如下:

  1. RecyclerView的简单实现
  2. RecyclerView添加分割线
  3. RecyclerView实现单击水波纹效果
  4. RecyclerView添加单击事件
  5. SwipeRefreshLayout结合RecyclerView实现下拉刷新滑到底部加载更多

1. RecyclerView的简单实现

RecyclerView是V7兼容包的一个控件,它的优点在于使用灵活,插拔式的体验,多种显示方式。可以说是ListView和GridView的升级版。

官方API介绍
A flexible view for providing a limited window into a large data set
一种灵活的视图,可以为大数据集提供有限的窗口

官网API链接:https://developer.android.com/reference/android/support/v7/widget/RecyclerView.html

我们先来看一下Activity中的代码RecycleViewSimple.cs,我们要做的是设置布局管理,设置数据适配器。

    [Activity(Label = "RecyclerViewSimple",MainLauncher =true,Theme = "@style/BaseAppTheme")]
    public class RecyclerViewSimple : AppCompatActivity
    {
        private Toolbar toolbar;
        private RecyclerView recyclerView;
        private RecyclerViewAdapter adapter;
        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);
            SetContentView(Resource.Layout.RecycleView);
            List<string> data = new List<string>() { "科比", "加内特", "麦迪", "费舍尔", "杰梅因奥尼尔", "大Z", "纳什", "雷阿伦", "马布里", "艾弗森", "安东尼沃克" };
            recyclerView = FindViewById<RecyclerView>(Resource.Id.recyclerView);
            adapter = new RecyclerViewAdapter(data,this);
            recyclerView.SetLayoutManager(new LinearLayoutManager(this));
            recyclerView.SetAdapter(adapter);
        }
    }

然后我们来实现一个RecyclerView的适配器RecyclerViewAdapter.cs

  public class RecyclerViewAdapter : RecyclerView.Adapter
    {
        private List<string> data;
        private Context _context;
        public RecyclerViewAdapter(List<string> list,Context context)
        {
            data = list;
            _context = context;
        }
        public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
        {
            MyViewHolder myViewHolder = holder as MyViewHolder;
            myViewHolder.tvTitle.Text = data[position];
        }
        public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent,int viewItem)
        {
            View view = LayoutInflater.From(_context).Inflate(Resource.Layout.item_recyclerView,parent,false);
            MyViewHolder holder = new MyViewHolder(view);
            return holder;
        }
        public override int ItemCount
        {
            get
            {
                return data.Count;
            }
        }
        public override void OnViewRecycled(Java.Lang.Object holder)
        {
            base.OnViewRecycled(holder);
            MyViewHolder myViewHolder = holder as MyViewHolder;
        }
    }
        public class MyViewHolder : RecyclerView.ViewHolder
    {
        public TextView tvTitle;
        public MyViewHolder(View itemView):base(itemView)
        {
            tvTitle = itemView.FindViewById<TextView>(Resource.Id.tv_num);
        }
    }

最后我们来看一下布局的代码主布局RecycleView.axml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
     android:orientation="vertical">
    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:divider="@color/red"
        android:dividerHeight="5dp" />
</LinearLayout>

RecyclerView的子布局item_recyclerView.axml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/ripple_recyclerview">
  <TextView
      android:id="@+id/tv_num"
      android:layout_width="match_parent"
      android:layout_height="60dp"
      android:textColor="#000000"
      android:gravity="center"
      android:text="1"/>
</LinearLayout>

最终的实现效果图:
这里写图片描述

2. RecyclerView添加分割线

我们发现RecyclerView的divider和divider是不起作用的,默认这两个属性是无效的,所以我们只能RecyclerView提供ItemDecoration类添加分割线,可以看看这篇深入理解ItemDecoration:http://www.tuicool.com/articles/fIbuYfI
调用RecyclerView.AddItemDecoration方法添加分割线,Recycler在绘制分割线时,会调用该类的OnDraw和OnDrawOver方法。
所以我们需要重写两个方法OnDraw或OnDrawOver(绘制分割线) 和GetItemOffsets(为RecyclerView的item设置一定的偏移量)
新建一个MyItemDecoration.cs:

    public class MyItemDecoration:RecyclerView.ItemDecoration
    {
        private static int[] ATTRS = new int[] {Android.Resource.Attribute.ListDivider};
        public static int HORIZONTAL = LinearLayoutManager.Horizontal;
        public static int VERTICAL = LinearLayoutManager.Vertical;
        private Drawable _divider;
        private int _orientation;
        public MyItemDecoration(Context context ,int orientation)
        {
            TypedArray t = context.ObtainStyledAttributes(ATTRS);
            _divider = t.GetDrawable(0);
            t.Recycle();
            SetOrientation(orientation);
        }
        public void SetOrientation(int orientation)
        {
            if (orientation != HORIZONTAL && orientation != VERTICAL)
                throw new System.Exception("invalid orientation");
            _orientation = orientation;
        }
        public override void OnDraw(Canvas cValue, RecyclerView parent)
        {
            if (_orientation == VERTICAL){
                DrawVertical(cValue,parent);
            }
            else{
                DrawHorizontal(cValue, parent);
            }
        }
        //竖屏时画竖线
        public void DrawVertical(Canvas c, RecyclerView parent)
        {
            int left = parent.PaddingLeft;
            int right = parent.Width - parent.PaddingRight;
            int childCount = parent.ChildCount;
            for (int i = 0; i < childCount; i++)
            {
                View childView = parent.GetChildAt(i);
                RecyclerView v = new RecyclerView(parent.Context);
                RecyclerView.LayoutParams _params = (RecyclerView.LayoutParams)childView.LayoutParameters;
                int top = childView.Bottom + _params.BottomMargin;
                int bottom = top + _divider.IntrinsicHeight;
                _divider.SetBounds(left,top,right,bottom);
                _divider.Draw(c);
            }
        }
//横屏时画横线
        public void DrawHorizontal(Canvas c, RecyclerView parent)
        {
            int top = parent.PaddingTop;
            int bottom = parent.Height - parent.PaddingBottom;
            int childCount = parent.ChildCount;
            for (int i = 0; i < childCount; i++)
            {
                View childView = parent.GetChildAt(i);
                RecyclerView v = new RecyclerView(parent.Context);
                RecyclerView.LayoutParams _params = (RecyclerView.LayoutParams)childView.LayoutParameters;
                int left = childView.Right + _params.RightMargin;
                int right= left + _divider.IntrinsicHeight;
                _divider.SetBounds(left, top, right, bottom);
                _divider.Draw(c);
            }
        }
        public override void GetItemOffsets(Rect outRect, int itemPosition, RecyclerView parent)
        {
            if (_orientation == VERTICAL) {
                outRect.Set(0,0,0,_divider.IntrinsicHeight);
            }
            else{
                outRect.Set(0,0,_divider.IntrinsicWidth,0);
            }
        }
    }

在activity中添加分割线加上这句代码

recyclerView.AddItemDecoration(new  MyDecoration(this,(int)Orientation.Vertical));

效果如图:
这里写图片描述
private static int[] ATTRS = new int[] {Android.Resource.Attribute.ListDivider};这里调用的是系统的分割线样式,参考hongyang的博客,我们也可以在Theme中自定义这个分割线的样式。Theme中是这样的

  <style name="BaseAppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="windowActionBar">false</item>
    <item name="windowNoTitle">true</item>
    <item name="colorPrimary">@color/primary</item>
    <item name="colorPrimaryDark">@color/primaryDark</item>
    <item name="android:listDivider">@drawable/divider_bg</item>
  </style>

divider_bg.xml

<?xml version="1.0" encoding="utf-8" ?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
       android:shape="rectangle">
  <gradient
    android:centerColor="#ff00ff00"
    android:endColor="#ff0000ff"
    android:startColor="#ffff0000"
    android:type="linear"/>
  <size android:height="4dp"/>
</shape>

最终实现了一个彩虹色的分割线
这里写图片描述

3.RecyclerView添加点击产生水波纹效果

和分割线一样,RecyclerView默认的也是没有水波纹的效果,这点不同于ListView。由于RecyclerView是android5.0的控件,所以先新建一个drawable-v21的文件夹,添加ripple_recyclerview.xml

<?xml version="1.0" encoding="utf-8" ?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
        android:color="@color/primary">
  <item android:drawable="@color/white"/>
</ripple>

同时也需要支持android5.0以下的版本,当然没有这种水波纹的效果。在drawable文件夹中添加ripple_recyclerview.xml

<?xml version="1.0" encoding="utf-8" ?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:drawable="@color/primary" android:state_pressed="true"/>
  <item android:drawable="@color/white" android:state_pressed="false"/>
</selector>

在RecyclerView的子布局item_recyclerView.axml中加上background属性

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/ripple_recyclerView">
    <TextView
        android:id="@+id/tv_num"
        android:layout_height="50dp"
        android:layout_width="match_parent"
        android:gravity="center"
        android:text="1" />
</LinearLayout>

在android5.0以上版本,现在单击就会产生一个水波纹的效果,符合Material Design的设计规范
这里写图片描述

4. RecyclerView添加单击事件

RecyclerView中的item添加单击事件,可以在RecyclerAdapter.cs中去添加,要注意两点:1.错位2.事件的具体实现推荐在MainActivity中去实现,也就是在适配器中仅声明,事件的实现交给外面的调用者
参考java的具体做法:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0327/2647.html
C#中没有java匿名内部类,不能做到在设置事件监听的时候去new 一个接口,但是C#有委托,在适配器中声明一个委托,将这个事件传递给外面的调用者,实现效果还是一样的。首先我们在RecyclerViewAdapter.cs中声明委托和事件

   public delegate void ItemClick(View v ,int position);
   public  event ItemClick OnItemClick;

在OnCreateViewHolder方法中添加事件

        public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
        {
            var  itemView = LayoutInflater.From(_context).Inflate(Resource.Layout.item_recyclerView, parent, false);
            MyViewHolder myViewHolder = new MyViewHolder(itemView);
            itemView.SetOnClickListener(this);
            itemView.Click += delegate {
                OnItemClick(itemView,(int)itemView.Tag);
            };
            return myViewHolder;
        }

这里的Tag需要在OnBindViewHolder方法中去设置item的position,以便点击时获取

  public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
        {
            MyViewHolder myViewHolder = holder as MyViewHolder;
            myViewHolder.tv_title.Text=_data[position];
            myViewHolder.ItemView.Tag=position;
        }

在Acticity中添加事件的具体实现

    adapter.OnItemClick += (view, position) =>
            {
                Toast.MakeText(this,"position:"+position+","+data[position],ToastLength.Short).Show();
            };

这里写图片描述

作者:kebi007 发表于2017/9/14 0:30:37 原文链接
阅读:81 评论:0 查看评论

Viewing all articles
Browse latest Browse all 5930

Trending Articles