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 ArrayList mData; 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
文章列表
請先 登入 以發表留言。