RecycleView簡單的萬能擴充卡
- RecyclerView的萬能擴充卡
-
- 界面效果
- 代碼
- 源碼位址
RecyclerView的萬能擴充卡
相信每次用到RecyclerView大多人都會寫一次擴充卡,發現十分的麻煩,是以我就去找了幾篇文章,發現一個簡單的萬能擴充卡,是要寫一次擴充卡就夠了,而且還添加了點選跟長按事件,代碼比較簡單易懂,是以分享給大家。文章出處:http://www.cnblogs.com/liushilin/p/5720926.html
界面效果
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());方法也是一樣的,效果如下:
源碼位址
github提取:https://github.com/nanchen2251/CommonAdapterRecyclerDemo