Android開發--RecyclerView使用,看AndroidL新特性,android5.0新特性

銳湃發表於2015-12-10

在去年Google I/0大會,Google開放了一個全新的檢視類RecyclerView,它被用來代替ListView以及GridView,提供更為高效的回收複用機制,同時實現管理與檢視的解耦合,今天對這個新的控制元件來進行一次總結。

概述

首先,讓我們來看一下RecyclerView類之下都有哪些重要的類,以及他們的作用:

  • RecyclerView.Adapter:託管資料集合,為每個Item建立檢視;
  • RecyclerView.ViewHolder:承載Item檢視的子檢視;
  • RecyclerView.LayoutManager:負責Item檢視的佈局;
  • RecyclerView.ItemDecoration:為每個Item檢視新增子檢視,在Demo中被用來繪製Divider;
  • RecyclerView.ItemAnimator:負責新增、刪除資料時的動畫效果;

基本用法

首先讓我來看一下RecyclerView的基本用法:

1.建立一個線性佈局管理器LayoutManager

// 建立一個線性佈局管理器
mLayoutManager = new LinearLayoutManager(this);
// 預設是Vertical,可以不寫
mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
mRecyclerView.setLayoutManager(mLayoutManager);

2.重新一個adapter繼承RecyclerView.Adapter《VH》,VH就表示我們平時在ListView中用的ViewHolder類(該類必須繼承RecyclerView.ViewHolder);

在adapter中有幾個重要的方法需要我們自己補充:

  • public int getItemCount():返回顯示Item總數;
  • public void onBindViewHolder(ViewHolder vh, int position):繫結View到Item上vh就是我們在繼承RecyclerView.Adapter傳入的VH型別,在這個方法中處理資料顯示到Item上;
  • public ViewHolder onCreateViewHolder(ViewGroup view, int position):在該方法中我們建立一個ViewHolder並返回,ViewHolder必須有一個帶有View的建構函式,這個View就是我們Item的根佈局,在這裡我們可以自定義Item的佈局;
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {

    private List<String> dataList;

    public MyAdapter(List<String> list) {
        this.dataList = list;
    }

    @Override
    public int getItemCount() {
        // TODO Auto-generated method stub
        return dataList.size();
    }

    @Override
    public void onBindViewHolder(ViewHolder viewHolder, int position) {
        // TODO Auto-generated method stub
        viewHolder.textView.setText(dataList.get(position));
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int position) {
        // TODO Auto-generated method stub
        View view = LayoutInflater.from(viewGroup.getContext()).inflate(
                R.layout.item, null);
        ViewHolder holder = new ViewHolder(view);
        return holder;
    }

    public class ViewHolder extends RecyclerView.ViewHolder {

        public TextView textView;

        public ViewHolder(View view) {
            super(view);
            // TODO Auto-generated constructor stub
            textView = (TextView) view.findViewById(R.id.item_text);
        }

    }

}

3.設定資料集

List<String> list = new ArrayList<String>();
for (int i = 0; i < 100; i++) {
    list.add("item  "+ i);
}
MyAdapter adapter = new MyAdapter(list);
mRecyclerView.setAdapter(adapter);

改變LinearLayoutManager的方向可以設定為橫向的ListView顯示,這也是RecyclerView的強大之處,可以實現回收管理和檢視的解耦。

mLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);

如何為Item新增分割線

簡單的使用之後我們看到的RecyclerView連基本的分割線都沒有,接下來就來看看如何為它新增分割線吧:使用addItemDecoration方法可以為RecyclerView新增一個ItemDecoration,利用ItemDecoration為我們繪製分割線。

ItemDecoration下有三個方法,ItemDecoration並沒有對其實現,需要我們自己完成:

  • onDraw方法:其繪製將會在每個Item被繪製之前進行;
  • onDrawOver:在繪製完Item後進行繪製;
  • getItemOffsets 可以通過outRect.set()為每個Item設定一定的偏移量;

讓我們來看看程式碼:

public class ItemDivider extends ItemDecoration {

    private Drawable mDrawable;

    public ItemDivider(Context context, int resId) {
        //在這裡我們傳入作為Divider的Drawable物件
        mDrawable = context.getResources().getDrawable(resId);
    }

    @Override
    public void onDrawOver(Canvas c, RecyclerView parent) {
        final int left = parent.getPaddingLeft();
        final int right = parent.getWidth() - parent.getPaddingRight();

        final int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View child = parent.getChildAt(i);
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
                    .getLayoutParams();
            //以下計算主要用來確定繪製的位置
            final int top = child.getBottom() + params.bottomMargin;
            final int bottom = top + mDrawable.getIntrinsicHeight();
            mDrawable.setBounds(left, top, right, bottom);
            mDrawable.draw(c);
        }
    }

    @Override
    public void getItemOffsets(Rect outRect, int position, RecyclerView parent) {
        outRect.set(0, 0, 0, mDrawable.getIntrinsicWidth());
    }
}

