关于RecyclerView你不能不知道的秘密

概述

关于RecyclerView的描述网络上已经很多了,这里不再继续深入探讨,本章主要方向为简化开发流程,每次使用rv的时候我都会想还得去写适配器这样既浪费时间也不方便快速开发和对问题的定位,便有了将适配器直接封装在控件中这样只需要每次使用自定义对应业务的rv即可把一些负责的业务逻辑独立出去,也可以简化开发流程提高效率。


RV万能适配器

我们先需要万能适配器来简化adapter的代码,万能适配器封装如下:

public abstract class CommonAdapter<T> extends RecyclerView.Adapter<RecyclerViewHolder> {

    /**
     * 获取上下文
     */
    protected Context context;

    /**
     * 数据源
     */
    protected List<T> dataArray;

    /**
     * 获取布局
     */
    protected LayoutInflater layoutInflater;

    /**
     * 绑定布局
     */
    private int layoutId;

    private RecyclerView recyclerView;

    private OnItemClickListener listener;//点击事件监听器
    private OnItemLongClickListener longClickListener;//长按监听器

    protected View rootView;

    /**
     * 构造方法
     *
     * @param context   上下文
     * @param dataArray 数据集
     * @param layoutId  布局id
     */
    public CommonAdapter(@NonNull Context context, List<T> dataArray, @LayoutRes int layoutId) {
        this.context = context;
        this.layoutInflater = LayoutInflater.from(context);
        this.layoutId = layoutId;
        if (dataArray == null) {
            this.dataArray = new ArrayList<>();
        } else {
            this.dataArray = dataArray;
        }
    }

    // 在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;
    }

    @Override
    public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        this.rootView = layoutInflater.inflate(layoutId, parent, false);
        return RecyclerViewHolder.getRecyclerHolder(context, this.rootView);
    }

    @SuppressLint("RecyclerView")
    @Override
    public void onBindViewHolder(RecyclerViewHolder holder, final int position) {
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (listener == null) return;
                if (v == null) return;
                if (recyclerView == null) return;
                listener.onItemClick(recyclerView, v, position);
            }
        });
        holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                if (longClickListener == null) return false;
                if (v == null) return false;
                if (recyclerView == null) return false;
                longClickListener.onItemLongClick(recyclerView, v, position);
                return true;
            }
        });

        convert(holder, dataArray.get(position), position);
    }

    /**
     * 公用的方法,用来处理对应的ListView的显示效果, 子类实现该方法即可
     *
     * @param holder   万能view操作对象
     * @param model    当前数据
     * @param position 当前下标
     */
    protected abstract void convert(RecyclerViewHolder holder, T model, int position);

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

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

    /**
     * 添加数据,如果初始化时未给适配器数据集则设定数据集
     * 如果数据集存在则先清除数据在将数据添加进去之后刷新
     */
    public void setData(List<T> dataArray) {
        this.dataArray.clear();
        this.dataArray.addAll(dataArray);
        this.notifyDataSetChanged();
    }

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

    /**
     * 定义一个点击事件接口回调
     */
    public interface OnItemClickListener {
        void onItemClick(RecyclerView parent, View view, int position);
    }

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

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

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

RecyclerViewHolder简化item调用

public class RecyclerViewHolder extends RecyclerView.ViewHolder {

    // 安卓提供的Map,map的key只能存放int型,比map效率要高
    // 缓存布局
    private SparseArray<View> viewArray;

    private Context context;

    public RecyclerViewHolder(Context context, View itemView) {
        super(itemView);
        this.context = context;
        // 指定一个初始为8
        this.viewArray = new SparseArray<>(8);
    }

    /**
     * 取得一个RecyclerHolder对象
     * @param context  上下文
     * @param itemView 子项
     * @return 返回一个RecyclerHolder对象
     */
    public static RecyclerViewHolder getRecyclerHolder(Context context, View itemView) {
        return new RecyclerViewHolder(context, itemView);
    }

    /**
     * 通过view的id获取对应的控件,如果没有则加入views中
     *
     * @param viewId 控件的id
     * @return 返回一个控件
     */
    @SuppressWarnings("unchecked")
    public <T extends View> T getView(int viewId) {
        View view = viewArray.get(viewId);
        if (view == null) {
            view = itemView.findViewById(viewId);
            viewArray.put(viewId, view);
        }
        return (T) view;
    }

    // -----------------------------------------------------------------

    /**
     * 设置text
     * @param viewId 布局id
     * @param text 需要修改布局的文本
     */
    public RecyclerViewHolder setText(@IdRes int viewId, String text) {
        TextView tv = this.getView(viewId);
        tv.setText(text);
        return this;
    }

