您好,登錄后才能下訂單哦!
本文主要介紹Android Support v7提供的RecycleView和交錯式布局(通常成為瀑布流布局)的使用和事件監聽處理。
1. 涉及到開源庫有:
Fresco :
Facebook開源的不是一般強大的圖片加載組件庫
Bufferknife :
Android View和事件綁定庫,通過注解完成,在編譯時APT處理注解文檔。
2. 模塊配置
Android Studio模塊,build.gradle配置:
apply plugin: 'com.android.application' android { compileSdkVersion 21 buildToolsVersion '21.1.2' defaultConfig { applicationId 'secondriver.sdk' minSdkVersion 16 targetSdkVersion 21 versionCode 1 versionName '1.0' } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } packagingOptions { exclude 'META-INF/services/javax.annotation.processing.Processor' } lintOptions { disable 'InvalidPackage' } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:21.0.3' compile 'com.android.support:recyclerview-v7:21.0.3@aar' compile 'com.android.support:cardview-v7:21.0.3@aar' compile 'com.facebook.fresco:fresco:0.8.0' compile 'com.jakewharton:butterknife:7.0.1' testCompile 'junit:junit:4.12' }
3. 布局文件
主布局文件:activity_recycleview.xml 包含一個RecycleView,將作為主屏幕組件。
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout android:id="@+id/swipe_refresh_layout" xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"> <android.support.v7.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:scrollbars="vertical" /> </RelativeLayout>
RecycleView 通過設置不同的布局管理器對象來實現不同的布局顯示,如:
android.support.v7.widget.LinearLayoutManager 可以實現ListView的布局效果
android.support.v7.widget.GridLayoutManager 可以實現GridView的布局效果
android.support.v7.widget.StaggeredGridLayoutManager 可以實現交錯式網格布局效果
次布局文件(RecycleView中顯示的每一項視圖的布局):item_recycelview.xml 通過com.android.support:CardView包提供的CardView幀式容器布局包含一個ImageView和TextView作為RecycleView的每一項視圖的布局。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:card_view="http://schemas.android.com/apk/res-auto" xmlns:fresco="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center"> <android.support.v7.widget.CardView android:id="@+id/card_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" card_view:cardCornerRadius="4dp" card_view:cardUseCompatPadding="true"> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <com.facebook.drawee.view.SimpleDraweeView android:id="@+id/info_p_w_picpath" android:layout_width="300dp" android:layout_height="420dp" fresco:actualImageScaleType="centerCrop" fresco:placeholderImage="@mipmap/ic_launcher" fresco:roundAsCircle="false" fresco:roundBottomLeft="true" fresco:roundBottomRight="true" fresco:roundTopLeft="true" fresco:roundTopRight="true" fresco:roundedCornerRadius="1dp" fresco:roundingBorderWidth="2dp" /> <TextView android:id="@+id/info_text" android:layout_width="200dp" android:layout_height="80dp" android:textSize="20sp" android:textColor="@android:color/holo_blue_dark" android:textAppearance="?android:attr/textAppearanceMedium" android:layout_alignLeft="@id/info_p_w_picpath" android:layout_alignRight="@id/info_p_w_picpath" android:layout_below="@id/info_p_w_picpath" android:gravity="left|center_vertical"/> </RelativeLayout> </android.support.v7.widget.CardView> </LinearLayout>
ImageView組件使用的是Fresco庫提供的視圖組件。
4. Activity實現和數據填充
4.1 RecycleView中的每一項視圖的數據組成
文本信息+ 圖片地址(url,file,resId) 本示例中采用Url網絡圖片
/** * View項的數據對象 */ static class Pair { public String text; public String url; public Pair(String text, String url) { this.text = text; this.url = url; } }
4.2 RecycleView中國的每一項視圖的數據填充,即適配器
自定義適配器需要實現RecycleView.Adapter類。
static class RecycleViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { /** * RecycleView的View項單擊事件監聽 */ public interface OnRecycleViewItemClickListener { void onRecycleViewItemClick(View view, int position); } private ArrayList<Pair> items = new ArrayList<>(); private OnRecycleViewItemClickListener mOnRecycleViewItemClickListener; public RecycleViewAdapter(ArrayList<Pair> items) { this.items = items; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_recyclerview, parent, false); return new RecycleViewItemHolder(view, mOnRecycleViewItemClickListener); } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { Pair pair = items.get(position); ((RecycleViewItemHolder) holder).setContent(pair); } @Override public int getItemCount() { return items.size(); } public void setOnRecycleViewItemClickListener(OnRecycleViewItemClickListener onItemClickListener) { if (null != onItemClickListener) { this.mOnRecycleViewItemClickListener = onItemClickListener; } } }
主要實現onCreateViewHolder和onBindViewHolder方法。由于RecycleView并未提供為視圖項添加監聽事件,這里自定義個一個事件監聽接口,在實例化適配器的時候可以選擇設置事件監聽。
4.3 創建ViewHolder需要通過自定義ViewHolder類繼承RecycleView.ViewHolder。
static class RecycleViewItemHolder extends RecyclerView.ViewHolder implements View.OnClickListener { @Bind(R.id.info_text) public TextView infoTextView; @Bind(R.id.info_p_w_picpath) public SimpleDraweeView draweeView; private RecycleViewAdapter.OnRecycleViewItemClickListener onItemClickListener; public RecycleViewItemHolder(View itemView, RecycleViewAdapter.OnRecycleViewItemClickListener onItemClickListener) { super(itemView); ButterKnife.bind(this, itemView); this.onItemClickListener = onItemClickListener; itemView.setOnClickListener(this); } public void setContent(Pair pair) { infoTextView.setText(pair.text); draweeView.setImageURI(Uri.parse(pair.url)); } @Override public void onClick(View v) { if (null != onItemClickListener) { onItemClickListener.onRecycleViewItemClick(v, getPosition()); } } }
在構造方法中的傳入OnRecycleViewItemClickListener對象,并且自定義ViewHolder實現OnClickListener接口,通過為itemView對象設置OnClickListener監聽事件,在onClick方法中將點擊事件的處理交由OnRecycleViewItemClickListener對象處理,從而達到為RecycleView中的itemView注冊點擊事件。
如果不采用這種方式添加事件監聽,就不需要自定義監聽接口和自定義ViewHolder實現事件監聽接口以及事件處理。另外可以通過獲得的itemView之后,通過組件I的獲取組件來添加事件監聽。還可以通過獲得的自定義ViewHolder,來訪問每個組件。
4.4 Activity的具體實現
package secondriver.sdk.activity; import android.app.Activity; import android.net.Uri; import android.os.Bundle; import android.support.v7.widget.DefaultItemAnimator; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.StaggeredGridLayoutManager; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import android.widget.Toast; import com.facebook.drawee.view.SimpleDraweeView; import java.util.ArrayList; import java.util.Arrays; import java.util.Random; import butterknife.Bind; import butterknife.ButterKnife; import secondriver.sdk.R; /** * Author : secondriver * Created : 2015/11/18 */ public class RecycleViewActivity extends Activity { private static final String TAG = RecyclerView.class.getName(); private static final String[] RES_URL = new String[]{ "http://p1.wmpic.me/article/2015/11/16/1447644849_hySANEEF.jpg", //減少篇幅,此處省去14個圖片Url }; @Bind(R.id.recycler_view) public RecyclerView mRecycleView; private final int PRE_SCREEN_NUMBER = 6; private final int SPAN_COUNT = 2; private int previousLastIndex = 0; private boolean isSlidingToLast = false; private RecycleViewAdapter mAdapter; private ArrayList<Pair> mItem = new ArrayList<>(); //交錯式網格布局管理對象,即通常稱的瀑布流布局 private StaggeredGridLayoutManager mLayoutManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_recyclerview); ButterKnife.bind(this); Fresco.initialize(this); //重要,Fresco做一系列初始化工作 initRecycleView(); } private void initRecycleView() { mLayoutManager = new StaggeredGridLayoutManager(SPAN_COUNT, StaggeredGridLayoutManager.VERTICAL); mRecycleView.setLayoutManager(mLayoutManager); mAdapter = new RecycleViewAdapter(mItem); loadData(false); mRecycleView.setAdapter(mAdapter); mRecycleView.setItemAnimator(new DefaultItemAnimator()); //RecycleView的View項單擊事件監聽 mAdapter.setOnRecycleViewItemClickListener(new RecycleViewAdapter.OnRecycleViewItemClickListener() { @Override public void onRecycleViewItemClick(View view, int position) { long id = mRecycleView.getChildItemId(view); Log.d(TAG, "View項的根視圖:" + view.getClass().getName() + ",position=" + position + " ViewHolder_Id=" + id); //通過findViewById查找View項中的元素 SimpleDraweeView draweeView = (SimpleDraweeView) view.findViewById(R.id.info_p_w_picpath); if (null != draweeView) { draweeView.setImageURI(Uri.parse(RES_URL[0])); Toast.makeText(RecycleViewActivity.this, "通過findViewById查找View項中的元素", Toast.LENGTH_LONG).show(); } RecycleViewItemHolder recycleViewItemHolder = (RecycleViewItemHolder) mRecycleView.findViewHolderForPosition(position); if (null != recycleViewItemHolder) { recycleViewItemHolder.infoTextView.setText("通過ViewHolder找到View項中的元素"); } } }); //下拉刷新,追加內容 mRecycleView.setOnScrollListener( new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); if (newState == RecyclerView.SCROLL_STATE_IDLE) { if (isPullToBottom() && isSlidingToLast) { if (mItem.size() > 36) { //最大數據量 Toast.makeText(RecycleViewActivity.this, "沒有數據了", Toast.LENGTH_LONG).show(); return; } else { loadData(false); Log.d(TAG, "notifyItemRangeInserted startPosition=" + previousLastIndex); mAdapter.notifyItemRangeInserted(previousLastIndex, PRE_SCREEN_NUMBER); } } } if (newState == RecyclerView.SCROLL_STATE_SETTLING) { Log.d(TAG, "settling"); } } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); isSlidingToLast = dy > 0; //上拉,下滑 Log.d(TAG, "dx = " + dx + " dy=" + dy + " isSlidingToLast=" + isSlidingToLast); } } ); } private boolean isPullToBottom() { int[] lastIndexs = mLayoutManager.findLastCompletelyVisibleItemPositions(null); Log.d(TAG, "last item =" + Arrays.toString(lastIndexs) + ", have item=" + mAdapter.getItemCount()); int maxIndex = mAdapter.getItemCount() - 1; for (int i : lastIndexs) { if (i == maxIndex) { return true; } } return false; } private void loadData(boolean isClear) { if (isClear) { mItem.clear(); } previousLastIndex = mItem.size(); Random r = new Random(); for (int index = 0; index < PRE_SCREEN_NUMBER && index < RES_URL.length; index++) { mItem.add(new Pair("Card " + (previousLastIndex + index), RES_URL[r.nextInt(RES_URL.length)])); } Log.d(TAG, "mItem count =" + mItem.size()); } }
說明:
RecycleView的ItemView的數據由Pair對象管理存儲
Fresco庫默認配置下的使用之前需要初始化調用Fresco.initialize(Context)
上述實現了2個事件監聽,一個OnScrollerListener由RecycleView提供,實現下拉刷新;一個OnRecycleViewItemClickListener由自定義的RecycleViewAdpater提供,實現單擊itemView來更換圖片(SimpleDraweeView)和文字(TextView)。
Butterknife和Fresco庫的具體使用參見其Github上的文檔。
5. 效果圖
比較遺憾ScreenRecord不支持模擬器和Android4.4一下的系統,只能附上截圖。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。