在這裡我寫了一個shape來代替分割線:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle" >

    <solid android:color="#000" />

    <size android:height="2dp" />

</shape>

新增分割線的效果:

如何新增點選事件 ##

在Adapter中設定自己OnItemClickListener以及OnItemLongClickListener 
在ViewHolder中公開Item的根佈局View,之後在onBindViewHolder方法獲得根佈局View並設定點選的listener,呼叫自己設定的listener

1.首先在MyAdapter中建立自己的介面:

public interface OnItemClickListener {
    public void onClick(View parent, int position);
}

public interface OnItemLongClickListener {
    public boolean onLongClick(View parent, int position);
}

2.接著在ViewHolder中將根佈局View公開:

public class ViewHolder extends RecyclerView.ViewHolder {

        public TextView textView;
        public View itemView;

        public ViewHolder(View view) {
            super(view);
            // TODO Auto-generated constructor stub
            itemView = view;
            textView = (TextView) view.findViewById(R.id.item_text);
        }

    }
3.最後在onBindViewHolder對itemView設定點選事件:

iewHolder.itemView.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                if (onItemClickListener != null) {
                    onItemClickListener.onClick(v, position);
                }
            }
        });
viewHolder.itemView.setOnLongClickListener(new OnLongClickListener() {

            @Override
            public boolean onLongClick(View v) {
                // TODO Auto-generated method stub
                if (onItemLongClickListener != null) {
                    return onItemLongClickListener.onLongClick(v, position);
                }
                return false;
            }
        });

如何判斷是否滑動到達尾部或頂部

LinearLayoutManager提供瞭如下幾個方法來幫助開發者獲取螢幕上的頂部item和底部item: 
findFirstVisibleItemPosition() 
findFirstCompletelyVisibleItemPosition() 
findLastVisibleItemPosition() 
findLastCompletelyVisibleItemPosition()

這樣我們就得到了思路:對RecyclerView設定滑動監聽事件,在其中進行判斷:

mRecyclerView.setOnScrollListener(new OnScrollListener() {
    boolean isShowTop = false;
    boolean isShowBottom = false;

    @Override
    public void onScrolled(int arg0, int arg1) {
        // TODO Auto-generated method stub
        if (mLayoutManager.findLastCompletelyVisibleItemPosition() == 99) {
            if (!isShowTop) {
                Toast.makeText(MainActivity.this, "滑動到底部",
                        Toast.LENGTH_SHORT).show();
            }
            isShowTop = true;

        } else {
            isShowTop = false;
        }
        if (mLayoutManager.findFirstCompletelyVisibleItemPosition() == 0) {
            if (!isShowBottom) {
                Toast.makeText(MainActivity.this, "滑動到頂部",
                        Toast.LENGTH_SHORT).show();

            }
            isShowBottom = true;
        } else {
            isShowBottom = false;
        }
    }

    @Override
    public void onScrollStateChanged(int arg0) {
        // TODO Auto-generated method stub

    }
});

來看一下效果:

新增或移除資料

RecyclerView.Adapter中提供了兩個方法來做出新增資料或刪除資料的調整: 
public final void notifyItemInserted(int position) 
public final void notifyItemRemoved(int position)

這樣我們只需在自己的Adapter中提供新增或刪除的方法,並在方法之中呼叫上述方法即可:

 public void insert(String data, int position){
        dataList.add(position, data);
        notifyItemInserted(position);
    }

    public void remove(int position){
        dataList.remove(position);
        notifyItemRemoved(position);
    }

接下來我在Activity中對RecyclerView設定點選新增資料,長按刪除資料;

 adapter.setOnItemClickListener(new OnItemClickListener() {

            @Override
            public void onClick(View parent, int position) {
                // TODO Auto-generated method stub
                adapter.insert("Insert", position);
            }
        });
        adapter.setOnItemLongClickListener(new OnItemLongClickListener() {

            @Override
            public boolean onLongClick(View parent, int position) {
                // TODO Auto-generated method stub
                adapter.remove(position);
                return true;
            }
        });

來看一下效果吧:

ItemAnimator可以設定載入和移除時的動畫,我們可以通過setItemAnimator方法設定,但目前只提供了DefaultItemAnimator。

轉自:http://www.bkjia.com/Androidjc/988765.html

相關文章