    /**
     * 设置图片
     * @param viewId 布局id
     * @param resId 资源图片id
     */
    public RecyclerViewHolder setImageResource(@IdRes int viewId, @DrawableRes int resId) {
        ImageView view = this.getView(viewId);
        view.setImageResource(resId);
        return this;
    }

    /**
     * 设置图片按钮
     * @param viewId 布局id
     * @param resId 资源图片id
     */
    public RecyclerViewHolder setImageButtonResource(@IdRes int viewId, @DrawableRes int resId) {
        ImageButton view = this.getView(viewId);
        view.setImageResource(resId);
        return this;
    }

    /**
     * 设置文本控件字体大小
     * @param viewId 布局id
     * @param unit 所需的尺寸单位
     * @param size 以给定单位表示的所需大小
     */
    public RecyclerViewHolder setTextSize(@IdRes int viewId, int unit, float size) {
        TextView textView = this.getView(viewId);
        textView.setTextSize(unit, size);
        return this;
    }

    // 动态设置item宽高
    public RecyclerViewHolder setRootViewWidthHeight(int widthPx, int heightPx) {
        View view = itemView;
        ViewGroup.LayoutParams params = view.getLayoutParams();
        params.width = DensityUtil.dip2px(context, widthPx);
        params.height = DensityUtil.dip2px(context, heightPx);
        view.setLayoutParams(params);
        return this;
    }

    public RecyclerViewHolder setViewWidthHeight(@IdRes int viewId, int widthPx, int heightPx) {
        View view = this.getView(viewId);
        ViewGroup.LayoutParams params = view.getLayoutParams();
        params.width = DensityUtil.dip2px(context, widthPx);
        params.height = DensityUtil.dip2px(context, heightPx);
        view.setLayoutParams(params);
        return this;
    }

    // 设置item根布局BackgroundResource
    public RecyclerViewHolder setRootViewBackgroundResource(@DrawableRes int backgroundResId) {
        View view = itemView;
        view.setBackgroundResource(backgroundResId);
        return this;
    }

    // 设置item根布局Background
    public RecyclerViewHolder setRootViewBackground(Drawable backgroundDrawable) {
        View view = itemView;
        view.setBackground(backgroundDrawable);
        return this;
    }

    @SuppressLint("ResourceType")
    public RecyclerViewHolder setRootViewBackgroundColor(@ColorInt int color) {
        View view = itemView;
        view.setBackgroundColor(ContextCompat.getColor(context, color));
        return this;
    }

    /**
     * 设置Bitmap图片
     * @param viewId 布局id
     * @param bitmap 要设置的Bitmap
     */
    public RecyclerViewHolder setImageBitmap(@IdRes int viewId, Bitmap bitmap) {
        ImageView view = this.getView(viewId);
        view.setImageBitmap(bitmap);
        return this;
    }

    /**
     * 设置Vie是否显示或隐藏
     * @param viewId 布局id
     * @param isVisible 是否显示控件,false:隐藏
     */
    public RecyclerViewHolder setVisible(@IdRes int viewId, boolean isVisible) {
        View view = this.getView(viewId);
        view.setVisibility(isVisible ? View.VISIBLE : View.GONE);
        return this;
    }

    /**
     * 设置文本颜色
     * @param viewId 布局id
     * @param textColorRes 所需资源标识
     */
    public RecyclerViewHolder setTextColorRes(@IdRes int viewId, @ColorRes int textColorRes) {
        TextView tv = this.getView(viewId);
        if (textColorRes != 0) {
            tv.setTextColor(ContextCompat.getColor(context, textColorRes));
        } else {
            tv.setTextColor(Color.rgb(0,0,0));
        }
        return this;
    }

    /**
     * 设置文本颜色
     * @param viewId 布局id
     * @param textColor 所需要的文字颜色
     */
    public RecyclerViewHolder setTextColor(@IdRes int viewId, @ColorInt int textColor) {
        TextView tv = getView(viewId);
        tv.setTextColor(textColor);
        return this;
    }

    /**
     * 设置背景颜色
     * @param viewId 布局id
     * @param color 资源id
     */
    public RecyclerViewHolder setBackgroundColor(@IdRes int viewId, @ColorInt int color) {
        View v = getView(viewId);
        v.setBackgroundColor(color);
        return this;
    }

    /**
     * 根据color.xml文件中的R.color来设置颜色
     * @param viewId 布局id
     * @param backgroundResId 颜色id
     */
    public RecyclerViewHolder setBackgroundColorResId(@IdRes int viewId, @DrawableRes int backgroundResId) {
        View view = getView(viewId);
        view.setBackgroundResource(backgroundResId);
        return this;
    }

    /**
     * 设置文字链接
     */
    public RecyclerViewHolder setTextLink(int viewId) {
        TextView view = getView(viewId);
        Linkify.addLinks(view, Linkify.ALL);
        return this;
    }

    /**
     * 设置多个text字体
     */
    public RecyclerViewHolder setTextArrayTypeface(Typeface typeface, @IdRes int... viewIds) {
        for (int viewId : viewIds) {
            TextView view = getView(viewId);
            view.setTypeface(typeface);
            view.setPaintFlags(view.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG);
        }
        return this;
    }

    public RecyclerViewHolder setRating(@IdRes int viewId, float rating) {
        RatingBar view = getView(viewId);
        view.setRating(rating);
        return this;
    }

    public RecyclerViewHolder setProgress(int viewId, int progress) {
        ProgressBar view = getView(viewId);
        view.setProgress(progress);
        return this;
    }

    public RecyclerViewHolder setProgressBarMaxAndProgress(int viewId, int progress, int max) {
        ProgressBar view = getView(viewId);
        view.setMax(max);
        view.setProgress(progress);
        return this;
    }

    public RecyclerViewHolder setProgressBarMax(int viewId, int max) {
        ProgressBar view = getView(viewId);
        view.setMax(max);
        return this;
    }

    public RecyclerViewHolder setRatingBarMaxAndRating(int viewId, float rating, int max) {
        RatingBar view = getView(viewId);
        view.setMax(max);
        view.setRating(rating);
        return this;
    }

    public RecyclerViewHolder setTag(@IdRes int viewId, int position) {
        View v = getView(viewId);
        v.setTag(position);
        return this;
    }

    public RecyclerViewHolder setTag(@IdRes int controlId, Object obj) {
        View v = getView(controlId);
        v.setTag(obj);
        return this;
    }

    /**
     * 设置CheckBox是否选中
     */
    public void setCheckBoxChecked(@IdRes int viewId, boolean pd) {
        CheckBox cb = getView(viewId);
        cb.setChecked(pd);
    }

    // 关于事件
    public RecyclerViewHolder setRootViewOnClickListener(View.OnClickListener listener) {
        View view = itemView;
        view.setOnClickListener(listener);
        return this;
    }

    public RecyclerViewHolder setOnClickListener(@IdRes int viewId,
                                         View.OnClickListener listener) {
        View view = getView(viewId);
        view.setOnClickListener(listener);
        return this;
    }

    public RecyclerViewHolder setOnTouchListener(@IdRes int viewId,
                                         View.OnTouchListener listener) {
        View view = getView(viewId);
        view.setOnTouchListener(listener);
        return this;
    }

    public RecyclerViewHolder setOnLongClickListener(@IdRes int viewId,
                                             View.OnLongClickListener listener) {
        View view = getView(viewId);
        view.setOnLongClickListener(listener);
        return this;
    }
}

创建让抽象的适配器可以直接被使用而不是被继承的适配器,该类只有一个功能,给自定义view提供适配器

/**
 * 适配器的基础实现,提供通用的适配器功能
 * 警告:
 *  1.该类不适合直接继承实现,该类主要用途是和view绑定
 *  2.如果继承该类请重写convert()函数,或者实现ConvertInterface接口
 */
public final class CurrencyRVAdapter<T> extends CommonAdapter<T> {

    private ConvertInterface<T> convertInterface = null;

    public CurrencyRVAdapter(@NonNull Context context, int layoutId) {
        this(context, null, layoutId);
    }

    /**
     * 构造方法
     * @param context   上下文
     * @param dataArray 数据集
     * @param layoutId  布局id
     */
    public CurrencyRVAdapter(@NonNull Context context, List<T> dataArray, int layoutId) {
        super(context, dataArray, layoutId);
    }

    @Override
    protected void convert(RecyclerViewHolder holder, T model, int position) {
        if (this.convertInterface == null) return;
        this.convertInterface.adapterConvertHandle(holder, model, position);
    }

    public int getViewMeasuredWidth() {
        return this.rootView == null ? 0 : this.rootView.getMeasuredWidth();
    }
    public int getViewMeasuredHeight() {
        return this.rootView == null ? 0 : this.rootView.getMeasuredHeight();
    }

    // 设置调用接口
    public void setCallbackInterface(ConvertInterface<T> convertInterface) {
        this.convertInterface = convertInterface;
    }

    // 通过接口将具体实现传递出去
    public interface ConvertInterface<T> {
        // 主要用途是代理adapter中的convert函数的实现
        void adapterConvertHandle(RecyclerViewHolder holder, T model, int position);
    }
}

创建通用的RecyclerView

public abstract class AbstractRecyclerViewWidget<T> extends RecyclerView
        implements CurrencyRVAdapter.ConvertInterface<T> {

    // 适配器
    protected CurrencyRVAdapter<T> adapter = null;

    // 默认是列表布局
    private boolean isList = true;
    // 默认是垂直-列表才生效
    private boolean isVertical = true;
    // 表格布局行数
    private int spanCount = 0;
    // 布局id
    private int layoutId = 0;

    public AbstractRecyclerViewWidget(Context context) {
        this(context, null);
    }

    public AbstractRecyclerViewWidget(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    @SuppressLint("Recycle")
    public AbstractRecyclerViewWidget(Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.AbstractRecyclerViewWidget);
        if(typedArray == null) throw new NullPointerException("err={ 加载失败!!!}");
        this.layoutId = typedArray.getResourceId(R.styleable.AbstractRecyclerViewWidget_layout, 0);
        if (layoutId == 0) throw new NullPointerException("err={请检查布局layoutId属性是否设定!!!}");
        this.isList = typedArray.getBoolean(R.styleable.AbstractRecyclerViewWidget_isList, true);
        this.isVertical = typedArray.getBoolean(R.styleable.AbstractRecyclerViewWidget_isVertical, true);
        this.spanCount = typedArray.getInt(R.styleable.AbstractRecyclerViewWidget_spanCount, 0);
        // 用完要关闭回收资源,必须的强制性的
        typedArray.recycle();
        List<T> dataArray = this.initDataArray();
        this.initAdapter(context, layoutId, dataArray);
    }

    // 初始化数据集, 如果需要可复写
    protected List<T> initDataArray() {
        return null;
    }

    // 初始化LayoutManager
    protected RecyclerView.LayoutManager initLayoutManager() {
        return null;
    }

    // 销毁资源
    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (this.adapter != null) {
            this.adapter = null;
        }
    }

    /**
     * 初始化适配器
     */
    private void initAdapter(Context context, int layoutId, List<T> dataArray) {
        if (dataArray == null) {
            this.adapter = new CurrencyRVAdapter<T>(context, layoutId);
        } else {
            this.adapter = new CurrencyRVAdapter<T>(context, dataArray, layoutId);
        }
        this.adapter.setCallbackInterface(this);
        this.setLayoutStyle();
        setAdapter(this.adapter);
    }

    // 设置布局方式
    private void setLayoutStyle() {
        RecyclerView.LayoutManager layoutManager = null;
        // 如果是列表, 默认是VERTICAL
        if (isList) {
            int orientation = this.isVertical ? LinearLayoutManager.VERTICAL : LinearLayoutManager.HORIZONTAL;
            layoutManager = new LinearLayoutManager(getContext(), orientation,false);
        } else {
            layoutManager = new GridLayoutManager(getContext(), this.spanCount);
        }
        if (this.initLayoutManager() != null) {
            layoutManager = this.initLayoutManager();
        }
        this.setLayoutManager(layoutManager);
    }

    /** 刷新适配器 **/
    public void setData(List<T> dataArray) {
        if (this.adapter == null) {
            this.initAdapter(getContext(), layoutId, dataArray);
        } else {
            this.adapter.setData(dataArray);
        }
    }

    public int getViewMeasuredWidth() {
        return this.adapter.getViewMeasuredWidth();
    }
    public int getViewMeasuredHeight() {
        return this.adapter.getViewMeasuredHeight();
    }
    public int getItemCount() {
        return this.adapter.getItemCount();
    }
}
<!-- 自定义属性 -->
 <declare-styleable name="AbstractRecyclerViewWidget">
 		<!-- item布局文件 -->
        <attr name="layout" format="reference" />
        <!-- 默认就是List,如果为false,则是表格布局 -->
        <attr name="isList" format="boolean" />
        <attr name="isVertical" format="boolean" />
        <attr name="spanCount" format="integer" />
  </declare-styleable>

例子:

public class PageManagerRVWidget extends AbstractRecyclerViewWidget<Bitmap> {
public PageManagerRVWidget(Context context) {
        this(context, null);
    }

    public PageManagerRVWidget(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public PageManagerRVWidget(Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    protected List<Bitmap> initDataArray() {
        return null;
    }
    @Override
    public void adapterConvertHandle(RecyclerViewHolder holder, Bitmap model, int position) {
       // 具体对item操作的代码
    }
}
 ...
 <com.lenovo.whiteboard.view.PageManagerRVWidget
        android:id="@+id/page_manager_rv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        app:isList="false"
        app:layout="@layout/cus_item_page_manager"
        app:spanCount="3" />
 ...

总结

通过以上步骤即可将rv和适配器绑定在一起使用, 基本上可以将rv的布局放到内部使用,或者在自定义的rv中写通用函数给外部调用,怎么操作看各位自己的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值