該文章主要記錄,Rv中的多佈局使用。
目錄
1. 繼承自RecyclerView.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;
}
.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));
}
}