1. 程式人生 > >RecyclerView的使用、res下新建選單menu-main.xml

RecyclerView的使用、res下新建選單menu-main.xml

2.使用RecyclerView需要匯入support v7包:

在build.gradle(app)中設定:(和AndroidStudio設定的一樣就行了,哈哈)

compile 'com.android.support:recyclerview-v7:25.1.0'

3.疑問:瀑布流中新增分割線操作?

4.程式碼如下:

MainActivity:

package com.ruru.recyclerview;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.Menu;
import android.view.MenuItem;

import com.ruru.recyclerview.adapter.DividerGridItemDecoration;
import com.ruru.recyclerview.adapter.DividerItemDecoration;
import com.ruru.recyclerview.adapter.MyAdapter;

import java.util.ArrayList;
import java.util.List;

/**
 * RecycleView-回收與複用View 高度解耦 給予充分定製自由
 */
public class MainActivity extends AppCompatActivity {
    //列印log語句
    public static final String TAG = "info";
    //UI控制元件
    private RecyclerView recycleView;
    //ListView集合
    private List<String> list;
    private MyAdapter mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //初始化控制元件
        initView();
        //初始化list集合
        initData();
        //初始化佈局
        initLayout();
    }

    /**
     * 初始化RecycleView的佈局
     */
    private void initLayout() {
        /*設定佈局
        RecyclerView.LayoutManager是一個抽象類 系統實現了三個實現類
        LinearLayoutManager 現行管理器,支援橫向、縱向。
        GridLayoutManager 網格佈局管理器
        StaggeredGridLayoutManager 瀑布就式佈局管理器*/

        //ListView
//        recycleView.setLayoutManager(new LinearLayoutManager(this));
//        recycleView.setAdapter(new MyAdapter(this, list));
        //當我們呼叫recycleView.addItemDecoration()方法新增decoration的時候,RecycleView在繪製的時候,
        // 會去繪製decorator,即呼叫該類的onDraw()和onDrawOver()方法
//        recycleView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST));

        //GridView
//        recycleView.setLayoutManager(new GridLayoutManager(this,4));
//        recycleView.setAdapter(new MyAdapter(this, list));
//        recycleView.addItemDecoration(new DividerGridItemDecoration(this));

        // 瀑布流StaggeredGridLayoutManager
        // 第二個引數傳一個orientation,
        // 如果傳入的是StaggeredGridLayoutManager.VERTICAL代表有多少列;注:固定列上下混動
        // 如果傳入的是StaggeredGridLayoutManager.HORIZONTAL就代表有多少行;注:固定行的話可能會左右滑動
        //如果是橫向的時候,item的寬度需要注意去設定,畢竟橫向的寬度沒有約束了,應為控制元件可以橫向滾動了
        recycleView.setLayoutManager(new StaggeredGridLayoutManager(4, StaggeredGridLayoutManager.VERTICAL));
        mAdapter = new MyAdapter(this, list);
        recycleView.setAdapter(mAdapter);

        // 設定item動畫
        recycleView.setItemAnimator(new DefaultItemAnimator());
    }

    /**
     * 初始化list集合資料
     */
    private void initData() {
        list = new ArrayList<String>();
        for (int i = 1; i < 10; i++) {
            list.add("序號" + i);
        }
    }

    /**
     * 初始化控制元件
     */
    private void initView() {
        recycleView = (RecyclerView) findViewById(R.id.recycleView);
    }

    /**
     * Activity中點選MenuItem觸發
     * 注意,這裡更新資料集不是用adapter.notifyDataSetChanged()
     * 而是notifyItemInserted(position)與notifyItemRemoved(position)
     */
    @Override
    public boolean onCreateOptionsMenu(Menu menu)
    {
        getMenuInflater().inflate(R.menu.main, menu);
        return super.onCreateOptionsMenu(menu);
    }

    /**
     * Activity中點選MenuItem觸發
     */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.id_action_add:
                mAdapter.addData(1);
                break;
            case R.id.id_action_delete:
                mAdapter.removeData(1);
                break;
        }
        return true;
    }
}
MyAdapter:
package com.ruru.recyclerview.adapter;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.ruru.recyclerview.R;
import java.util.List;

/**
 * Created by SophieLiang on 2017/2/28.
 */
