RecyclerView、CardView实战

来源:互联网 发布:帝国时代3mac版本 编辑:程序博客网 时间:2024/05/01 20:16

本篇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!

欢迎留言指导交流!

1 0
原创粉丝点击