文章出處

RecyclerView 是Android L版本中新添加的一個用來取代ListView的SDK,RecyclerView與ListView的原理是類似的:都是僅僅維護少量的View并且可以展示大量的數據集,但是,RecyclerView提供了插拔式的體驗,高度的解耦,十分的靈活 ,通過它提供的LayoutManager,ItemDecoration,ItemAnimator可以實現令ListView可望不可即的效果。

RecyclerView用以下兩種方式簡化了數據的展示和處理:

使用LayoutManager來確定每一個item的排列方式。使用ItemAnimator來控制Item的增刪動畫。使用ItemDecoration來控制Item的間隔。

先來看看實現的效果:

\

 

下面就來詳解RecyclerView 的使用,以下給出了實現此效果的全部代碼:

1,添加依賴:

 

dependencies {    compile fileTree(dir: 'libs', include: ['*.jar'])    testCompile 'junit:junit:4.12'    compile 'com.android.support:appcompat-v7:24.+'    compile 'com.android.support:recyclerview-v7:23.2.1'}
2,RecyclerView對應的布局文件:

 

    

3,和ListView相同,RecyclerView 也需要一個適配器,需要說明的是,RecyclerView 并沒有提供點擊和長按事件監聽的API,所以需要自己來實現,這里我在適配器中通過定義接口,然后回調接口的方式來實現點擊和長按事件的監聽。代碼中有詳細注解:
package com.example.recycleviewtest;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 java.util.ArrayList;/** * Created by Administrator on 2016/10/6. * RecycleView對應的適配器 * 要求必須實現ViewHolder類,用于緩存控件 */public class MyAdapter extends RecyclerView.Adapter {    //通過構造方法把數據傳遞過來    protected ArrayListmData;    protected LayoutInflater inflater;    public MyAdapter(Context context,ArrayList mData) {        this.mData = mData;        this.inflater = LayoutInflater.from(context);    }    //定義一個接口,響應點擊事件    protected OnItemClickListener mOnItemClickListener;    protected  interface OnItemClickListener{        //點擊事件的回調        void setOnItemClick(View view,int position);        void setOnLongItemClick(View view,int position);    }    public void setmOnItemClickListener(OnItemClickListener listener) {        this.mOnItemClickListener = listener;    }    /**     * 渲染布局     */    @Override    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        View itemView = inflater.inflate(R.layout.item, parent, false);        return new MyViewHolder(itemView);    }    /**     * 將數據綁定到ViewHolder     */    @Override    public void onBindViewHolder(MyViewHolder holder, final int position) {        //將傳遞過來的數據設置給holder中的控件        holder.mTextView.setText(mData.get(position));        //初始化點擊事件        initClick(holder,position);    }    protected void initClick(MyViewHolder holder, final int position) {        //單擊事件的回調        holder.itemView.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                // mOnItemClickListener是在MainActivity調用之后傳過來的,                // 如果不為空,說明被調用了,把當前的position回調給MainActivity                if (mOnItemClickListener != null){                    mOnItemClickListener.setOnItemClick(v,position);                }            }        });        //長按事件的回調        holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {            @Override            public boolean onLongClick(View v) {                if (mOnItemClickListener != null){                    mOnItemClickListener.setOnLongItemClick(v,position);                }                return true; //注意:一定要返回true,這樣可以消費事件,讓點擊事件不再生效            }        });    }    /**     * 返回條目數     */    @Override    public int getItemCount() {        return mData.size();    }    /**     * 用于緩存條目數據的Holder類     * RcycleView要求必須實現此類     */    public class MyViewHolder extends RecyclerView.ViewHolder{        //參數itemView即為要緩存的條目布局        TextView mTextView;        public MyViewHolder(View itemView) {            super(itemView);            mTextView = (TextView) itemView.findViewById(R.id.tv);        }    }}

 

 

4,實現RecyclerView神奇效果的核心代碼+注解:

RecyclerView.LayoutManager是一個抽象類,系統提供了3個實現類:

 

①LinearLayoutManager 現行管理器,支持橫向、縱向。默認為縱向。

②GridLayoutManager 網格布局管理器,支持橫向、縱向。默認為縱向。

③StaggeredGridLayoutManager 瀑布就式布局管理器,支持橫向、縱向。默認為縱向。

 

package com.example.recycleviewtest;import android.content.Intent;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 android.view.View;import android.widget.Toast;import java.util.ArrayList;public class MainActivity extends AppCompatActivity {    private RecyclerView mRecycleView;    private ArrayListmData;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        //1.獲取RecyclerView控件        mRecycleView = (RecyclerView) findViewById(R.id.rv);        //2.獲取數據        initData();        //3.設置適配器        MyAdapter adapter = new MyAdapter(this,mData);        //4.給RecyclerView設置布局容器        // 4.1 線性布局//        mRecycleView.setLayoutManager(new LinearLayoutManager(this));        // 4.2 宮格布局(GridView) (設置為默認布局)        mRecycleView.setLayoutManager(new GridLayoutManager(this,2));        // 4.3 瀑布流布局//        mRecycleView.setLayoutManager(new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL));        //5.給RecyclerView設置適配器        mRecycleView.setAdapter(adapter);        //6.給RecyclerView添加分割線//        mRecycleView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST));        //7.給RecyclerView設置動畫        mRecycleView.setItemAnimator(new DefaultItemAnimator());        //8.給適配器設置點擊事件        adapter.setmOnItemClickListener(new MyAdapter.OnItemClickListener() {            @Override            public void setOnItemClick(View view, int position) {                Toast.makeText(MainActivity.this,"點擊了"+position+"條目",Toast.LENGTH_SHORT).show();            }            @Override            public void setOnLongItemClick(View view, int position) {                Toast.makeText(MainActivity.this,"長按了"+position+"條目",Toast.LENGTH_SHORT).show();            }        });    }    /**     * 初始化數據     */    private void initData() {        mData = new ArrayList<>();        for (int i = 'A'; i <= 'z'; i++) {            mData.add(String.valueOf((char)i));        }    }    /**     * 創建選擇菜單     * 加載自定義的菜單     * @param menu Interface for managing the items in a menu.     * @return     */    @Override    public boolean onCreateOptionsMenu(Menu menu) {        getMenuInflater().inflate(R.menu.menu,menu);        return true; //消費事件,處理自己的業務    }    /**     * 菜單選擇項     * 判斷選擇了哪個菜單項,做相應的業務     * @param item 選中的菜單項     * @return     */    @Override    public boolean onOptionsItemSelected(MenuItem item) {        int itemId = item.getItemId();        switch (itemId){  //根據選中菜單項的id來顯示不同的布局            case R.id.listView:  //線性布局                mRecycleView.setLayoutManager(new LinearLayoutManager(this));                break;            case R.id.gridView:  //宮格布局                mRecycleView.setLayoutManager(new GridLayoutManager(this,2));                break;            case R.id.horizontalStaggerGridView:  //水平瀑布流宮格布局                mRecycleView.setLayoutManager(new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.HORIZONTAL));                break;            case R.id.staggerGridView:  //垂直瀑布流宮格布局                Intent intent = new Intent(MainActivity.this,StaggerActivity.class);                startActivity(intent);                break;        }        return true;    }}

5,把不同的布局切換以菜單的形式來展示,這樣界面看起來更加的簡潔,對應的菜單文件res---->menu---->menu.xml:

 

 

    

6,適配器中條目布局對應的布局文件item.xml:

 

 

    

7,RecyclerView雖然很強大,但我感覺有兩個讓我們開發者很不爽的地方,一是沒有點擊和長按監聽事件,二是沒有提供分割線的API,所以如果我們想設置分割線的話需要自定義,我在代碼中設置分割線的代碼注釋掉了,而是使用布局文件來給每個Item設置間距,下面是官方提供的分割線的demo:

 

 

package com.example.recycleviewtest;/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */import android.content.Context;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Rect;import android.graphics.drawable.Drawable;import android.support.v7.widget.LinearLayoutManager;import android.support.v7.widget.RecyclerView;import android.util.Log;import android.view.View;/** * This class is from the v7 samples of the Android SDK. It's not by me! * 

* See the license above for details. */ public class DividerItemDecoration extends RecyclerView.ItemDecoration { //分割線的圖片屬性,系統圖片 private static final int[] ATTRS = new int[] { android.R.attr.listDivider }; //水平排列 public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL; //垂直排列 public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL; 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); } /** * 設置排列方向 * @param orientation */ public void setOrientation(int orientation) { if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) { throw new IllegalArgumentException("invalid orientation"); } mOrientation = orientation; } /** * 繪制分割線 * @param c * @param parent */ @Override public void onDraw(Canvas c, RecyclerView parent) { if (mOrientation == VERTICAL_LIST) { drawVertical(c, parent); } else { drawHorizontal(c, parent); } } /** * 畫豎直方向的分割線 * @param c * @param 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); RecyclerView v = new 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); } } /** * 畫水平方向的分割線 * @param c * @param parent */ 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); } } /** * 為分割線預留空間 * @param outRect * @param itemPosition * @param parent */ @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); } } }

 

 

8,下面是我在drawable目錄下自定義的一個分割線divider.xml:

 

            


9,實現垂直瀑布流宮格布局效果時,需要設置每個條目的高度(或寬帶)最好有差別,這里我的思路是:當選擇垂直瀑布流宮格布局時,我跳轉到另外一個StaggerActivity中,在StaggerActivity對應的適配器中來改變每個條目的高度。這個方案很笨拙,但容易理解,StaggerActivity對應的適配器代碼:

 

 

package com.example.recycleviewtest;import android.content.Context;import android.view.ViewGroup;import java.util.ArrayList;/** * Created by Administrator on 2016/10/7. */public class StaggerAdapter extends MyAdapter {    private ArrayList mHeights; //瀑布流item的高度    public StaggerAdapter(Context context, ArrayList mData) {        super(context, mData);        mHeights = new ArrayList<>();        for (int i = 0; i < mData.size(); i++) {            mHeights.add((int) (Math.random()*300 + 100));        }    }    /*        在綁定數據時改變item的高度     */    @Override    public void onBindViewHolder(MyViewHolder holder, int position) {        //2.通過getLayoutParams拿到對應控件的屬性,對其進行設置        ViewGroup.LayoutParams params = holder.mTextView.getLayoutParams();        //3.改變item的高度        params.height = mHeights.get(position);        //1.通過setLayoutParams方法來設置控件的屬性        holder.mTextView.setLayoutParams(params);        //給控件設置內容        holder.mTextView.setText(mData.get(position));        //初始化監聽事件        initClick(holder,position);    }}

10,StaggerActivity其實和MainActivity的代碼幾乎相同,只是改變適配器和menu的條目選擇后的跳轉方向。

 

 

package com.example.recycleviewtest;import android.content.Intent;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.support.v7.widget.DefaultItemAnimator;import android.support.v7.widget.RecyclerView;import android.support.v7.widget.StaggeredGridLayoutManager;import android.view.Menu;import android.view.MenuItem;import android.view.View;import android.widget.Toast;import java.util.ArrayList;public class StaggerActivity extends AppCompatActivity {    private RecyclerView mRecycleView;    private ArrayListmData;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        //1.獲取RecyclerView控件        mRecycleView = (RecyclerView) findViewById(R.id.rv);        //2.獲取數據        initData();        //3.設置適配器        StaggerAdapter adapter = new StaggerAdapter(this,mData);        //4.給RecyclerView設置布局容器        // 4.1 線性布局//        mRecycleView.setLayoutManager(new LinearLayoutManager(this));        // 4.2 宮格布局(GridView)//        mRecycleView.setLayoutManager(new GridLayoutManager(this,2));        // 4.3 瀑布流布局        mRecycleView.setLayoutManager(new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL));        //5.給RecyclerView設置適配器        mRecycleView.setAdapter(adapter);        //6.給RecyclerView設置分割線//        mRecycleView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST));        //7.給RecyclerView設置動畫        mRecycleView.setItemAnimator(new DefaultItemAnimator());        //8.給適配器設置點擊事件        adapter.setmOnItemClickListener(new MyAdapter.OnItemClickListener() {            @Override            public void setOnItemClick(View view, int position) {                Toast.makeText(StaggerActivity.this,"點擊了"+position+"條目",Toast.LENGTH_SHORT).show();            }            @Override            public void setOnLongItemClick(View view, int position) {                Toast.makeText(StaggerActivity.this,"長按了"+position+"條目",Toast.LENGTH_SHORT).show();            }        });    }    /**     * 初始化數據     */    private void initData() {        mData = new ArrayList<>();        for (int i = 'A'; i <= 'z'; i++) {            mData.add(String.valueOf((char)i));        }    }    /**     * 創建選擇菜單     * 加載自定義的菜單     * @param menu Interface for managing the items in a menu.     * @return     */    @Override    public boolean onCreateOptionsMenu(Menu menu) {        getMenuInflater().inflate(R.menu.menu,menu);        return true; //消費事件,處理自己的業務    }    /**     * 菜單選擇項     * 判斷選擇了哪個菜單項,做響應的業務     * @param item 選中的菜單項     * @return     */    @Override    public boolean onOptionsItemSelected(MenuItem item) {        int itemId = item.getItemId();        switch (itemId){  //根據選中菜單項的id來顯示不同的布局            case R.id.listView:  //線性布局                Intent intent = new Intent(StaggerActivity.this,MainActivity.class);                startActivity(intent);                break;            case R.id.gridView:  //宮格布局                Intent intent2 = new Intent(StaggerActivity.this,MainActivity.class);                startActivity(intent2);                break;            case R.id.horizontalStaggerGridView:  //水平瀑布流宮格布局                Intent intent3 = new Intent(StaggerActivity.this,MainActivity.class);                startActivity(intent3);                break;            case R.id.staggerGridView:  //垂直瀑布流宮格布局                mRecycleView.setLayoutManager(new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL));                break;        }        return true;    }}
就愛閱讀www.92to.com網友整理上傳,為您提供最全的知識大全,期待您的分享,轉載請注明出處。
歡迎轉載:http://www.kanwencang.com/bangong/20161206/63529.html

文章列表


不含病毒。www.avast.com
創作者介紹
創作者 IT工程師數位筆記本 的頭像
大師兄

IT工程師數位筆記本

大師兄 發表在 痞客邦 留言(0) 人氣( 25 )