//注意要加後面的<MyAdapter.MyViewHolder>
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {

    private Context context;
    private List<String> list;

    public MyAdapter(Context context, List<String> list) {
        this.context = context;
        this.list = list;
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        MyViewHolder holder = new MyViewHolder(LayoutInflater.from(context).inflate(R.layout.item, parent, false));
        return holder;
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        holder.tv_name.setText(list.get(position));
        //如果是瀑布流的話,為item設計個隨機的高度
    }

    @Override
    public int getItemCount() {
        return list.size();
    }

    class MyViewHolder extends RecyclerView.ViewHolder {

        TextView tv_name;//不要寫成private static

        public MyViewHolder(View itemView) {
            super(itemView);
            tv_name = (TextView) itemView.findViewById(R.id.tv_name);
        }
    }

    /**
     * 新增動畫更新資料集
     */
    public void addData(int position) {
        list.add(position, "Insert One");
        notifyItemInserted(position);
    }

    /**
     * 刪除動畫更新資料集
     */
    public void removeData(int position) {
        list.remove(position);
        notifyItemRemoved(position);
    }
}
ItemDecoration:
package com.ruru.recyclerview;

import android.graphics.Canvas;
import android.graphics.Rect;
import android.support.v7.widget.RecyclerView;
import android.view.View;

/**
 * Created by SophieLiang on 2017/2/28.
 */
public abstract class ItemDecoration {

    //onDraw方法先於drawChildren
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        onDraw(c, parent, state);
    }

    //onDrawOver在drawChildren之後,一般我們選擇複寫其中一個即可。
    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
        onDrawOver(c, parent, state);
    }

    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        getItemOffsets(outRect, ((RecyclerView.LayoutParams) view.getLayoutParams()).getViewLayoutPosition(),
                parent);
    }

    //getItemOffsets 可以通過outRect.set()為每個Item設定一定的偏移量,主要用於繪製Decorator。
    @Deprecated
    public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
        outRect.set(0, 0, 0, 0);
    }
}
DividerItemDecoration:ListView新增分割線的操作
/**
 * Created by SophieLiang on 2017/2/28.
 * 新增分割線操作
 */
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
    private static final String TAG = "info";

    /**
     * 通過讀取系統主題中的 Android.R.attr.listDivider作為Item間的分割線,並且支援橫向和縱向
     */
    private static final int[] ATTRS = new int[]{
            android.R.attr.listDivider
    };

    //定義了兩個方法中的orientation
    public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;

    public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;

    //獲取到listDivider以後,該屬性的值是個Drawable
    private Drawable mDivider;

    private int mOrientation;

    public DividerItemDecoration(Context context, int orientation) {
        //自定義屬性
        final TypedArray a = context.obtainStyledAttributes(ATTRS);
        mDivider = a.getDrawable(0);
        a.recycle();
        //設定分割線的方向
        setOrientation(orientation);
    }

    /**
     * 設定分割線方向
     */
    public void setOrientation(int orientation) {
        if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
            throw new IllegalArgumentException("invalid orientation");
        }
        mOrientation = orientation;
    }

    /**
     * 畫分割線:一個item只有一個children
     */
    @Override
    public void onDraw(Canvas c, RecyclerView parent) {
        Log.i(TAG, "onDraw:+++ ");
        if (mOrientation == VERTICAL_LIST) {
            drawVertical(c, parent);
        } else {
            drawHorizontal(c, parent);
        }
    }

    /**
     * 畫垂直分割線
     */
    public void drawVertical(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);
            android.support.v7.widget.RecyclerView v = new android.support.v7.widget.RecyclerView(parent.getContext());
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
            final int top = child.getBottom() + params.bottomMargin;
            final int bottom = top + mDivider.getIntrinsicHeight();
            mDivider.setBounds(left, top, right, bottom);//左上右下
            mDivider.draw(c);
        }
    }

    /**
     * 畫水平分割線
     */
    public void drawHorizontal(Canvas c, RecyclerView parent) {
        final int top = parent.getPaddingTop();
        final int bottom = parent.getHeight() - parent.getPaddingBottom();

        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 left = child.getRight() + params.rightMargin;
            final int right = left + mDivider.getIntrinsicHeight();
            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }

    /**
     * 在getItemOffsets中,outRect去設定了繪製的範圍。onDraw中實現了真正的繪製
     */
    @Override
    public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
        if (mOrientation == VERTICAL_LIST) {
            outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
        } else {
            outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
        }
    }
}
DividerGridItemDecoration: GridView新增分割線的操作
public class DividerGridItemDecoration extends RecyclerView.ItemDecoration {
    private static final int[] ATTRS = new int[]{android.R.attr.listDivider};
    private Drawable mDivider;

