<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                [TOC] # 優化Adapter代碼 item view 如下: ![](https://img.kancloud.cn/e3/0f/e30f75815309f19ac327897f07b67d9d_674x224.png) 代碼如下: ```java public class QuickAdapter extends BaseQuickAdapter<Status, BaseViewHolder> { public QuickAdapter() { super(R.layout.tweet, DataServer.getSampleData()); } @Override protected void convert(BaseViewHolder viewHolder, Status item) { viewHolder.setText(R.id.tweetName, item.getUserName()) .setText(R.id.tweetText, item.getText()) .setText(R.id.tweetDate, item.getCreatedAt()) .setVisible(R.id.tweetRT, item.isRetweet()) .linkify(R.id.tweetText); Glide.with(mContext).load(item.getUserAvatar()).crossFade().into((ImageView) viewHolder.getView(R.id.iv)); } } ``` 可以看到,僅僅需要繼承BaseQuickAdapter,在構造器中傳入item view的布局,并重寫convert方法即可。 ## 優化Adapter代碼源碼分析 直接來看BaseQuickAdapter的構造方法和convert方法: 構造方法: ```java public abstract class BaseQuickAdapter<T, K extends BaseViewHolder> extends RecyclerView.Adapter<K> { public BaseQuickAdapter(@LayoutRes int layoutResId, @Nullable List<T> data) { this.mData = data == null ? new ArrayList<T>() : data; if (layoutResId != 0) { this.mLayoutResId = layoutResId; } } //... protected abstract void convert(@NonNull K helper, T item); @Override public void onBindViewHolder(@NonNull K holder, int position) { int viewType = holder.getItemViewType(); switch (viewType) { case 0: convert(holder, getItem(position - getHeaderLayoutCount())); break; //... } } } ``` 可以看到我們熟悉的代碼了,在BaseQuickAdapter的構造方法中初始化了item布局和數據源;convert方法是一個抽象方法,在onBindViewHolder方法中進行調用。 # 點擊事件 如果是item的點擊事件,只要為Adapter設置clickListener即可: ```java adapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() { @Override public void onItemClick(BaseQuickAdapter adapter, View view, int position) { //... } }); ``` 而為item里面的控件設置點擊事件才是我們經常用到的 ```java @Override protected void convert(BaseViewHolder viewHolder, Status item) { viewHolder.addOnClickListener(R.id.tweetAvatar) .addOnClickListener(R.id.tweetName); } // Adapter設置監聽器 adapter.setOnItemChildClickListener(new BaseQuickAdapter.OnItemChildClickListener() { @Override public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) { switch (view.getId()) { case R.id.tweetAvatar: break; case R.id.tweetName: break; } } }); ``` ## 點擊事件源碼分析 在上一節的源碼分析中,我們在convert方法中可以拿到ViewHolder,這個ViewHolder繼承自BaseViewHolder,來看看源碼: ```java public class BaseViewHolder extends RecyclerView.ViewHolder { private final SparseArray<View> views; public BaseViewHolder setText(@IdRes int viewId, CharSequence value) { TextView view = getView(viewId); view.setText(value); return this; } public BaseViewHolder addOnClickListener(@IdRes final int ...viewIds) { for (int viewId : viewIds) { childClickViewIds.add(viewId); final View view = getView(viewId); view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int position = getAdapterPosition(); adapter.getOnItemChildClickListener().onItemChildClick(adapter, v, position); } }); } return this; } public <T extends View> T getView(@IdRes int viewId) { View view = views.get(viewId); if (view == null) { // 如果未緩存,則從視圖中尋找,并緩存 view = itemView.findViewById(viewId); views.put(viewId, view); } return (T) view; } } ``` BaseViewHolder采用SparseArray將所有View緩存起來,在需要使用的時候調用getView方法進行獲取。上面源碼只列出了setText方法,其他如setVisible、setBackgroundColor、setImageDrawable等均類似。 值得注意的一點是關于點擊事件的處理。最新版本的代碼中廢棄了`view.setOnClickListener(listener)`直接設置監聽器的做法,改為調用BaseQuickAdapter的OnItemChildClickListener的相應方法。這種操作將點擊事件的設定由Adapter內部,改到Adapter外部,也就是操作Adapter對象來設置點擊事件,讓Adapter來專心做item的適配工作。 # item展示動畫 ```java // 打開默認動畫 public void openLoadAnimation() {} // 打開自定義動畫 public void openLoadAnimation(BaseAnimation animation) {} // 打開內置的5種動畫 public void openLoadAnimation(@AnimationType int animationType) {} ``` ## item展示動畫源碼分析 ```java public void openLoadAnimation() { this.mOpenAnimationEnable = true; } public void openLoadAnimation(BaseAnimation animation) { this.mOpenAnimationEnable = true; this.mCustomAnimation = animation; } ``` 打開動畫僅僅是將mOpenAnimationEnable置為true,那么是什么時候添加的動畫呢? 通過閱讀源碼可知, ```java public void onViewAttachedToWindow(@NonNull K holder) { //... addAnimation(holder); } ``` 在Adapter創建出的itemView被添加到Window時,會調用addAnimation方法。 ```java private void addAnimation(RecyclerView.ViewHolder holder) { if (mOpenAnimationEnable) { //... if (mCustomAnimation != null) { animation = mCustomAnimation; } else { animation = mSelectAnimation; } for (Animator anim : animation.getAnimators(holder.itemView)) { startAnim(anim, holder.getLayoutPosition()); } } } } ``` 接下來我們再仔細分析分析內置的動畫,具體是如何展示的呢。內置動畫全部實現了BaseAnimation接口: ```java public interface BaseAnimation { Animator[] getAnimators(View view); } ``` 來看看隨便一個實現類: ```java public class SlideInBottomAnimation implements BaseAnimation { @Override public Animator[] getAnimators(View view) { return new Animator[]{ ObjectAnimator.ofFloat(view, "translationY", view.getMeasuredHeight(), 0) }; } } ``` 是的,直接使用屬性動畫來完成的操作。下面我們再整理一下整個步驟: * 為Adapter設置openLoadAnimation方法打開動畫 * Adapter創建出的itemView在添加到Window展示時,為itemView添加屬性動畫 # 添加HeadView和FootView ListView可以方便的添加HeadView和FootView,下面看看BaseRecyclerViewAdapterHelper是如何使用及實現的。 ```java public int addHeaderView(View header) {} public int addFooterView(View footer) {} public void removeHeaderView(View header) {} public void removeFooterView(View footer) {} public void removeAllHeaderView() {} public void removeAllFooterView() {} ``` ## 添加HeadView和FootView源碼分析 來看看addHeaderView的源碼: ```java private LinearLayout mHeaderLayout; public int addHeaderView(View header,final int index, int orientation) { if (mHeaderLayout == null) { mHeaderLayout = new LinearLayout(header.getContext()); if (orientation == LinearLayout.VERTICAL) { mHeaderLayout.setOrientation(LinearLayout.VERTICAL); mHeaderLayout.setLayoutParams(new LayoutParams(MATCH_PARENT, WRAP_CONTENT)); } else { mHeaderLayout.setOrientation(LinearLayout.HORIZONTAL); mHeaderLayout.setLayoutParams(new LayoutParams(WRAP_CONTENT, MATCH_PARENT)); } } final int childCount = mHeaderLayout.getChildCount(); int mIndex =index; if (index < 0 || index > childCount) { mIndex = childCount; } mHeaderLayout.addView(header, mIndex); if (mHeaderLayout.getChildCount() == 1) { int position = getHeaderViewPosition(); if (position != -1) { notifyItemInserted(position); } } return mIndex; } ``` 代碼有點長,但是邏輯很簡單,首先判斷mHeaderLayout是否為空,mHeaderLayout是一個LinearLayout,用來放HeadView的,由此判斷HeadView可以添加多個。創建一個LinearLayout并把HeadView添加進去即可。mHeaderLayout又是如何展示出來的呢? ```java public K onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { switch (viewType) { case HEADER_VIEW: ViewParent headerLayoutVp = mHeaderLayout.getParent(); // 如果headerLayoutVp有父布局的話,進行移除 if (headerLayoutVp instanceof ViewGroup) { ((ViewGroup) headerLayoutVp).removeView(mHeaderLayout); } baseViewHolder = createBaseViewHolder(mHeaderLayout); break; //... } baseViewHolder.setAdapter(this); return baseViewHolder; } ``` 原來在onCreateViewHolder方法中,根據ViewType類型來創建ViewHolder即可。 # 拖拽和滑動刪除item 使用拖拽和滑動刪除item功能需要Adapter繼承BaseItemDraggableAdapter。 ```java ItemDragAndSwipeCallback itemDragAndSwipeCallback = new ItemDragAndSwipeCallback(mAdapter); ItemTouchHelper itemTouchHelper = new ItemTouchHelper(itemDragAndSwipeCallback); itemTouchHelper.attachToRecyclerView(mRecyclerView); // 開啟拖拽 mAdapter.enableDragItem(itemTouchHelper, R.id.textView, true); mAdapter.setOnItemDragListener(onItemDragListener); // 開啟滑動刪除 mAdapter.enableSwipeItem(); mAdapter.setOnItemSwipeListener(onItemSwipeListener); ``` ## 拖拽和滑動刪除item源碼分析 ### 拖拽源碼分析 從enableDragItem方法看起: ```java public void enableDragItem(@NonNull ItemTouchHelper itemTouchHelper, int toggleViewId, boolean dragOnLongPress) { itemDragEnabled = true; mItemTouchHelper = itemTouchHelper; // 設置切換id setToggleViewId(toggleViewId); // 設置是否需要長按,才能拖動 setToggleDragOnLongPress(dragOnLongPress); } ``` 先來看看方法的三個參數,第一個參數ItemTouchHelper是一個系統類,用于RecyclerView的item移動;第二個參數是需要按住的子view的id;第三個參數是設置是否需要長按。來看看setToggleDragOnLongPress方法: ```java public void setToggleDragOnLongPress(boolean longPress) { mDragOnLongPress = longPress; if (mDragOnLongPress) { mOnToggleViewLongClickListener = new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { if (mItemTouchHelper != null && itemDragEnabled) { mItemTouchHelper.startDrag((RecyclerView.ViewHolder) v.getTag(R.id.BaseQuickAdapter_viewholder_support)); } return true; } }; } else { //... } } ``` 初始化OnToggleViewLongClickListener了,那OnToggleViewLongClickListener又是在那里用到的呢? ```java public void onBindViewHolder(@NonNull K holder, int position) { int viewType = holder.getItemViewType(); if (hasToggleView()) { View toggleView = holder.getView(mToggleViewId); if (toggleView != null) { toggleView.setTag(R.id.BaseQuickAdapter_viewholder_support, holder); if (mDragOnLongPress) { toggleView.setOnLongClickListener(mOnToggleViewLongClickListener); } else { toggleView.setOnTouchListener(mOnToggleViewTouchListener); } } } } ``` 可以看到,在創建ViewHolder的時候進行了綁定監聽器。開啟拖拽后,下面我們來看看拖拽監聽器: ```java public void onItemDragStart(RecyclerView.ViewHolder viewHolder) { if (mOnItemDragListener != null && itemDragEnabled) { mOnItemDragListener.onItemDragStart(viewHolder, getViewHolderPosition(viewHolder)); } } public void onItemDragMoving(RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) { //... if (mOnItemDragListener != null && itemDragEnabled) { mOnItemDragListener.onItemDragMoving(source, from, target, to); } } public void onItemDragEnd(RecyclerView.ViewHolder viewHolder) { if (mOnItemDragListener != null && itemDragEnabled) { mOnItemDragListener.onItemDragEnd(viewHolder, getViewHolderPosition(viewHolder)); } } ``` 設置好的拖拽監聽器分別在上述三個方法中調用,這三個方法又是在何時調用的呢?閱讀源碼可知,在ItemDragAndSwipeCallback方法進行調用,ItemDragAndSwipeCallback實現了ItemTouchHelper.Callback接口,完成了具體的拖拽滑動工作,ItemDragAndSwipeCallback的源碼后期再分析! ### 滑動刪除item源碼分析 ```java public void onItemSwipeStart(RecyclerView.ViewHolder viewHolder) { if (mOnItemSwipeListener != null && itemSwipeEnabled) { mOnItemSwipeListener.onItemSwipeStart(viewHolder, getViewHolderPosition(viewHolder)); } } public void onItemSwipeClear(RecyclerView.ViewHolder viewHolder) { if (mOnItemSwipeListener != null && itemSwipeEnabled) { mOnItemSwipeListener.clearView(viewHolder, getViewHolderPosition(viewHolder)); } } public void onItemSwiped(RecyclerView.ViewHolder viewHolder) { if (mOnItemSwipeListener != null && itemSwipeEnabled) { mOnItemSwipeListener.onItemSwiped(viewHolder, pos); } } public void onItemSwiping(Canvas canvas, RecyclerView.ViewHolder viewHolder, float dX, float dY, boolean isCurrentlyActive) { if (mOnItemSwipeListener != null && itemSwipeEnabled) { mOnItemSwipeListener.onItemSwipeMoving(canvas, viewHolder, dX, dY, isCurrentlyActive); } } ``` OnItemSwipeListener在上述幾個方法中調用,上面幾個方法在ItemDragAndSwipeCallback中調用,執行真正的滑動刪除工作。 # 上拉下拉更新 1、上拉加載使用代碼 ```java mAdapter.setOnLoadMoreListener(new BaseQuickAdapter.RequestLoadMoreListener() { @Override public void onLoadMoreRequested() { loadMore(); } }); private void loadMore() { new Request(mNextRequestPage, new RequestCallBack() { @Override public void success(List<Status> data) { boolean isRefresh = mNextRequestPage == 1; setData(isRefresh, data); } @Override public void fail(Exception e) { mAdapter.loadMoreFail(); } }).start(); } // setData方法上拉加載、下拉刷新共用 private void setData(boolean isRefresh, List data) { // 獲取到數據了,頁數加一 mNextRequestPage++; final int size = data == null ? 0 : data.size(); // 如果是第一頁,也就是重新刷新的 if (isRefresh) { mAdapter.setNewData(data); } else { // 不是第一頁,并且有數據 if (size > 0) { mAdapter.addData(data); } } if (size < PAGE_SIZE) { // 下拉刷新時,如果第一頁數據不夠一頁,就隱藏【沒有更多數據布局】 // 如果是后面的頁數,就顯示出【沒有更多數據布局】 mAdapter.loadMoreEnd(isRefresh); Toast.makeText(this, "no more data", Toast.LENGTH_SHORT).show(); } else { // 成功加載一頁數據 mAdapter.loadMoreComplete(); } } ``` 可以看到,在成功獲取到數據后,首先為Adapter添加數據,然后在回調loadMore相應的方法。 2、下拉刷新代碼 ```java mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { refresh(); } }); private void refresh() { mNextRequestPage = 1; // 這里的作用是防止下拉刷新的時候還可以上拉加載 mAdapter.setEnableLoadMore(false); new Request(mNextRequestPage, new RequestCallBack() { @Override public void success(List<Status> data) { setData(true, data); mAdapter.setEnableLoadMore(true); mSwipeRefreshLayout.setRefreshing(false); } @Override public void fail(Exception e) { Toast.makeText(PullToRefreshUseActivity.this, R.string.network_err, Toast.LENGTH_LONG).show(); mAdapter.setEnableLoadMore(true); mSwipeRefreshLayout.setRefreshing(false); } }).start(); } ``` ## 上拉下拉更新源碼分析 1、上拉加載源碼分析 關于上拉加載我們主要分析下面這兩個問題: * OnLoadMoreListener接口的onLoadMoreRequested 方法什么時候回調 * Adapter的loadMoreFail、loadMoreEnd、loadMoreComplete分別做了什么 先來看看setOnLoadMoreListener方法: ```java public void setOnLoadMoreListener(RequestLoadMoreListener requestLoadMoreListener, RecyclerView recyclerView) { openLoadMore(requestLoadMoreListener); // 綁定RecyclerView到當前Adapter if (getRecyclerView() == null) { setRecyclerView(recyclerView); } } // 設置監聽器 private void openLoadMore(RequestLoadMoreListener requestLoadMoreListener) { this.mRequestLoadMoreListener = requestLoadMoreListener; mNextLoadEnable = true; mLoadMoreEnable = true; mLoading = false; } ``` mRequestLoadMoreListener又是什么時候被調用到的呢,看源代碼: ```java // autoLoadMore 方法會在onBindViewHolder方法 private void autoLoadMore(int position) { if (doNotNeedShowLoadMore) { return; } //... mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_LOADING); if (!mLoading) { mLoading = true; if (getRecyclerView() != null) { getRecyclerView().post(new Runnable() { @Override public void run() { mRequestLoadMoreListener.onLoadMoreRequested(); } }); } else { mRequestLoadMoreListener.onLoadMoreRequested(); } } } ``` 可以看到,在onBindViewHolder方法中,會調用autoLoadMore方法來判斷是否需要請求加載更多,如需要則請求。接下來看看Adapter的loadMoreFail、loadMoreEnd、loadMoreComplete分別做了什么。 ```java public void loadMoreEnd(boolean gone) { mLoading = false; mNextLoadEnable = false; mLoadMoreView.setLoadMoreEndGone(gone); // 是否隱藏LoadMoreView if (gone) { notifyItemRemoved(getLoadMoreViewPosition()); } else { mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_END); notifyItemChanged(getLoadMoreViewPosition()); } } public void loadMoreComplete() { mLoading = false; mNextLoadEnable = true; mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_DEFAULT); notifyItemChanged(getLoadMoreViewPosition()); } public void loadMoreFail() { mLoading = false; mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_FAIL); notifyItemChanged(getLoadMoreViewPosition()); } ``` a、loadMoreEnd和loadMoreComplete的不同之處有,一是設置LoadMoreView狀態值不同,用于展示不同UI,下一步會說明;二是mNextLoadEnable的值設置不同,這個值用于獲取LoadMoreView的數量: ```java public int getLoadMoreViewCount() { if (!mNextLoadEnable && mLoadMoreView.isLoadEndMoreGone()) { return 0; } return 1; } ``` 可以看到,loadMoreEnd方法將mNextLoadEnable置為false,在獲取LoadMoreView數量時會返回0。 b、調用完成后修改mLoading、mNextLoadEnable的值,并更新loadMoreView的顯示狀態。LoadMoreView 的convert方法會根據mLoadMoreStatus狀態值來展示相應的UI: ```java public void convert(BaseViewHolder holder) { switch (mLoadMoreStatus) { case STATUS_LOADING: visibleLoading(holder, true); visibleLoadFail(holder, false); visibleLoadEnd(holder, false); break; case STATUS_FAIL: visibleLoading(holder, false); visibleLoadFail(holder, true); visibleLoadEnd(holder, false); break; //... } } ``` 注:可繼承LoadMoreView類來創建自定義LoadMoreView,為Adapter.setLoadMoreView即可。 2、下拉刷新源碼分析 下拉刷新的邏輯比較簡單,需要注意的是下拉刷新時需要禁用Adapter的上拉加載功能。 # 可折疊item ![](https://img.kancloud.cn/70/64/7064a0d673468bdf2d1e5e17e02795b2_341x535.gif) Java bean代碼 ```java public class Level0Item extends AbstractExpandableItem<Level1Item> {...} public class Level1Item extends AbstractExpandableItem<Person> {...} public class Person {...} ``` 適配器需要繼承自BaseMultiItemQuickAdapter,代碼: ```java public class ExpandableItemAdapter extends BaseMultiItemQuickAdapter<MultiItemEntity, BaseViewHolder> { public ExpandableItemAdapter(List<MultiItemEntity> data) { super(data); addItemType(TYPE_LEVEL_0, R.layout.item_expandable_lv0); addItemType(TYPE_LEVEL_1, R.layout.item_expandable_lv1); addItemType(TYPE_PERSON, R.layout.item_text_view); } @Override protected void convert(final BaseViewHolder holder, final MultiItemEntity item) { switch (holder.getItemViewType()) { case TYPE_LEVEL_0: .... //set view content holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int pos = holder.getAdapterPosition(); if (lv0.isExpanded()) { collapse(pos); } else { expand(pos); } }}); break; case TYPE_LEVEL_1: // similar with level 0 break; case TYPE_PERSON: //just set the content break; } } ``` 使用: ```java public class ExpandableUseActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { ... ArrayList<MultiItemEntity> list = generateData(); ExpandableItemAdapter adapter = new ExpandableItemAdapter(list); mRecyclerView.setAdapter(adapter); } private ArrayList<MultiItemEntity> generateData() { ArrayList<MultiItemEntity> res = new ArrayList<>(); for (int i = 0; i < lv0Count; i++) { Level0Item lv0 = new Level0Item(...); for (int j = 0; j < lv1Count; j++) { Level1Item lv1 = new Level1Item(...); for (int k = 0; k < personCount; k++) { lv1.addSubItem(new Person()); } lv0.addSubItem(lv1); } res.add(lv0); } return res; } } ``` ## 可折疊item源碼分析 在適配器ExpandableItemAdapter代碼中可以看到,點擊事件所執行的操作僅僅是如果是展開的就折疊起來,如果是折疊的就展開,那么我們來看看展開和折疊操作是怎么實現的。 1、折疊源碼 先來看看collapse(pos)方法: ```java // 折疊 public int collapse(@IntRange(from = 0) int position, boolean animate, boolean notify) { // 獲取當前item IExpandable expandable = getExpandableItem(position); // 遞歸折疊所有子item int subItemCount = recursiveCollapse(position); // 設置item展開狀態 expandable.setExpanded(false); // 更新UI notifyDataSetChanged(); return subItemCount; } // 遞歸折疊所有子item private int recursiveCollapse(@IntRange(from = 0) int position) { T item = getItem(position); IExpandable expandable = (IExpandable) item; List<T> collapseList = new ArrayList<>(); for (int i = position + 1, n = mData.size(); i < n; i++) { itemTemp = mData.get(i); collapseList.add(itemTemp); } // 從數據源移除所有子item mData.removeAll(collapseList); return collapseList.size(); } ``` 其中IExpandable接口如下,AbstractExpandableItem就實現了此接口: ```java // 如果一個item是可以展開折疊類型的,就實現這個接口 public interface IExpandable<T> { boolean isExpanded(); void setExpanded(boolean expanded); List<T> getSubItems(); int getLevel(); } ``` 2、展開源碼 ```java public int expand(@IntRange(from = 0) int position, boolean animate, boolean shouldNotify) { // 獲取item實例 IExpandable expandable = getExpandableItem(position); // 沒有子item,直接設置為已展開狀態,并更新UI if (!hasSubItems(expandable)) { expandable.setExpanded(true); notifyItemChanged(position); return 0; } // 展開item if (!expandable.isExpanded()) { List list = expandable.getSubItems(); mData.addAll(position + 1, list); // 遞歸展開子item subItemCount += recursiveExpand(position + 1, list); // 設置展開狀態 expandable.setExpanded(true); } notifyDataSetChanged(); return subItemCount; } ``` 展開狀態的源碼邏輯和折疊邏輯基本一致。 # 添加多類型item ```java public class MultipleItemQuickAdapter extends BaseMultiItemQuickAdapter<MultipleItem> { public MultipleItemQuickAdapter(List data) { super(data); addItemType(MultipleItem.TEXT, R.layout.text_view); addItemType(MultipleItem.IMG, R.layout.image_view); } @Override protected void convert(BaseViewHolder helper, MultipleItem item) { switch (helper.getItemViewType()) { case MultipleItem.TEXT: helper.setImageUrl(R.id.tv, item.getContent()); break; case MultipleItem.IMG: helper.setImageUrl(R.id.iv, item.getContent()); break; default: break; } } } ``` ## 添加多類型item源碼分析 在Adapter的構造方法中添加需要的itemType,源碼如下: ```java public abstract class BaseMultiItemQuickAdapter { // 緩存各種類型的布局資源文件 private SparseIntArray layouts; protected void addItemType(int type, @LayoutRes int layoutResId) { if (layouts == null) { layouts = new SparseIntArray(); } layouts.put(type, layoutResId); } private int getLayoutId(int viewType) { return layouts.get(viewType, TYPE_NOT_FOUND); } } ``` getLayout方法會在Adapter的onCreateViewHolder方法中,創建ViewHolder的時候進行獲取,并加載相應的布局。 同時,BaseRecyclerViewAdapterHelper還提供了另外一種實現多類型item的方案MultipleItemRvAdapter,用于解決類型過多時convert方法中業務代碼臃腫的問題,具體可參考[https://github.com/chaychan/MultipleItemRvAdapter](https://github.com/chaychan/MultipleItemRvAdapter)。 # 設置空布局 ```java public void setEmptyView(View emptyView) {} ``` ## 設置空布局源碼分析 ```java public void setEmptyView(View emptyView) { if (mEmptyLayout == null) { mEmptyLayout = new FrameLayout(emptyView.getContext()); final LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); final ViewGroup.LayoutParams lp = emptyView.getLayoutParams(); if (lp != null) { layoutParams.width = lp.width; layoutParams.height = lp.height; } mEmptyLayout.setLayoutParams(layoutParams); } mEmptyLayout.removeAllViews(); mEmptyLayout.addView(emptyView); notifyDataSetChanged(); } ``` 代碼很簡單,mEmptyLayout是一個FrameLayout,首先判斷是否為空,為空則創建,并把要添加的空布局添加進去即可。我們已經設置好了空布局,但是什么時候會顯示呢?Adapter在創建ViewHolder的時候都是根據viewType來進行創建的,而viewType是在getItemViewType方法配置,一起來看看: ```java public int getItemViewType(int position) { // 只有進到這里才會顯示空布局 if (getEmptyViewCount() == 1) { boolean header = mHeadAndEmptyEnable && getHeaderLayoutCount() != 0; switch (position) { case 0: if (header) { return HEADER_VIEW; } else { return EMPTY_VIEW; } case 1: if (header) { return EMPTY_VIEW; } else { return FOOTER_VIEW; } case 2: return FOOTER_VIEW; default: return EMPTY_VIEW; } } //... } public int getEmptyViewCount() { if (mEmptyLayout == null || mEmptyLayout.getChildCount() == 0) { return 0; } if (!mIsUseEmpty) { return 0; } if (mData.size() != 0) { return 0; } return 1; } ``` 可以看到,只有getEmptyViewCount返回值為1才會顯示空布局,而只有mEmptyLayout不為空且有設置空布局,有配置使用空布局,數據源為空,這幾個條件全部滿足時,才會顯示空布局(會結合HeadView一起判斷,此處暫不分析)。 # 總結 BaseRecyclerViewAdapterHelper對于我們使用RecyclerView常用的功能進行了封裝,主要思路為 * 找出重復代碼,抽取到基類,非復用部分使用抽象方法代替,具體子類來實現 * 靈活使用RecyclerView的itemViewType特性,根據不同的viewType來創建不同的視圖,如下拉上拉、空布局等等都是使用此思路實現
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看