天天看點

RecycleView簡單的萬能擴充卡RecyclerView的萬能擴充卡

RecycleView簡單的萬能擴充卡

  • RecyclerView的萬能擴充卡
    • 界面效果
    • 代碼
    • 源碼位址

RecyclerView的萬能擴充卡

相信每次用到RecyclerView大多人都會寫一次擴充卡,發現十分的麻煩,是以我就去找了幾篇文章,發現一個簡單的萬能擴充卡,是要寫一次擴充卡就夠了,而且還添加了點選跟長按事件,代碼比較簡單易懂,是以分享給大家。文章出處:http://www.cnblogs.com/liushilin/p/5720926.html

界面效果

RecycleView簡單的萬能擴充卡RecyclerView的萬能擴充卡

RecyclerView萬能擴充卡的簡單構造思路:

多半還是和構造ListView的萬能擴充卡差不多,畢竟RecyclerView就是為了替代它們出現的,隻是RecyclerView封裝了ViewHolder而已,而我們要實作把ViewHolder和Adaper封裝成一個萬能的擴充卡,我們肯定還是得像上篇提到的利用每個view獨一無二的id進行鍵值映射來做處理,當然我們還是用現在官方推薦的SparseArray,這個東西在能替代HashMap的時候真的好用,性能的優化就不用多說了。

代碼

先看看核心代碼:

我們封裝了ViewHolder,為了把設定值等都封裝進去,我們對外提供了set方法。通過一個getView來實作之前類似于ViewHolder的設定标簽的效果。如果已經綁定,則直接傳回,否則放到SparseArray中。

下面是ViewHolder的基本封裝。如果你有之前ListView的ViewHolder的封裝,這個看起來我相信很好了解。

package com.example.nanchen.commonadaperrecyclerdemo;

import android.content.Context;
import android.graphics.Bitmap;
import android.support.v7.widget.RecyclerView;
import android.util.SparseArray;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

import com.squareup.picasso.Picasso;

/**
 * 萬能的RecyclerView的ViewHolder
 * Created by 南塵 on 16-7-30.
 */
public class BaseRecyclerHolder extends RecyclerView.ViewHolder {

    private SparseArray<View> views;
    private Context context;

    private BaseRecyclerHolder(Context context,View itemView) {
        super(itemView);
        this.context = context;
        //指定一個初始為8
        views = new SparseArray<>(8);
    }

    /**
     * 取得一個RecyclerHolder對象
     * @param context 上下文
     * @param itemView 子項
     * @return 傳回一個RecyclerHolder對象
     */
    public static BaseRecyclerHolder getRecyclerHolder(Context context,View itemView){
        return new BaseRecyclerHolder(context,itemView);
    }

    public SparseArray<View> getViews(){
        return this.views;
    }

    /**
     * 通過view的id擷取對應的控件,如果沒有則加入views中
     * @param viewId 控件的id
     * @return 傳回一個控件
     */
    @SuppressWarnings("unchecked")
    public <T extends View> T getView(int viewId){
        View view = views.get(viewId);
        if (view == null ){
            view = itemView.findViewById(viewId);
            views.put(viewId,view);
        }
        return (T) view;
    }

    /**
     * 設定字元串
     */
    public BaseRecyclerHolder setText(int viewId,String text){
        TextView tv = getView(viewId);
        tv.setText(text);
        return this;
    }

    /**
     * 設定圖檔
     */
    public BaseRecyclerHolder setImageResource(int viewId,int drawableId){
        ImageView iv = getView(viewId);
        iv.setImageResource(drawableId);
        return this;
    }

    /**
     * 設定圖檔
     */
    public BaseRecyclerHolder setImageBitmap(int viewId, Bitmap bitmap){
        ImageView iv = getView(viewId);
        iv.setImageBitmap(bitmap);
        return this;
    }

    /**
     * 設定圖檔
     */
    public BaseRecyclerHolder setImageByUrl(int viewId,String url){
        Picasso.with(context).load(url).into((ImageView) getView(viewId));
        //        ImageLoader.getInstance().init(ImageLoaderConfiguration.createDefault(context));
        //        ImageLoader.getInstance().displayImage(url, (ImageView) getView(viewId));
        return this;
    }
}
           

