RecyclerView(一)最简单的recyclerview

RecyclerView相比listview有很多灵活性,可以完全取代listview。

RecyclerView is a more advanced and flexible version of ListView. This widget is a container for large sets of views that can be recycled and scrolled very efficiently.

最简单例子 Project: RecycleViewTest

先来看个最简单的例子,首先在项目的依赖库内加入recycleview的库。

activity的layout如下

<?xml version="1.0" encoding="utf-8"?>
<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"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.fish.recycleviewtest.MainActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycle_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"></android.support.v7.widget.RecyclerView>
</RelativeLayout>

recycleview的item的布局如下

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:background="#44ff0000"
    android:layout_height="wrap_content" >

    <TextView
        android:id="@+id/id_num"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:gravity="center"
        android:text="1" />
</FrameLayout>
MainActivity代码

package com.fish.recycleviewtest;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    private List<String> mDatas;
    private RecyclerView recyclerView;
    private FishAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        recyclerView = (RecyclerView) findViewById(R.id.recycle_view);
        initData();
        initRecycleView();
    }

    private void initRecycleView() {
        adapter = new FishAdapter(this);
        //必须指定adaoter
        recyclerView.setAdapter(adapter);
        //必须指定layoutmanager
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        adapter.setData(mDatas);
    }

    protected void initData() {
        mDatas = new ArrayList<String>();
        for (int i = 'A'; i < 'z'; i++) {
            mDatas.add("" + (char) i);
        }
    }
}

FishAdapter代码

package com.fish.recycleviewtest;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.ViewGroup;

import java.util.List;

/**
 * Created by fish on 16/6/4.
 */
public class FishAdapter extends RecyclerView.Adapter<FishViewHolder> {
    private List<String> data;
    private LayoutInflater inflater;

    public FishAdapter(Context context) {
        inflater = LayoutInflater.from(context);
    }

    @Override
    public FishViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        LogUtil.fish("onCreateViewHolder");
        FishViewHolder holder = new FishViewHolder(inflater.inflate(
                R.layout.item, parent, false));
        return holder;
    }

    @Override
    public void onBindViewHolder(FishViewHolder holder, int position) {
        LogUtil.fish("onBindViewHolder " + position);
        holder.tv.setText(data.get(position));
    }

    @Override
    public int getItemCount() {
        return data.size();
    }

    public void setData(List<String> pDatas) {
        data = pDatas;
    }
}

FishViewHolder代码

package com.fish.recycleviewtest;

import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.TextView;

public class FishViewHolder extends RecyclerView.ViewHolder {

    TextView tv;

    public FishViewHolder(View view) {
        super(view);
        tv = (TextView) view.findViewById(R.id.id_num);
    }
}

最简单的recycleview就这么诞生了,非常简单。效果如下


看看MainActivity的initRecycleView,为recycleview依次设置了adapter,layoutmanager,recycleview必须要设置adapter和layoutManager。adapter用来管理数据,layoutmanager用来管理各个item view的布局,比如布局成listview或者gridview或者瀑布流。

adapter内部的onCreateViewHolder负责为某个item创建viewholder(和listview里面的viewholder概念一样),在使用listview的时候我们经常还要getTag,setTag,这里系统帮我们做了,我们只要往里面放一个view,就得到了一个viewholder。

  FishViewHolder holder = new FishViewHolder(inflater.inflate(
                R.layout.item, parent, false));

如果没有设置adapter,会怎么样呢?

可以看下这个方法RecyclerView#dispatchLayout,这个方法会在layout过程中调用,如果发现没有adapter会报错No adapter attached; skipping layout

如果发现没有layoutManager会报错    No layout manager attached; skipping layout

   void dispatchLayout() {
        if (mAdapter == null) {
            Log.e(TAG, "No adapter attached; skipping layout");
            // leave the state in START
            return;
        }
        if (mLayout == null) {
            Log.e(TAG, "No layout manager attached; skipping layout");
            // leave the state in START
            return;
        }
        mState.mIsMeasuring = false;
        onEnterLayoutOrScroll();
        if (mState.mLayoutStep == State.STEP_START) {
            dispatchLayoutStep1();
            mLayout.setExactMeasureSpecsFrom(this);
            dispatchLayoutStep2();
        } else if (mAdapterHelper.hasUpdates() || mLayout.getWidth() != getWidth() ||
                mLayout.getHeight() != getHeight()) {
            // First 2 steps are done in onMeasure but looks like we have to run again due to
            // changed size.
            mLayout.setExactMeasureSpecsFrom(this);
            dispatchLayoutStep2();
        } else {
            // always make sure we sync them (to ensure mode is exact)
            mLayout.setExactMeasureSpecsFrom(this);
        }
        dispatchLayoutStep3();
        onExitLayoutOrScroll();
    }


