Android5.x 新控件之RecyclerView,CardView,Palette的使用

pdce 9年前

自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 布局管理参数。参数类型可以有以下几种:

  1. LinearLayoutManager:线性布局
  2. GridLayoutManager:网格布局
  3. StaggeredGridLayoutManager:流式布局

那么怎么new一个LayoutManager出来呢?举个例子:

new LinearLayoutManager(this, LinearLayout.VERTICAL, true)

第一个参数 Context ,第二个参数:布局方向LinearLayout.VERTICAL垂直和LinearLayout.HORIZONTAL水平,

第三个参数:表示是否从最后的Item数据开始显示,ture表示是,false就是正常显示—从开头显示。

setItemAnimator()方法的作用是设置当前RecyclerView容器有子Item改变时(添加item或者删除item)导致

整个布局的动画效果。一般我们new 一个系统默认的动画出来就好了。

RecyclerView适配器

既然RecyclerView是一个容器控件,那么里面总的装载内容吧,也就是的有一个自己的适配器。来看看适配器怎么

实现的吧!

/**   * Description:RecyclerView 适配器   * User: xjp   * Date: 2015/6/8   * Time: 10:15   */    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);          }      }  }

看到嘛?我们是继承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;      }

在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容器更新数据的方法有很多,不信你看:

  1. notifyDataSetChanged():更新所有数据
  2. notifyItemInserted(int position):在position位置插入数据的时候更新
  3. notifyItemRemoved(int position):移除postion位置的数据的时候更新
  4. notifyItemChanged(int position):当postion位置数据有改变时候更新
  5. notifyItemMoved(int fromPosition, int toPosition):移除从位置formPosition到toPosition位置数据更新
  6. notifyItemRangeChanged(int positionStart, int itemCount)
  7. notifyItemRangeInserted(int positionStart, int itemCount)
  8. notifyItemRangeRemoved(int positionStart, int itemCount)

如果你在代码里设置了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="http://schemas.android.com/apk/res/android"      xmlns:card="http://schemas.android.com/apk/res-auto"      android:layout_width="160dp"      android:layout_height="200dp"      android:layout_gravity="center"      card:cardBackgroundColor="@android:color/white"      card:cardCornerRadius="0dp"      card:cardElevation="2dp"      card:cardMaxElevation="@dimen/cardview_default_elevation">      <!--cardMaxElevation:最大卡片阴影的宽度-->      <!--cardElevation:卡片阴影的宽度-->      <!--cardBackgroundColor:卡片的背景颜色-->      <!--cardCornerRadius :卡片的圆角半径-->        <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>

在使用CardView的时候需要引入属性命名空间,也就是加入以下代码
xmlns:card="http://schemas.android.com/apk/res-auto"

和自定义控件一样,引入命名空间是为了使用CardView的属性值,名字“card”可以任意。来看看CardView有哪

些常用的属性吧!

  1. cardElevation:卡片阴影的宽度
  2. cardMaxElevation:最大卡片阴影的宽度
  3. cardBackgroundColor:卡片的背景颜色
  4. cardCornerRadius :卡片的圆角半径

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());                  }              }          });

由于在Android设备中,对图像的处理有可能是耗时操作,因此,Palette类通过异步接口onGenerated回调的方法

来获得Bitmap的颜色值。Palette类获得的颜色值有以下几种类型:

  1. Palette.Swatch a = palette.getVibrantSwatch();//有活力
  2. Palette.Swatch b = palette.getDarkVibrantSwatch();//有活力 暗色
  3. Palette.Swatch c = palette.getLightVibrantSwatch();//有活力 亮色
  4. Palette.Swatch d = palette.getMutedSwatch();//柔和
  5. Palette.Swatch e = palette.getDarkMutedSwatch();//柔和 暗色
  6. Palette.Swatch f = palette.getLightMutedSwatch();//柔和 亮色

我们从以上颜色中可以获取到如下颜色值:

  1. int color1 = a.getBodyTextColor();//内容颜色
  2. int color2 = a.getTitleTextColor();//标题颜色
  3. int color3 = a.getRgb();//rgb颜色

综合例子

通过以上的了解,这里提供一个综合的例子来看看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;    /**   * Description:RecyclerView 适配器   * User: xjp   * Date: 2015/6/8   * Time: 10:15   */    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;      }    }

源码地址 Demo源码例子

来自:http://blog.csdn.net/feiduclear_up/article/details/46439005