然後是Recycler的Adapter,由于RecyclerView的Adapter必須繼承自RecyclerView.Adapter,并且指定我們寫的ViewHolder為泛型,為了達到萬能的效果,我們把需要傳入的Java Bean屬性直接用一個泛型T指代。

下面這些值得你注意:

1)RecyclerView沒有提供Item的點選事件,是以我們需要自己自定義,建議實作在Adapter中,因為adapter裡面會用到ViewHolder,這樣有助用我們寫每一項的點選事件。

2)RecyclerView不僅支援全局重新整理,而且支援局部重新整理,是以我們建議把添加和删除的方法直接寫在Adapter中。

3)我們為了達到萬能的效果,是以我們把設定holder的方法作為一個抽象方法,方面我們通過viewId傳值到相應的控件中,把整個Adapter變成一個抽象方法,這樣在子類中就可以去通過強制實作的方式把我們的資料填充進去。

還是直接看源碼吧。

package com.example.nanchen.commonadaperrecyclerdemo;

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

import java.util.List;

/**
 * 萬能的RecyclerView擴充卡
 * Created by 南塵 on 16-7-30.
 */
public abstract class BaseRecyclerAdapter<T> extends RecyclerView.Adapter<BaseRecyclerHolder> {

    private Context context;//上下文
    private List<T> list;//資料源
    private LayoutInflater inflater;//布局器
    private int itemLayoutId;//布局id
    private boolean isScrolling;//是否在滾動
    private OnItemClickListener listener;//點選事件監聽器
    private OnItemLongClickListener longClickListener;//長按監聽器
    private RecyclerView recyclerView;

    //在RecyclerView提供資料的時候調用
    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
        this.recyclerView = recyclerView;
    }

    @Override
    public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
        super.onDetachedFromRecyclerView(recyclerView);
        this.recyclerView = null;
    }

    /**
     * 定義一個點選事件接口回調
     */
    public interface OnItemClickListener {
        void onItemClick(RecyclerView parent, View view, int position);
    }

    public interface OnItemLongClickListener {
        boolean onItemLongClick(RecyclerView parent, View view, int position);
    }

    /**
     * 插入一項
     *
     * @param item
     * @param position
     */
    public void insert(T item, int position) {
        list.add(position, item);
        notifyItemInserted(position);
    }

    /**
     * 删除一項
     *
     * @param position 删除位置
     */
    public void delete(int position) {
        list.remove(position);
        notifyItemRemoved(position);
    }

    public BaseRecyclerAdapter(Context context, List<T> list, int itemLayoutId) {
        this.context = context;
        this.list = list;
        this.itemLayoutId = itemLayoutId;
        inflater = LayoutInflater.from(context);

        //        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
        //            @Override
        //            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
        //                super.onScrollStateChanged(recyclerView, newState);
        //                isScrolling = !(newState == RecyclerView.SCROLL_STATE_IDLE);
        //                if (!isScrolling) {
        //                    notifyDataSetChanged();
        //                }
        //            }
        //        });
    }

    @Override
    public BaseRecyclerHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = inflater.inflate(itemLayoutId, parent, false);
        return BaseRecyclerHolder.getRecyclerHolder(context, view);
    }

    @Override
    public void onBindViewHolder(final BaseRecyclerHolder holder, int position) {

        if (listener != null){
            holder.itemView.setBackgroundResource(R.drawable.recycler_bg);//設定背景
        }
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (listener != null && view != null && recyclerView != null) {
                    int position = recyclerView.getChildAdapterPosition(view);
                    listener.onItemClick(recyclerView, view, position);
                }
            }
        });


        holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View view) {
                if (longClickListener != null && view != null && recyclerView != null) {
                    int position = recyclerView.getChildAdapterPosition(view);
                    longClickListener.onItemLongClick(recyclerView, view, position);
                    return true;
                }
                return false;
            }
        });

        convert(holder, list.get(position), position, isScrolling);

    }

    @Override
    public int getItemCount() {
        return list == null ? 0 : list.size();
    }

    public void setOnItemClickListener(OnItemClickListener listener) {
        this.listener = listener;
    }

    public void setOnItemLongClickListener(OnItemLongClickListener longClickListener) {
        this.longClickListener = longClickListener;
    }

    /**
     * 填充RecyclerView擴充卡的方法,子類需要重寫
     *
     * @param holder      ViewHolder
     * @param item        子項
     * @param position    位置
     * @param isScrolling 是否在滑動
     */
    public abstract void convert(BaseRecyclerHolder holder, T item, int position, boolean isScrolling);
}
           

