本篇blog參照網上大神demo實現,效果一樣http://frank-zhu.github.io/android/2015/02/26/android-recyclerview-part-3/。
關鍵點:
- CardView的使用,CardView繼承的是FrameLayout,所以擺放內部控件的時候需要注意一下;
- RecyclerView的簡單使用,關鍵理解RecyclerView實現的思想,對比ListView學習;
- array配置文件讀取
一、首先,引入依賴包,重新編譯
compile 'com.android.support:appcompat-v7:22.2.0'
compile 'com.android.support:recyclerview-v7:21.0.3'
compile 'com.android.support:cardview-v7:21.0.3'
CardView
先來簡單介紹下CardView,其實我們可以在很多App中已經看到過這樣的效果,就是把list的一個item做成卡片樣式的,之前很多人通過自定義view可以實現卡片的效果,不過現在有了現成的,Google親生。CardView繼承的是FrameLayout,所以擺放內部控件的時候需要注意一下啦。
簡單總結下CardView的參數:
<resources>
<declare-styleable name="CardView">
<!-- Background color for CardView. -->
<!-- 背景色 -->
<attr name="cardBackgroundColor" format="color" />
<!-- Corner radius for CardView. -->
<!-- 邊緣弧度數 -->
<attr name="cardCornerRadius" format="dimension" />
<!-- Elevation for CardView. -->
<!-- 高度 -->
<attr name="cardElevation" format="dimension" />
<!-- Maximum Elevation for CardView. -->
<!-- 最大高度 -->
<attr name="cardMaxElevation" format="dimension" />
<!-- Add padding in API v21+ as well to have the same measurements with previous versions. -->
<!-- 設置內邊距,v21+的版本和之前的版本仍舊具有一樣的計算方式 -->
<attr name="cardUseCompatPadding" format="boolean" />
<!-- Add padding to CardView on v20 and before to prevent intersections between the Card content and rounded corners. -->
<!-- 在v20和之前的版本中添加內邊距,這個屬性是爲了防止卡片內容和邊角的重疊 -->
<attr name="cardPreventCornerOverlap" format="boolean" />
<!-- 下面是卡片邊界距離內部的距離-->
<!-- Inner padding between the edges of the Card and children of the CardView. -->
<attr name="contentPadding" format="dimension" />
<!-- Inner padding between the left edge of the Card and children of the CardView. -->
<attr name="contentPaddingLeft" format="dimension" />
<!-- Inner padding between the right edge of the Card and children of the CardView. -->
<attr name="contentPaddingRight" format="dimension" />
<!-- Inner padding between the top edge of the Card and children of the CardView. -->
<attr name="contentPaddingTop" format="dimension" />
<!-- Inner padding between the bottom edge of the Card and children of the CardView. -->
<attr name="contentPaddingBottom" format="dimension" />
</declare-styleable>
</resources>
RecyclerView
先來說說RecycleView的優點就是,他可以通過設置LayoutManager來快速實現listview、gridview、瀑布流的效果,而且還可以設置橫向和縱向顯示,添加動畫效果也非常簡單(自帶了ItemAnimation,可以設置加載和移除時的動畫,方便做出各種動態瀏覽的效果),也是官方推薦使用的。
關鍵是RecyclerView將view的操作交給了Adapter,而不在自身處理view。
OK,簡單瞭解了CardView、RecyclerView,接下來實現我們的效果!
簡單效果的實現:
很簡單的List列表樣式,外層RecycleView,item用CardView實現。
activity_main佈局文件:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/m_rv"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
關鍵是我們的NormalRecyclerViewAdapter
package com.wj.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 android.widget.Toast;
import com.wj.R;
/**
* Created by ${wj} ,
* on 2015/7/15 0015.
*/
public class NormalRecyclerViewAdapter extends RecyclerView.Adapter<NormalRecyclerViewAdapter.NormalTextViewHolder>{
/**
* 視圖加載器
*/
private LayoutInflater mInflater;
/**
* 內容提供者
*/
private Context mContext;
/**
* Item展示的內容,這裏只是一個簡單的text.
*/
private String[] mTitles;
/**
* 構造器,正常應該傳入我們Item所要展示的對象List,這裏只是簡單實現了文字展示
* @param context
*/
public NormalRecyclerViewAdapter(Context context) {
this.mContext = context;
mInflater=LayoutInflater.from(mContext);
mTitles=mContext.getResources().getStringArray(R.array.titles);
}
/**
* 創建RecyclerView的VIewHolder
* @param viewGroup
* @param i
* @return
*/
@Override
public NormalTextViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
//加載佈局文件
View view=mInflater.inflate(R.layout.item_text,viewGroup,false);
//創建佈局文件對應的ViewHolder
return new NormalTextViewHolder(view);
}
/**
* 實例化viewHolder中各控件內容
* @param normalTextViewHolder
* @param i
*/
@Override
public void onBindViewHolder(NormalTextViewHolder normalTextViewHolder, int i) {
normalTextViewHolder.itemText.setText(mTitles[i]);
}
/**
* 返回Item個數
* @return
*/
@Override
public int getItemCount() {
return mTitles==null ? 0 : mTitles.length;
}
/**
* RecyclerView關鍵類,ViewHolder.這個就是RecyclerView優於ListView的關鍵點之一,封裝了ViewHolder,可以更好的實現view的重載
* 這裏需要做的操作
* 1.聲明我們的Item裏面的所有控件
* 2.在構造函數中初始化我們聲明的控件
* 3.可以設置Item的點擊事件,不再像ListView一樣,交給外層來處理
*/
public class NormalTextViewHolder extends RecyclerView.ViewHolder{
private TextView itemText;
public NormalTextViewHolder(View itemView) {
super(itemView);
itemText= (TextView) itemView.findViewById(R.id.text_view);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(mContext,mTitles[getPosition()],Toast.LENGTH_SHORT).show();
}
});
}
}
}
爲了方便理解,我加了詳細的註釋
MainActivity中很簡單
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView= (RecyclerView) findViewById(R.id.m_rv);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
//mRecyclerView.setLayoutManager(new GridLayoutManager(this,2));
mAdapter=new NormalRecyclerViewAdapter(this);
mRecyclerView.setAdapter(mAdapter);
// mAdapter1=new MultipleItemAdapter(this);
// mRecyclerView.setAdapter(mAdapter1);
}
關鍵注意:設置Layoutmanger方法,可以看到上面代碼我們設置了linearLayoutManger和GridLayoutManger,就可以分別實現上面的兩種效果。
接下來再來看一下Adapter的複雜用法,可以看到下面效果Item的展示形式不一樣,對的,這裏其實我們用了兩個Item的佈局,一個是圖片+文字的,一個是單有文字的(紅色背景)。感覺這樣的效果蠻讚的,那麼如何實現呢,其實很簡單。
關鍵還是在Adapter中實現,MultileItemAdapter,這裏我們寫了兩個ViewHoder
/**
* 只顯示文本的item
*/
public class TextViewHolder extends RecyclerView.ViewHolder{
private TextView itemText;
public TextViewHolder(View itemView) {
super(itemView);
itemText= (TextView) itemView.findViewById(R.id.text_view);
//Item的點擊事件
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(mContext, mTitles[getPosition()], Toast.LENGTH_SHORT).show();
}
});
}
}
/**
* 顯示圖像和文本的viewhoder
*/
public class ImageViewHolder extends RecyclerView.ViewHolder{
private ImageView imageView;
private TextView textView;
public ImageViewHolder(View itemView) {
super(itemView);
imageView= (ImageView) itemView.findViewById(R.id.item_image_iv);
textView= (TextView) itemView.findViewById(R.id.item_image_tv);
//Item的點擊事件
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(mContext, mTitles[getPosition()], Toast.LENGTH_SHORT).show();
}
});
}
}
那麼我們如何來區分加載這兩個view呢,很簡單
public class MultipleItemAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
/**
* 枚舉類型,兩種顯示方式
*/
public static enum ITEM_TYPE{
ITEM_TYPE_IMAGE,
ITEM_TYPE_TEXT
}
/**
* 不註釋了,應該明白
*/
private LayoutInflater mInflater;
private Context mContext;
private String[] mTitles;
/**
* 同上
* @param context
*/
public MultipleItemAdapter(Context context) {
this.mContext = context;
mInflater=LayoutInflater.from(mContext);
//從values的array文件裏讀取數據
mTitles=mContext.getResources().getStringArray(R.array.titles);
}
/**
* 關鍵在這裏實現,onCreateViewHolder裏面帶了一個叫做viewType的參數,這個參數就是標識view的類型的
* @param parent
* @param viewType
* @return
*/
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//java.lang.Enum.ordinal()方法返回此枚舉常量的序數(其枚舉聲明中的位置,其中初始常量分配的序數爲零)。
if(viewType==ITEM_TYPE.ITEM_TYPE_IMAGE.ordinal()){
View view=mInflater.inflate(R.layout.item_image,parent,false);
return new ImageViewHolder(view);
}else {
View view=mInflater.inflate(R.layout.item_text,parent,false);
return new TextViewHolder(view);
}
}
/**
* 這裏判斷holder是屬於哪一個,返回對應的viewhoder
* @param holder
* @param position
*/
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if(holder instanceof ImageViewHolder){
((ImageViewHolder)holder).imageView.setImageResource(R.drawable.test);
((ImageViewHolder)holder).textView.setText(mTitles[position]);
}else if(holder instanceof TextViewHolder){
((TextViewHolder)holder).itemText.setText(mTitles[position]);
}
}
@Override
public int getItemCount() {
return mTitles==null ? 0 : mTitles.length;
}
/**
* 關鍵方法,對應上面onCreateViewHoder裏面的newsType
* 重寫Recycler.Adapter的getItemViewType方法
* 這裏我們設置了單雙數區別
* @param position
* @return
*/
@Override
public int getItemViewType(int position) {
return position%2==0 ? ITEM_TYPE.ITEM_TYPE_IMAGE.ordinal() : ITEM_TYPE.ITEM_TYPE_TEXT.ordinal();
}
OK,基本用法介紹到這裏Over!
歡迎留言指導交流!