    public DividerGridItemDecoration(Context context) {
        final TypedArray a = context.obtainStyledAttributes(ATTRS);
        mDivider = a.getDrawable(0);
        a.recycle();
    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {

        drawHorizontal(c, parent);
        drawVertical(c, parent);

    }

    private int getSpanCount(RecyclerView parent) {
        // 列數
        int spanCount = -1;
        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager) {

            spanCount = ((GridLayoutManager) layoutManager).getSpanCount();
        } else if (layoutManager instanceof StaggeredGridLayoutManager) {
            spanCount = ((StaggeredGridLayoutManager) layoutManager)
                    .getSpanCount();
        }
        return spanCount;
    }

    public void drawHorizontal(Canvas c, RecyclerView parent) {
        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 left = child.getLeft() - params.leftMargin;
            final int right = child.getRight() + params.rightMargin
                    + mDivider.getIntrinsicWidth();
            final int top = child.getBottom() + params.bottomMargin;
            final int bottom = top + mDivider.getIntrinsicHeight();
            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }

    public void drawVertical(Canvas c, RecyclerView parent) {
        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.getTop() - params.topMargin;
            final int bottom = child.getBottom() + params.bottomMargin;
            final int left = child.getRight() + params.rightMargin;
            final int right = left + mDivider.getIntrinsicWidth();

            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }

    private boolean isLastColum(RecyclerView parent, int pos, int spanCount, int childCount) {
        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager) {
            if ((pos + 1) % spanCount == 0)// 如果是最後一列,則不需要繪製右邊
            {
                return true;
            }
        } else if (layoutManager instanceof StaggeredGridLayoutManager) {
            int orientation = ((StaggeredGridLayoutManager) layoutManager)
                    .getOrientation();
            if (orientation == StaggeredGridLayoutManager.VERTICAL) {
                if ((pos + 1) % spanCount == 0)// 如果是最後一列,則不需要繪製右邊
                {
                    return true;
                }
            } else {
                childCount = childCount - childCount % spanCount;
                if (pos >= childCount)// 如果是最後一列,則不需要繪製右邊
                    return true;
            }
        }
        return false;
    }

    private boolean isLastRaw(RecyclerView parent, int pos, int spanCount,
                              int childCount) {
        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager) {
            childCount = childCount - childCount % spanCount;
            if (pos >= childCount)// 如果是最後一行,則不需要繪製底部
                return true;
        } else if (layoutManager instanceof StaggeredGridLayoutManager) {
            int orientation = ((StaggeredGridLayoutManager) layoutManager)
                    .getOrientation();
            // StaggeredGridLayoutManager 且縱向滾動
            if (orientation == StaggeredGridLayoutManager.VERTICAL) {
                childCount = childCount - childCount % spanCount;
                // 如果是最後一行,則不需要繪製底部
                if (pos >= childCount)
                    return true;
            } else
            // StaggeredGridLayoutManager 且橫向滾動
            {
                // 如果是最後一行,則不需要繪製底部
                if ((pos + 1) % spanCount == 0) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 主要在getItemOffsets方法中,去判斷如果是最後一行,則不需要繪製底部;如果是最後一列,則不需要繪製右邊,
     * 整個判斷也考慮到了StaggeredGridLayoutManager的橫向和縱向
     * 一般如果僅僅是希望有空隙,還是去設定item的margin方便
     */
    @Override
    public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
        int spanCount = getSpanCount(parent);
        int childCount = parent.getAdapter().getItemCount();
        if (isLastRaw(parent, itemPosition, spanCount, childCount))// 如果是最後一行,則不需要繪製底部
        {
            outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
        } else if (isLastColum(parent, itemPosition, spanCount, childCount))// 如果是最後一列,則不需要繪製右邊
        {
            outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
        } else {
            outRect.set(0, 0, mDivider.getIntrinsicWidth(),
                    mDivider.getIntrinsicHeight());
        }
    }
}
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>
res右鍵第二個新建menu目錄,再新建xml檔案:main.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/id_action_add"
        android:title="新增動畫"/>
    <item
        android:id="@+id/id_action_delete"
        android:title="刪除動畫"/>
</menu>
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.ruru.recyclerview.MainActivity">

    <!--RecycleView中divider這樣的屬性不會起作用-->
    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycleView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:divider="#ffff0000"
        android:dividerHeight="10dp"></android.support.v7.widget.RecyclerView>

</RelativeLayout>

item.xml:ListView有一個item,GridView有好多個ChildView

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:background="#44ff0000">

    <TextView
        android:id="@+id/tv_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:gravity="center" />
</FrameLayout>