實體類get、set方法Data.java:

public class Data {

    private String text;
    private String text2;
    private int imageId;
    private String imageUrl;

    public Data(String text) {
        this.text=text;
    }
    public Data(String text, String text2, int imageId) {
        this.text = text;
        this.text2=text2;
        this.imageId = imageId;
    }

    public Data(String text, String text2, String imageUrl) {
        this.imageUrl = imageUrl;
        this.text = text;
        this.text2=text2;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public String getText2() {
        return text2;
    }

    public void setText2(String text2) {
        this.text2 = text2;
    }

    public int getImageId() {
        return imageId;
    }

    public void setImageId(int imageId) {
        this.imageId = imageId;
    }

    public String getImageUrl() {
        return imageUrl;
    }

    public void setImageUrl(String imageUrl) {
        this.imageUrl = imageUrl;
    }
}

           

在首頁面中調用:

package com.example.nanchen.commonadaperrecyclerdemo;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

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

public class MainActivity extends AppCompatActivity {

    private List<Data> list;
    private RecyclerView recyclerView;
    private BaseRecyclerAdapter<Data> adapter;
    private EditText text;

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

        list = new ArrayList<>();

        initList();

        adapter = new BaseRecyclerAdapter<Data>(this,list,R.layout.list_item) {
            @Override
            public void convert(BaseRecyclerHolder holder, Data item, int position, boolean isScrolling) {
                holder.setText(R.id.item_text,item.getText());
                if (item.getImageUrl() != null){
                    holder.setImageByUrl(R.id.item_image,item.getImageUrl());
                }else {
                    holder.setImageResource(R.id.item_image,item.getImageId());
                }
            }

        };

        adapter.setOnItemClickListener(new BaseRecyclerAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(RecyclerView parent, final View view, int position) {
                Toast.makeText(MainActivity.this, String.format(Locale.CHINA,"你點選了第%d項,長按會删除!",position),Toast.LENGTH_SHORT).show();
            }
        });

        adapter.setOnItemLongClickListener(new BaseRecyclerAdapter.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(RecyclerView parent, View view, int position) {
                adapter.delete(position);
                return true;
            }
        });

        text = (EditText) findViewById(R.id.main_text);
        recyclerView = (RecyclerView) findViewById(R.id.main_recycler);
        recyclerView.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false));
        recyclerView.setAdapter(adapter);



    }

    public void initList(){
        for (int i = 0; i < 5; i++) {
            list.add(new Data("本地 "+i,R.mipmap.ic_launcher));
        }
        for (int i = 0; i < 5; i++) {
            list.add(new Data("網絡 "+i,"http://pic.cnblogs.com/face/845964/20160301162812.png"));
        }
    }

    public void btnClick(View view) {
        String string = text.getText().toString().trim();
        Data data = new Data(string,R.mipmap.ic_launcher);
//        list.add(list.size()/2,data);
        adapter.insert(data,list.size()/2);

        Toast.makeText(MainActivity.this,list.size()+"",Toast.LENGTH_SHORT).show();
    }
}

           

這樣就基本完成了,像不同的layout布局,隻要再建一個layout布局,替換擴充卡初始化中的布局,然後通過holder.getView(R.id.textView)就可以擷取到控件id,就可以設定,或者holder.setText(R.id.item_text, item.getText());方法也是一樣的,效果如下:

RecycleView簡單的萬能擴充卡RecyclerView的萬能擴充卡
RecycleView簡單的萬能擴充卡RecyclerView的萬能擴充卡

源碼位址

github提取:https://github.com/nanchen2251/CommonAdapterRecyclerDemo

繼續閱讀