您的位置:首页 > 其它

RecyclerView、CardView实战

2015-07-15 17:21 471 查看
本篇blog参照网上大神demo实现,效果一样http://frank-zhu.github.io/android/2015/02/26/android-recyclerview-part-3/

关键点:

- CardView的使用,CardView继承的是FrameLayout,所以摆放内部控件的时候需要注意一下;

- RecyclerView的简单使用,关键理解RecyclerView实现的思想,对比ListView学习;

- array配置文件读取

一、首先,引入依赖包,重新编译

[code]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的参数:

[code]<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布局文件:

[code]<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

[code]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中很简单

[code]  @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

[code] /**
     * 只显示文本的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();
                }
            });
        }
    }


[code] /**
     * 显示图像和文本的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呢,很简单

[code]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!

欢迎留言指导交流!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: