Android RecyclerView多佈局使用技巧

該文章主要記錄,Rv中的多佈局使用。

目錄

1. 繼承自RecyclerView.Adapter實現聊天多佈局

 SparseArray的學習及使用

2. 使用BRVAH Adapter幫助類實現多佈局 

1. 繼承自RecyclerView.Adapter實現聊天多佈局

實現該類多佈局,主要是重寫了getItemViewType,然後纔是根據不同的數據類型去返回各自相對應的Item子佈局。

而在onCreateViewHolder()中才是加載對應的itemType轉換爲對應的view即可。

 

/**
 * @author crazyZhangxl on 2019/1/15.
 * Describe: 多佈局實現聊天通信 純UI
 */
public class SessionAdapter extends RecyclerView.Adapter<OneViewHolder>{
    private Context mContext;
    private List<Message> mMessagesList;
    private static final int SEND_TEXT = R.layout.item_text_send;
    private static final int RECEIVE_TEXT = R.layout.item_text_receive;
    private static final int UNDEFINE_MSG = R.layout.item_no_support_msg_type;

    /**
     * 構造函數----
     * @param context
     * @param messagesList
     */
    public SessionAdapter(Context context, List<Message> messagesList) {
        mContext = context;
        mMessagesList = messagesList;
    }

    /**
     * 創建ViewHolder
     * @param viewGroup 父親組件
     * @param viewType  文本佈局資源文件[對應getItemViewType返回的類型]
     * @return
     */
    @NonNull
    @Override
    public OneViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
        return new OneViewHolder(LayoutInflater.from(mContext).inflate(viewType, viewGroup,false), mContext);
    }

    /**
     * 綁定ViewHolder設置初始化
     * @param viewHolder
     * @param position
     */
    @Override
    public void onBindViewHolder(@NonNull OneViewHolder viewHolder, int position) {
        // 設置時間
        setTime(viewHolder,position);
        setName(viewHolder,position);
        setContent(viewHolder,position);
    }

    private void setName(OneViewHolder viewHolder, int position) {
        TextView tvName =  viewHolder.mConvertView.findViewById(R.id.tvName);
        tvName.setText(mMessagesList.get(position).getSendName());
    }

    private void setContent(OneViewHolder viewHolder, int position) {
        Message message = mMessagesList.get(position);
        if (message instanceof TextMessage){
            TextView tvMessage =  viewHolder.mConvertView.findViewById(R.id.tvText);
            TextMessage textMessage = (TextMessage) mMessagesList.get(position);
            tvMessage.setText(textMessage.getTextInfo());
        }
    }

    private void setTime(OneViewHolder viewHolder, int position) {
        TextView tvTime = viewHolder.mConvertView.findViewById(R.id.tvTime);
        Message message = mMessagesList.get(position);
        long sendTime = message.getSendTime();
        if (position > 0){
            long preTime = mMessagesList.get(position - 1).getSendTime();
            if (sendTime - preTime > 5*60*1000){
                tvTime.setVisibility(View.VISIBLE);
                tvTime.setText(TimeUtils.getInstance().longToTime(sendTime));
            }else {
                tvTime.setVisibility(View.GONE);
            }
        }else {
            tvTime.setVisibility(View.VISIBLE);
            tvTime.setText(TimeUtils.getInstance().longToTime(sendTime));
        }
    }

    /**
     * 對應各種消息類型[多佈局的核心]
     * @param position 對應的下標position
     * @return
     */
    @Override
    public int getItemViewType(int position) {
        int viewType = UNDEFINE_MSG;
        Message message = mMessagesList.get(position);
        boolean isSend = message.getDirection() == MessageDirection.SEND.integerValue;
        switch (message.getMessageType()){
            case TEXT:
                viewType = isSend?SEND_TEXT:RECEIVE_TEXT;
                break;
            case IMAGE:
                break;
                default:
                    break;
        }
        return viewType;
    }

    @Override
    public int getItemCount() {
        if (mMessagesList == null){
            return 0;
        }
        return mMessagesList.size();
    }
}
/**
 * @author crazyZhangxl on 2019/1/15.
 * Describe: 基本的ViewHolder
 */
public class OneViewHolder extends RecyclerView.ViewHolder{
    protected View mConvertView;
    private Context mContext;

    public OneViewHolder(@NonNull View itemView) {
        super(itemView);
    }

    public OneViewHolder(@NonNull View itemView, Context context) {
        super(itemView);
        mConvertView = itemView;
        mContext = context;
    }

    public View getConvertView() {
        return mConvertView;
    }

    public void setConvertView(View convertView) {
        mConvertView = convertView;
    }

    public Context getContext() {
        return mContext;
    }

    public void setContext(Context context) {
        mContext = context;
    }
}

拓展內容

可以學習下優秀的人封裝的ViewHolder,特點是對View的操作更加簡潔了,而且封裝了item的各種操作事件處理。還有一個知識點是 SparseArray<Views>的學習以及使用,優化的緩存方案。

public class LQRViewHolder extends RecyclerView.ViewHolder {

    protected Context mContext;
    protected View mConvertView;
    protected SparseArray<View> mViews;
    protected int mMyPosition;//LQRViewHolderForAbsListView專用(另一個自帶getPosition方法)

    protected OnItemClickListener mOnItemClickListener;
    protected OnItemLongClickListener mOnItemLongClickListener;
    protected OnItemTouchListener mOnItemTouchListener;

    public LQRViewHolder(View itemView) {
        super(itemView);
    }

    /**
     * 根據id得到佈局中的View(使用SparseArray保管,提高效率)
     */
    public <T extends View> T getView(int viewId) {
        View view = mViews.get(viewId);
        if (view == null) {
            view = mConvertView.findViewById(viewId);
            mViews.put(viewId, view);
        }
        return (T) view;
    }


    /**
     * 得到當前item對應的View
     */
    public View getConvertView() {
        return mConvertView;
    }

    public int getMyPosition() {
        return mMyPosition;
    }

    public void setMyPosition(int myPosition) {
        mMyPosition = myPosition;
    }

    public OnItemClickListener getOnItemClickListener() {
        return mOnItemClickListener;
    }

    public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
        mOnItemClickListener = onItemClickListener;
    }

    public OnItemLongClickListener getOnItemLongClickListener() {
        return mOnItemLongClickListener;
    }

    public void setOnItemLongClickListener(OnItemLongClickListener onItemLongClickListener) {
        mOnItemLongClickListener = onItemLongClickListener;
    }

    public OnItemTouchListener getOnItemTouchListener() {
        return mOnItemTouchListener;
    }

    public void setOnItemTouchListener(OnItemTouchListener onItemTouchListener) {
        mOnItemTouchListener = onItemTouchListener;
    }

    /*================== 一切有可能的操作控件的方法 begin ==================*/

    /**
     * 設置TextView文字,並返回this
     */
    public LQRViewHolder setText(int viewId, String text) {
        TextView tv = getView(viewId);
        tv.setText(text);
        return this;
    }

    /**
     * 設置TextView的文字顏色,並返回this
     */
    public LQRViewHolder setTextColor(int viewId, int colorId) {
        TextView tv = getView(viewId);
        tv.setTextColor(mContext.getResources().getColor(colorId));
        return this;
    }

    /**
     * 設置ImageView的圖片,並返回this
     */
    public LQRViewHolder setImageResource(int viewId, int resId) {
        ImageView iv = getView(viewId);
        iv.setImageResource(resId);
        return this;
    }

    /**
     * 設置ImageView的圖片,並返回this
     */
    public LQRViewHolder setImageBitmap(int viewId, Bitmap bitmap) {
        ImageView iv = getView(viewId);
        iv.setImageBitmap(bitmap);
        return this;
    }

    /**
     * 設置ImageView的圖片,並返回this
     */
    public LQRViewHolder setImageFileResource(int viewId, String path) {
        ImageView iv = getView(viewId);
        Bitmap bitmap = BitmapFactory.decodeFile(path);
        iv.setImageBitmap(bitmap);
        return this;
    }

    /**
     * 設置背景顏色,並返回this
     */
    public LQRViewHolder setBackgroundColor(int viewId, int colorId) {
        View view = getView(viewId);
        view.setBackgroundColor(mContext.getResources().getColor(colorId));
        return this;
    }


    /**
     * 設置背景資源,並返回this
     */
    public LQRViewHolder setBackgrounResource(int viewId, int resId) {
        View view = getView(viewId);
        view.setBackgroundResource(resId);
        return this;
    }

    /**
     * 設置顯隱,並返回this
     */
    public LQRViewHolder setViewVisibility(int viewId, int visibility) {
        View view = getView(viewId);
        view.setVisibility(visibility);
        return this;
    }

    /**
     * 設置是否可用,並返回this
     */
    public LQRViewHolder setEnabled(int viewId, boolean enabled) {
        View view = getView(viewId);
        view.setEnabled(enabled);
        return this;
    }

    /**
     * 設置是否可獲取焦點,並返回this
     */
    public LQRViewHolder setFocusable(int viewId, boolean focusable) {
        View view = getView(viewId);
        view.setFocusable(focusable);
        return this;
    }

    /*================== 一切有可能操作控件的方法 end ==================*/

}

public class LQRViewHolderForRecyclerView extends LQRViewHolder {

    public LQRViewHolderForRecyclerView(Context context, View itemView) {
        super(itemView);
        mContext = context;
        mConvertView = itemView;
        mViews = new SparseArray<>();

        mConvertView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mOnItemClickListener != null) {
                    mOnItemClickListener.onItemClick(LQRViewHolderForRecyclerView.this, null, v, getPosition());
                }
            }
        });

        mConvertView.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                if (mOnItemLongClickListener != null) {
                    return mOnItemLongClickListener.onItemLongClick(LQRViewHolderForRecyclerView.this, null, v, getPosition());
                }
                return false;
            }
        });

        mConvertView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (mOnItemTouchListener != null) {
                    return mOnItemTouchListener.onItemTouch(LQRViewHolderForRecyclerView.this, v, event, getPosition());
                }
                return false;
            }
        });

    }
}

 SparseArray的學習及使用

 用途:當數據結構中key的類型是int時可用此結構來替代hashmap來進行優化

 特點:查找操作時使用的是二分法查找,時間複雜度時O(N);存儲採用的時數組,佔用的內存空間小

 HashMap是數組和鏈表的結合體,被稱爲鏈表散列.

 SparseArray是單純數組的結合.被稱爲稀疏數組,對數據保存的時候,不會有額外的開銷

 獲取以及設置的使用方式

    /**
     * 根據id得到佈局中的View(使用SparseArray保管,提高效率)
     */
    public <T extends View> T getView(int viewId) {
        View view = mViews.get(viewId);
        if (view == null) {
            view = mConvertView.findViewById(viewId);
            mViews.put(viewId, view);
        }
        return (T) view;
    }

Android學習筆記之性能優化SparseArray

Android常見優化方式-SparseArray

Android studio中.9圖片的含義及製作教程

.9圖的簡單製作,右邊3圖效果依次爲: 上下拉伸/左右拉伸/上下左右都拉伸的效果展示

2. 使用BRVAH Adapter幫助類實現多佈局 

    private void initData() {
        mMulCityBeanList.add(new MulCityBean("101","南京","12","晴"));
        mMulCityBeanList.add(new MulCityBean("101","北京","15","陰"));
        mMulCityBeanList.add(new MulCityBean("101","天津","18","小雨"));
        mMulCityBeanList.add(new MulCityBean());
    }

    private void initAdapter() {
        mCityRecyclerView.setLayoutManager(new GridLayoutManager(this,3));
        mMulCityAdapter = new MulCityAdapter(mMulCityBeanList,this);
        // 設置adapter
        mCityRecyclerView.setAdapter(mMulCityAdapter);
    }

核心數據bean,必須得實現MultiItemEntity

public class MulCityBean implements MultiItemEntity{
    /**
     * 具體城市信息
     */
    public static final int CITY = 1;
    /**
     * 添加的按鈕
     */
    public static final int ADD_SYMBOL = 2;

    /**
     * 用於返回給itemType的數值
     * 在構造方法中可進行初始化
     */
    private int itemType;

    // 對應的每個Item的具體數值
    public String cityId;
    // 就是江寧
    public String cityName;
    public String temp;
    public String weatherStatus;
    /**
     * 是否顯示刪除的按鈕
     */
    private boolean isShowDelete;
    /**
     * 是否顯示本地的城市
     */
    private boolean isNowCity;


    private boolean isChecked;

    public boolean isChecked() {
        return isChecked;
    }

    public void setChecked(boolean checked) {
        isChecked = checked;
    }

    public boolean isShowDelete() {
        return isShowDelete;
    }

    public void setShowDelete(boolean showDelete) {
        isShowDelete = showDelete;
    }

    public boolean isNowCity() {
        return isNowCity;
    }

    public void setNowCity(boolean nowCity) {
        isNowCity = nowCity;
    }

    /**
     * 無參數構造方法那麼默認該bean就是添加按鈕
     */
    public MulCityBean() {
        itemType = ADD_SYMBOL;
    }

    /**
     * 多慘構造方法即是城市的信息
     * @param cityId
     * @param cityName
     * @param temp
     * @param weatherStatus
     */
    public MulCityBean(String cityId, String cityName, String temp, String weatherStatus) {
        this.cityId = cityId;
        this.cityName = cityName;
        this.temp = temp;
        this.weatherStatus = weatherStatus;
        itemType = CITY;
    }

    @Override
    public int getItemType() {
        return itemType;
    }
}

adapter實現BaseMultiItemQuickAdapter ​​​​​​​

public class MulCityAdapter extends BaseMultiItemQuickAdapter<MulCityBean,BaseViewHolder>{
    private Context context;
    public static final int[] BLUR_IMAGE = {
            R.mipmap.ic_city_blur0,
            R.mipmap.ic_city_blur1,
            R.mipmap.ic_city_blur2,
            R.mipmap.ic_city_blur3,
            R.mipmap.ic_city_blur4,
            R.mipmap.ic_city_blur5};
    private Drawable mDrawableLocation;
    private ImageView mImageView;
    private TextView mTv_status;
    private ImageView mView_del;
    private View mView_hover;
    private TextView mText_city_name;
    private ImageView mMChecked;

    /**
     * Same as QuickAdapter#QuickAdapter(Context,int) but with
     * some initialization data.
     *
     * @param data A new list is created out of this one to avoid mutable list
     */
    public MulCityAdapter(List<MulCityBean> data,Context context) {
        super(data);
        // 對應類型綁定不同的佈局
        addItemType(MulCityBean.CITY, R.layout.item_city_followed_city);
        addItemType(MulCityBean.ADD_SYMBOL, R.layout.item_city_add_city);
        this.context = context;
        initDrawable();
    }

    /**
     * 初始化Drawable-----
     */
    private void initDrawable() {
        mDrawableLocation = ContextCompat.getDrawable(context,R.mipmap.ic_location);
        mDrawableLocation.setBounds(0,0,dpToPx(context,14),dpToPx(context,14));
    }

    @Override
    protected void convert(BaseViewHolder helper, MulCityBean item) {
        switch (helper.getItemViewType()){
            case MulCityBean.CITY:
                if (item == null){
                    return;
                }
                mImageView = helper.getView(R.id.image);
                mImageView.setImageResource(BLUR_IMAGE[helper.getAdapterPosition()% BLUR_IMAGE.length]);
                helper.setText(R.id.city_temp,item.temp);
                mText_city_name = helper.getView(R.id.city_name);
                mText_city_name.setText(item.cityName);

                mTv_status = helper.getView(R.id.city_status);
                mTv_status.setText(item.weatherStatus);
                mView_del = helper.getView(R.id.delete);
                helper.addOnClickListener(R.id.delete);
                // 設置刪除按鈕的顯示
                mView_del.setVisibility(item.isShowDelete()?View.VISIBLE:View.GONE);

                // 設備陰影的顯示
                mView_hover = helper.getView(R.id.hover);
                mView_hover.setVisibility(item.isShowDelete()?View.VISIBLE : View.GONE);

                // 是否是當前
                mMChecked = helper.getView(R.id.checked);
                mMChecked.setVisibility(item.isChecked()?View.VISIBLE:View.GONE);
                break;
                case MulCityBean.ADD_SYMBOL:
                    break;
                    default:
                        break;
        }
    }

    private int dpToPx(Context context,int dp){
        if (context == null){
            return  0;
        }

        DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
        return (int) (displayMetrics.density*(dp+0.5f));
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章