Android5.x 新控件之RecyclerView,CardView,Palette的使用
自Android5.0發布以來,谷歌推出全新的Material Desigen設計風格,時過一年多了,在國內也看到很多應用在慢
慢適應MD設計風格。其中比較好的app就是網易新聞客戶端了,其設計風格基本符合MD要求。鑒于越來多App采
用MD設計風格,作為吊絲程序員的我們怎能落后呢?那就讓我們來學習一些Android5.x新推出的一些控件吧。
先上效果圖:
注明:我的開發環境是AS1.0 ,使用Eclipse的童鞋自行配置。為了能使用Android5.0的一些新控件,我們不
得不引用Support v7包,在AS里很好配置,直接在build.gradle文件下添加如下配置:
dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') compile 'com.android.support:recyclerview-v7:21.0.3' compile 'com.android.support:cardview-v7:21.0.3' compile 'com.android.support:palette-v7:22.2.0' }
RecyclerView控件
類似ListView ,GridView,RecyclerView也是一個繼承ViewGroup的容器控件,用于在有限的界面視圖情況下裝
載更多的內容。我們通過代碼來看看RecyclerView控件怎么使用的吧!先XML從布局看
<android.support.v7.widget.RecyclerView android:id="@+id/recyclerview" android:layout_width="match_parent" android:layout_height="match_parent" />
很簡單,直接引用Support v7包里的RecyclerView就可以了,貌似布局文件里沒有太多的配置,不像ListView和
GridView控件有很多配置比如:android:dividerHeight ,android:divider,android:numColumns等。這是因
為RecyclerView雖然也是容器控件,大多數的效果顯示可以通過代碼來控制顯示,但是RecyclerView更加自由,
更加包容,用戶更容易去定義它的內容顯示方
式。接下來通過代碼看怎么使用RecyclerView吧!
private void initViews() { recylerView = findView(R.id.recyclerview); //設置布局顯示方式 recylerView.setLayoutManager(new LinearLayoutManager(this, LinearLayout.VERTICAL, true)); //設置添加刪除item時候的動畫 recylerView.setItemAnimator(new DefaultItemAnimator()); }
是不是感覺還是蠻簡單的嘛?就兩行代碼,我們來看看setLayoutManager設置布局顯示方式方法吧!
setLayoutManager()方法接受一個 LayoutManager 布局管理參數。參數類型可以有以下幾種:
- LinearLayoutManager:線性布局
- GridLayoutManager:網格布局
- StaggeredGridLayoutManager:流式布局 </ol>
- Description:RecyclerView 適配器
- User: xjp
- Date: 2015/6/8
- Time: 10:15 */
- notifyDataSetChanged():更新所有數據
- notifyItemInserted(int position):在position位置插入數據的時候更新
- notifyItemRemoved(int position):移除postion位置的數據的時候更新
- notifyItemChanged(int position):當postion位置數據有改變時候更新
- notifyItemMoved(int fromPosition, int toPosition):移除從位置formPosition到toPosition位置數據更新
- notifyItemRangeChanged(int positionStart, int itemCount)
- notifyItemRangeInserted(int positionStart, int itemCount)
- notifyItemRangeRemoved(int positionStart, int itemCount) </ol>
- cardElevation:卡片陰影的寬度
- cardMaxElevation:最大卡片陰影的寬度
- cardBackgroundColor:卡片的背景顏色
- cardCornerRadius :卡片的圓角半徑 </ol>
- Palette.Swatch a = palette.getVibrantSwatch();//有活力
- Palette.Swatch b = palette.getDarkVibrantSwatch();//有活力 暗色
- Palette.Swatch c = palette.getLightVibrantSwatch();//有活力 亮色
- Palette.Swatch d = palette.getMutedSwatch();//柔和
- Palette.Swatch e = palette.getDarkMutedSwatch();//柔和 暗色
- Palette.Swatch f = palette.getLightMutedSwatch();//柔和 亮色 </ol>
- int color1 = a.getBodyTextColor();//內容顏色
- int color2 = a.getTitleTextColor();//標題顏色
- int color3 = a.getRgb();//rgb顏色 </ol>
- Description:RecyclerView 適配器
- User: xjp
- Date: 2015/6/8
- Time: 10:15 */
那么怎么new一個LayoutManager出來呢?舉個例子:
new LinearLayoutManager(this, LinearLayout.VERTICAL, true)
第一個參數 Context ,第二個參數:布局方向LinearLayout.VERTICAL垂直和LinearLayout.HORIZONTAL水平,
第三個參數:表示是否從最后的Item數據開始顯示,ture表示是,false就是正常顯示—從開頭顯示。
setItemAnimator()方法的作用是設置當前RecyclerView容器有子Item改變時(添加item或者刪除item)導致
整個布局的動畫效果。一般我們new 一個系統默認的動畫出來就好了。
RecyclerView適配器
既然RecyclerView是一個容器控件,那么里面總的裝載內容吧,也就是的有一個自己的適配器。來看看適配器怎么
實現的吧!
/**
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.MyViewHolder> {
private Context context;
private List<ModelBean> list;
private Resources res;
public RecyclerAdapter(Context context, List<ModelBean> list) {
this.context = context;
this.list = list;
res = context.getResources();
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.item_card_view, parent, false);
return new MyViewHolder(view);
}
@Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
final ModelBean bean = list.get(position);
holder.title.setText(bean.getTitle());
holder.imageView.setImageResource(bean.getResId());
}
@Override
public int getItemCount() {
return null == list ? 0 : list.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
private ImageView imageView;
private TextView title;
public MyViewHolder(View view) {
super(view);
imageView = (ImageView) view.findViewById(R.id.pic);
title = (TextView) view.findViewById(R.id.name);
}
}
}</pre>
看到嘛?我們是繼承RecyclerView.Adapter類,實現里面的抽象方法即可。可以看到RecyclerView.Adapter適配
器里面有一套完整的機制來控制之ItemView的查找和顯示。通過內部類MyViewHolder繼承
RecyclerView.ViewHolder封裝容器中的ItemView,實現onCreateViewHolder抽象方法來加載ItemView的布
局,實現onBindViewHolder抽象方法來綁定容器中的ItemView,進而進行賦值。
ItemView點擊事件
細心的你會發現,很遺憾的是RecyclerView沒有提供setItemOnClickListener點擊監聽方法。那么我們要監聽每個
ItemView的點擊事件怎么辦呢?沒關系!我們來看看代碼中怎么實現吧!
@Override public void onBindViewHolder(final MyViewHolder holder, final int position) { final ModelBean bean = list.get(position); holder.title.setText(bean.getTitle()); holder.imageView.setImageResource(bean.getResId());/**
* 調用接口回調 */ holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (null != listener) listener.onItemClick(position, bean); } }); }
/**
* 內部接口回調方法 */ public interface OnItemClickListener { void onItemClick(int position, Object object); } /** * 設置監聽方法 * * @param listener */ public void setOnItemClickListener(OnItemClickListener listener) { this.listener = listener; }</pre><br />
在RecyclerView的適配器類中定義了一個OnItemClickListener接口,然后在onBindViewHolder方法中設置每個holder.itemView的點擊事件,外面調用setOnItemClickListener方法即可
adapter.setOnItemClickListener(new RecyclerAdapter.OnItemClickListener() { @Override public void onItemClick(int position, Object object) { Toast.makeText(MainActivity.this, ((ModelBean) object).getTitle(), Toast.LENGTH_SHORT).show(); } });
RecyclerView添加,刪除,更新數據
和ListView,GridView容器不一樣的是,RecyclerView容器更新數據的方法有很多,不信你看:
如果你在代碼里設置了RecyclerView的ItemView改變時有動畫效果的話
recylerView.setItemAnimator(new DefaultItemAnimator());在RecyclerView適配器更新數據的時候就會有系統默認的動畫效果,童鞋們可以根據下面提供的源碼看效果。
RecyclerView控件使用基本就
是以上內容,最后我會提供一個RecyclerView,CardView,Palette一起使用的源碼例子,接著往下看吧騷年!
CardView控件
CardView稱之為卡片,也是Android5.0推出來的 Support v7包里的widget,CardView是繼承自FrameLayout。
從XML中看它是怎么使用的
<android.support.v7.widget.CardView xmlns:android="<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <ImageView android:id="@+id/pic" android:layout_width="match_parent" android:layout_height="0dp" android:layout_centerInParent="true" android:layout_weight="3" android:scaleType="fitXY" android:src="@drawable/img1" /> <TextView android:id="@+id/name" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:clickable="true" android:gravity="center" android:padding="5dp" android:text="圖片描述" android:textColor="@android:color/black" android:textSize="16sp" /> </LinearLayout>
</android.support.v7.widget.CardView></pre>
在使用CardView的時候需要引入屬性命名空間,也就是加入以下代碼xmlns:card="http://schemas.android.com/apk/res-auto"
和自定義控件一樣,引入命名空間是為了使用CardView的屬性值,名字“card”可以任意。來看看CardView有哪
些常用的屬性吧!
CardView只需要在XML布局文件里配置各種參數,代碼中無需任何操作。其實CardView就是一個FrameLayout容器控件,只是添加了一些屬性而已,使用很簡單,只要掌握以上四種屬性配置即可。
Palette
Palette類也是Android5.0引進來的一個獲取Bitmap顏色值的一個類。google為了兼容前面的版本也把這個類放在
了Support v7 Library包里,需要使用該類可以在項目中引進
compile 'com.android.support:palette-v7:22.2.0'
我們從代碼中來看看它是怎么使用的//異步獲得bitmap圖片顏色值 Palette.from(bitmap).generate(new Palette.PaletteAsyncListener() { @Override public void onGenerated(Palette palette) { Palette.Swatch vibrant = palette.getVibrantSwatch();//有活力if (vibrant != null) { holder.title.setBackgroundColor( vibrant.getRgb()); holder.title.setTextColor( vibrant.getTitleTextColor()); } } });</pre><br />
由于在Android設備中,對圖像的處理有可能是耗時操作,因此,Palette類通過異步接口onGenerated回調的方法
來獲得Bitmap的顏色值。Palette類獲得的顏色值有以下幾種類型:
我們從以上顏色中可以獲取到如下顏色值:
綜合例子
通過以上的了解,這里提供一個綜合的例子來看看RecyclerView,CardView,Palette結合的使用。以后給出
MainActivity和Adapter的實現
package com.xjp.androidmddemo.activity;import android.os.Bundle; import android.support.v7.app.AppCompatActivity; 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.support.v7.widget.Toolbar; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.LinearLayout; import android.widget.Spinner; import android.widget.TextView; import android.widget.Toast;
import com.xjp.androidmddemo.R; import com.xjp.androidmddemo.activity.adapter.RecyclerAdapter; import com.xjp.androidmddemo.activity.model.ModelBean;
import java.util.ArrayList; import java.util.List;
public class MainActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener, View.OnClickListener {
protected Toolbar toolbar; protected TextView title; protected Spinner spinner; protected Button add; private RecyclerView recylerView; private List<ModelBean> beanList; private RecyclerAdapter adapter; private String des[] = {"云層里的陽光", "好美的海灘", "好美的海灘", "夕陽西下的美景", "夕陽西下的美景" , "夕陽西下的美景", "夕陽西下的美景", "夕陽西下的美景", "好美的海灘"}; private int resId[] = {R.drawable.img1, R.drawable.img2, R.drawable.img2, R.drawable.img3, R.drawable.img4, R.drawable.img5, R.drawable.img3, R.drawable.img1}; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initViews(); initData(); initSpinner(); } private void initSpinner() { String categorys[] = this.getResources().getStringArray(R.array.categorys); ArrayAdapter adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, categorys); // 為adapter設置下拉菜單樣式 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); // spinner設置adapter spinner.setAdapter(adapter); spinner.setOnItemSelectedListener(this); } private void initViews() { toolbar = findView(R.id.toolbar); if (null != toolbar) { setSupportActionBar(toolbar); title = findView(R.id.toolbar_title); spinner = findView(R.id.toolbar_category); add = findView(R.id.button_add); if (null != title) { title.setText(getTitle()); } } add.setOnClickListener(this); recylerView = findView(R.id.recyclerview); //設置布局顯示方式 recylerView.setLayoutManager(new LinearLayoutManager(this, LinearLayout.VERTICAL, true)); //設置添加刪除item時候的動畫 recylerView.setItemAnimator(new DefaultItemAnimator()); } private void initData() { beanList = new ArrayList<>(); for (int i = 0; i < 8; i++) { ModelBean bean = new ModelBean(); bean.setResId(resId[i]); bean.setTitle(des[i]); beanList.add(bean); } adapter = new RecyclerAdapter(this, beanList); recylerView.setAdapter(adapter); adapter.setOnItemClickListener(new RecyclerAdapter.OnItemClickListener() { @Override public void onItemClick(int position, Object object) { Toast.makeText(MainActivity.this, ((ModelBean) object).getTitle(), Toast.LENGTH_SHORT).show(); } }); } @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { switch (position) { case 0: recylerView.setLayoutManager(new LinearLayoutManager(this, LinearLayout.VERTICAL, true)); break; case 1: recylerView.setLayoutManager(new LinearLayoutManager(this, LinearLayout.HORIZONTAL, true)); break; case 2: recylerView.setLayoutManager(new GridLayoutManager(this, 2)); break; case 3: recylerView.setLayoutManager(new GridLayoutManager(this, 2, LinearLayout.HORIZONTAL, true)); break; case 4: recylerView.setLayoutManager(new StaggeredGridLayoutManager(2, LinearLayout.VERTICAL)); break; } } @Override public void onNothingSelected(AdapterView<?> parent) { } @Override public void onClick(View v) { ModelBean bean = new ModelBean(); bean.setTitle("這是新添加的"); bean.setResId(R.drawable.img5); beanList.add(0, bean); // adapter.notifyDataSetChanged();//更新全部數據 // adapter.notifyItemInserted(0);//在 // adapter.notifyItemRemoved(0); // adapter.notifyItemChanged(0); // adapter.notifyItemMoved(0,1); // adapter.notifyItemRangeChanged(0,2); // adapter.notifyItemRangeInserted(0,2); // adapter.notifyItemRangeRemoved(0,2); } protected <T extends View> T findView(int id) { return (T) findViewById(id); }
}
............................
package com.xjp.androidmddemo.activity.adapter;
import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.support.v7.graphics.Palette; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView;
import com.xjp.androidmddemo.R; import com.xjp.androidmddemo.activity.model.ModelBean;
import java.util.List;
/**
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.MyViewHolder> {
private Context context; private List<ModelBean> list; private Resources res; private OnItemClickListener listener; public RecyclerAdapter(Context context, List<ModelBean> list) { this.context = context; this.list = list; res = context.getResources(); } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(context).inflate(R.layout.item_card_view, parent, false); return new MyViewHolder(view); } @Override public void onBindViewHolder(final MyViewHolder holder, final int position) { final ModelBean bean = list.get(position); holder.title.setText(bean.getTitle()); holder.imageView.setImageResource(bean.getResId()); Bitmap bitmap = BitmapFactory.decodeResource(res, bean.getResId()); //異步獲得bitmap圖片顏色值 Palette.from(bitmap).generate(new Palette.PaletteAsyncListener() { @Override public void onGenerated(Palette palette) { Palette.Swatch vibrant = palette.getVibrantSwatch();//有活力 Palette.Swatch c = palette.getDarkVibrantSwatch();//有活力 暗色 Palette.Swatch d = palette.getLightVibrantSwatch();//有活力 亮色 Palette.Swatch f = palette.getMutedSwatch();//柔和 Palette.Swatch a = palette.getDarkMutedSwatch();//柔和 暗色 Palette.Swatch b = palette.getLightMutedSwatch();//柔和 亮色 if (vibrant != null) { int color1 = vibrant.getBodyTextColor();//內容顏色 int color2 = vibrant.getTitleTextColor();//標題顏色 int color3 = vibrant.getRgb();//rgb顏色 holder.title.setBackgroundColor( vibrant.getRgb()); holder.title.setTextColor( vibrant.getTitleTextColor()); } } }); /** * 調用接口回調 */ holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (null != listener) listener.onItemClick(position, bean); } }); } @Override public int getItemCount() { return null == list ? 0 : list.size(); } public class MyViewHolder extends RecyclerView.ViewHolder { private ImageView imageView; private TextView title; public MyViewHolder(View view) { super(view); imageView = (ImageView) view.findViewById(R.id.pic); title = (TextView) view.findViewById(R.id.name); } } /** * 內部接口回調方法 */ public interface OnItemClickListener { void onItemClick(int position, Object object); } /** * 設置監聽方法 * * @param listener */ public void setOnItemClickListener(OnItemClickListener listener) { this.listener = listener; }
}</pre>
源碼地址 Demo源碼例子
來自:http://blog.csdn.net/feiduclear_up/article/details/46439005