TO BE SMART

上边的代码虽然没问题,但是我们完全可以写的更好一点,比如把和viewholder相关的东西都放到Viewholder里面去,而不是在adapter内部处理。再比如,把recycleview的设置layoutmanager放到adapter内部(onAttachedToRecyclerView方法)去。

修改之后的代码如下所示

adapter的代码

package com.fish.recycleviewtest;

import android.content.Context;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.ViewGroup;

import java.util.List;

/**
 * Created by fish on 16/6/4.
 */
public class FishAdapter extends RecyclerView.Adapter<FishViewHolder> {
    private List<String> data;

    public FishAdapter() {

    }

    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
        //必须指定layoutmanager
        recyclerView.setLayoutManager(new LinearLayoutManager(recyclerView.getContext()));
    }

    @Override
    public FishViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        LogUtil.fish("onCreateViewHolder");
        FishViewHolder holder = new FishViewHolder(parent);
        return holder;
    }

    @Override
    public void onBindViewHolder(FishViewHolder holder, int position) {
        LogUtil.fish("onBindViewHolder " + position);
        holder.bind(data.get(position));
    }

    @Override
    public int getItemCount() {
        return data.size();
    }

    public void setData(List<String> pDatas) {
        data = pDatas;
    }
}

viewholder的代码

package com.fish.recycleviewtest;

import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class FishViewHolder extends RecyclerView.ViewHolder {

    TextView tv;

    public FishViewHolder(ViewGroup parent) {
        super(LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false));
        tv = (TextView) itemView.findViewById(R.id.id_num);
    }

    public void bind(String s){
        tv.setText(s);
    }
}

这样看起来思路更清晰一点,   FishViewHolder负责所有和viewholder相关的操作,主要是一个创建一个bind,而adapter不直接操作viewholder。和recycleview初始化相关的操作放入adapter的onAttachedToRecyclerView内部,而不是放在activity里面

多种item project:FishRecycleViewMultiType

listview支持多种item,recyclerview同样支持,写起来很简单
写2个viewholder,然后把数据添加进去,就OK了,效果如下

package com.fish.fishrecycleviewmultitype;

import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.ViewGroup;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by fish on 16/6/4.
 */
public class MyAdapter extends RecyclerView.Adapter<FishViewHolder> {
    private List<FishData> data = new ArrayList<>();

    public static final int TYPE_TEXT = 1;
    public static final int TYPE_IMAGE = 2;

    public MyAdapter() {

    }

    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
        //必须指定layoutmanager
        recyclerView.setLayoutManager(new LinearLayoutManager(recyclerView.getContext()));
    }

    @Override
    public FishViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        LogUtil.fish("onCreateViewHolder");
        switch (viewType) {
            case TYPE_TEXT:
                return new TextViewHolder(parent);
            case TYPE_IMAGE:
                return new ImageViewHolder(parent);
        }
        return null;
    }

    @Override
    public void onBindViewHolder(FishViewHolder holder, int position) {
        holder.bind(data.get(position).data);
    }


    public void addData(int type, Object o) {
        data.add(new FishData(type, o));
    }

    @Override
    public int getItemCount() {
        return data.size();
    }

    @Override
    public int getItemViewType(int position) {
        return data.get(position).type;
    }

}

package com.fish.fishrecycleviewmultitype;

import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.TextView;

public class TextViewHolder extends FishViewHolder {

    TextView tv;

    public TextViewHolder(ViewGroup parent) {
        super(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_text, parent, false));
        tv = (TextView) itemView.findViewById(R.id.id_num);
    }


    @Override
    protected void bind(Object object) {
        String s = (String) object;
        tv.setText(s);
    }
}

package com.fish.fishrecycleviewmultitype;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

public class ImageViewHolder extends FishViewHolder {

    ImageView tv;
    Context context;
    public ImageViewHolder(ViewGroup parent) {
        super(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_image, parent, false));
        context = parent.getContext();
        tv = (ImageView) itemView.findViewById(R.id.image);
    }


    @Override
    protected void bind(Object object) {
        int drawableId = (int) object;
        tv.setImageDrawable(context.getDrawable(drawableId));
    }
}

item_image
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#44ff77">

    <ImageView
        android:id="@+id/image"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:gravity="center"
        android:text="1" />
</FrameLayout>
item_text
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:background="#44ff0000"
    android:layout_height="wrap_content" >

    <TextView
        android:id="@+id/id_num"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:gravity="center"
        android:text="1" />
</FrameLayout>

以后如果需要更多种类的布局,就再添加viewholder就可以 了






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值