00.RecyclerView複雜封裝庫android
02.Adapter程序員
03.ViewHoldergithub
04.LayoutManagercanvas
關於RecyclerView,你們都已經很熟悉了,用途十分普遍,大概結構以下所示
如圖所示,直觀展現結構
adapter的做用是什麼
幾個方法是作什麼用的
public VH onCreateViewHolder(ViewGroup parent, int viewType) 建立Item視圖,並返回相應的ViewHolder public void onBindViewHolder(VH holder, int position) 綁定數據到正確的Item視圖上。 public int getItemCount() 返回該Adapter所持有的Itme數量 public int getItemViewType(int position) 用來獲取當前項Item(position參數)是哪一種類型的佈局
如何理解adapter訂閱者模式
a.首先看.notifyDataSetChanged()源碼
public final void notifyDataSetChanged() { mObservable.notifyChanged(); }
b.接着查看.notifyChanged();源碼
static class AdapterDataObservable extends Observable<AdapterDataObserver> { public boolean hasObservers() { return !mObservers.isEmpty(); } public void notifyChanged() { for (int i = mObservers.size() - 1; i >= 0; i--) { mObservers.get(i).onChanged(); } } public void notifyItemRangeChanged(int positionStart, int itemCount) { notifyItemRangeChanged(positionStart, itemCount, null); } public void notifyItemRangeChanged(int positionStart, int itemCount, Object payload) { for (int i = mObservers.size() - 1; i >= 0; i--) { mObservers.get(i).onItemRangeChanged(positionStart, itemCount, payload); } } public void notifyItemRangeInserted(int positionStart, int itemCount) { for (int i = mObservers.size() - 1; i >= 0; i--) { mObservers.get(i).onItemRangeInserted(positionStart, itemCount); } } }
public static abstract class AdapterDataObserver { public void onChanged() { // Do nothing } public void onItemRangeChanged(int positionStart, int itemCount) { // do nothing } public void onItemRangeChanged(int positionStart, int itemCount, Object payload) { onItemRangeChanged(positionStart, itemCount); } }
c.接着查看setAdapter()源碼中的setAdapterInternal(adapter, false, true)方法
public void setAdapter(Adapter adapter) { // bail out if layout is frozen setLayoutFrozen(false); setAdapterInternal(adapter, false, true); requestLayout(); }
private void setAdapterInternal(Adapter adapter, boolean compatibleWithPrevious, boolean removeAndRecycleViews) { if (mAdapter != null) { mAdapter.unregisterAdapterDataObserver(mObserver); mAdapter.onDetachedFromRecyclerView(this); } if (!compatibleWithPrevious || removeAndRecycleViews) { removeAndRecycleViews(); } mAdapterHelper.reset(); final Adapter oldAdapter = mAdapter; mAdapter = adapter; if (adapter != null) { //註冊一個觀察者RecyclerViewDataObserver adapter.registerAdapterDataObserver(mObserver); adapter.onAttachedToRecyclerView(this); } if (mLayout != null) { mLayout.onAdapterChanged(oldAdapter, mAdapter); } mRecycler.onAdapterChanged(oldAdapter, mAdapter, compatibleWithPrevious); mState.mStructureChanged = true; markKnownViewsInvalid(); }
d.notify……方法被調用,刷新數據
ViewHolder做用大概有這些:
如何理解ViewHolder的複用
在複寫RecyclerView.Adapter的時候,須要咱們複寫兩個方法:博客
複用機制是怎樣的?
查看一下createViewHolder源代碼
public final VH createViewHolder(ViewGroup parent, int viewType) { TraceCompat.beginSection(TRACE_CREATE_VIEW_TAG); final VH holder = onCreateViewHolder(parent, viewType); holder.mItemViewType = viewType; TraceCompat.endSection(); return holder; }
對於ViewHolder對象的數量「夠用」以後就中止調用onCreateViewHolder方法,能夠查看
public View getViewForPosition(int position) { return getViewForPosition(position, false); } View getViewForPosition(int position, boolean dryRun) { return tryGetViewHolderForPositionByDeadline(position, dryRun, FOREVER_NS).itemView; } @Nullable ViewHolder tryGetViewHolderForPositionByDeadline(int position,boolean dryRun, long deadlineNs) { //代碼省略了,有須要的小夥伴能夠本身看看,這裏面邏輯實在太複雜呢 }
ViewHolder封裝如何對findViewById優化?
class MyViewHolder extends RecyclerView.ViewHolder { private SparseArray<View> viewSparseArray; private TextView tvTitle; MyViewHolder(final View itemView) { super(itemView); if(viewSparseArray==null){ viewSparseArray = new SparseArray<>(); } tvTitle = (TextView) viewSparseArray.get(R.id.tv_title); if (tvTitle == null) { tvTitle = itemView.findViewById(R.id.tv_title); viewSparseArray.put(R.id.tv_title, tvTitle); } } }
爲什麼使用SparseArray替代HashMap存儲viewId
HashMap
當有鍵值對插入時,HashMap 會發生什麼 ?
缺點:
SparseArray博客
當保存一對鍵值對的時候:
查找的時候:
LayoutManager做用是什麼?
LayoutManager樣式有哪些?
setLayoutManager(LayoutManager layout)源碼
public void setLayoutManager(LayoutManager layout) { if (layout == mLayout) { return; } // 中止滑動 stopScroll(); if (mLayout != null) { // 若是有動畫,則中止全部的動畫 if (mItemAnimator != null) { mItemAnimator.endAnimations(); } // 移除並回收視圖 mLayout.removeAndRecycleAllViews(mRecycler); // 回收廢棄視圖 mLayout.removeAndRecycleScrapInt(mRecycler); //清除mRecycler mRecycler.clear(); if (mIsAttached) { mLayout.dispatchDetachedFromWindow(this, mRecycler); } mLayout.setRecyclerView(null); mLayout = null; } else { mRecycler.clear(); } mChildHelper.removeAllViewsUnfiltered(); mLayout = layout; if (layout != null) { if (layout.mRecyclerView != null) { throw new IllegalArgumentException("LayoutManager " + layout + " is already attached to a RecyclerView: " + layout.mRecyclerView); } mLayout.setRecyclerView(this); if (mIsAttached) { mLayout.dispatchAttachedToWindow(this); } } //更新新的緩存數據 mRecycler.updateViewCacheSize(); //從新請求 View 的測量、佈局、繪製 requestLayout(); }
SnapHelper主要是作什麼用的
SnapHelper是怎麼實現支持RecyclerView的對齊方式
SnapHelper類重要的方法
什麼是Fling操做
LinearSnapHelper類分析
最簡單的使用就是,以下代碼
LinearSnapHelper snapHelper = new LinearSnapHelper(); snapHelper.attachToRecyclerView(mRecyclerView);
PagerSnapHelper類分析
最簡單的使用就是,以下代碼
PagerSnapHelper snapHelper = new PagerSnapHelper(); snapHelper.attachToRecyclerView(mRecyclerView);
SpanSizeLookup的做用是幹什麼的?
SpanSizeLookup如何使用?
GridLayoutManager manager = new GridLayoutManager(this, 6); manager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { @Override public int getSpanSize(int position) { SpanModel model = mDataList.get(position); if (model.getType() == 1) { return 6; } else if(model.getType() == 2){ return 3; }else if (model.getType() == 3){ return 2; }else if (model.getType() == 4){ return 2; } else { return 1; } } });
ItemDecoration的用途是什麼?
自定義ItemDecoration有哪些重寫方法
public void onDraw(Canvas c, RecyclerView parent) 裝飾的繪製在Item條目繪製以前調用,因此這有可能被Item的內容所遮擋 public void onDrawOver(Canvas c, RecyclerView parent) 裝飾的繪製在Item條目繪製以後調用,所以裝飾將浮於Item之上 public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) 與padding或margin相似,LayoutManager在測量階段會調用該方法,計算出每個Item的正確尺寸並設置偏移量。
分析一下addItemDecoration()源碼?
a.經過下面代碼可知,mItemDecorations是一個ArrayList,咱們將ItemDecoration也就是分割線對象,添加到其中。
public void addItemDecoration(ItemDecoration decor) { addItemDecoration(decor, -1); } //主要看這個方法,個人GitHub:https://github.com/yangchong211/YCBlogs public void addItemDecoration(ItemDecoration decor, int index) { if (mLayout != null) { mLayout.assertNotInLayoutOrScroll("Cannot add item decoration during a scroll or" + " layout"); } if (mItemDecorations.isEmpty()) { setWillNotDraw(false); } if (index < 0) { mItemDecorations.add(decor); } else { // 指定添加分割線在集合中的索引 mItemDecorations.add(index, decor); } markItemDecorInsetsDirty(); // 從新請求 View 的測量、佈局、繪製 requestLayout(); }
總結歸納博客
上拉加載更多的功能是如何作的?
01.添加recyclerView的滑動事件
02.上拉加載分頁數據
03.設置上拉加載的底部footer佈局
在adapter中,能夠上拉加載時處理footerView的邏輯
04.顯示和隱藏footer佈局
網格佈局上拉加載如何優化
@Override public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) { super.onAttachedToRecyclerView(recyclerView); RecyclerView.LayoutManager manager = recyclerView.getLayoutManager(); if (manager instanceof GridLayoutManager) { final GridLayoutManager gridManager = ((GridLayoutManager) manager); gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { @Override public int getSpanSize(int position) { // 若是當前是footer的位置,那麼該item佔據2個單元格,正常狀況下佔據1個單元格 return getItemViewType(position) == footType ? gridManager.getSpanCount() : 1; } }); } }
那麼如何實現自動進行上拉刷新?
那麼如何實現手動上拉刷新呢?
RecyclerView繪製原理如何理解?
性能優化本質是什麼?
RecyclerView作性能優化要說複雜也複雜,好比說佈局優化,緩存,預加載,複用池,刷新數據等等。
所以性能優化的本質就是要減小這兩個函數的調用時間和調用的次數。博客
RecyclerView繪製原理過程大概是怎樣的?
簡化問題
RecyclerView 以LinearLayoutManager爲例 忽略ItemDecoration 忽略ItemAnimator 忽略Measure過程 假設RecyclerView的width和height是肯定的 Recycler 忽略mViewCacheExtension
繪製過程
類的職責介紹
繪製過程簡介
RecyclerView的Recyler是如何實現ViewHolder的緩存?
首先看看代碼
public final class Recycler { final ArrayList<ViewHolder> mAttachedScrap = new ArrayList<>(); ArrayList<ViewHolder> mChangedScrap = null; final ArrayList<ViewHolder> mCachedViews = new ArrayList<ViewHolder>(); private final List<ViewHolder> mUnmodifiableAttachedScrap = Collections.unmodifiableList(mAttachedScrap); private int mRequestedCacheMax = DEFAULT_CACHE_SIZE; int mViewCacheMax = DEFAULT_CACHE_SIZE; RecycledViewPool mRecyclerPool; private ViewCacheExtension mViewCacheExtension; static final int DEFAULT_CACHE_SIZE = 2; }
RecyclerView在Recyler裏面實現ViewHolder的緩存,Recycler裏面的實現緩存的主要包含如下5個對象:
ArrayList mAttachedScrap:未與RecyclerView分離的ViewHolder列表,若是仍依賴於 RecyclerView (好比已經滑動出可視範圍,但尚未被移除掉),但已經被標記移除的 ItemView 集合會被添加到 mAttachedScrap 中
ArrayList mCachedViews:緩存ViewHolder,主要用於解決RecyclerView滑動抖動時的狀況,還有用於保存Prefetch的ViewHoder
ViewCacheExtension mViewCacheExtension:開發者可自定義的一層緩存,是虛擬類ViewCacheExtension的一個實例,開發者可實現方法getViewForPositionAndType(Recycler recycler, int position, int type)來實現本身的緩存。
mRecyclerPool ViewHolder緩存池,在有限的mCachedViews中若是存不下ViewHolder時,就會把ViewHolder存入RecyclerViewPool中。
如何理解recyclerView三級緩存是如何實現的?
一級緩存:返回佈局和內容都都有效的ViewHolder
二級緩存:返回View
三級緩存:返回佈局有效,內容無效的ViewHolder
圖解博客
屏幕滑動(狀態是item狀態可見,不可見,即將可見變化)時三級緩存是如何理解的?
如圖所示
實例解釋:
圖片解釋:
出屏幕時候的狀況
ViewHolder(position=1,type=2)同步驟1 - 當ViewHolder(position=2,type=1)出屏幕的時候因爲一級緩存mCacheViews已經滿了,所以將其放入RecyclerPool(type=1)的緩存池裏面。此時ViewHolder的內容會被標記爲無效,當其複用的時候須要再次經過Adapter.bindViewHolder來綁定內容。 ViewHolder(position=3,type=2)同步驟3 - 進屏幕時候的狀況[博客](https://github.com/yangchong211/YCBlogs) - 當ViewHolder(position=3-10,type=3)進入屏幕繪製的時候,因爲Recycler的mCacheViews裏面找不到position匹配的View,同時RecyclerPool裏面找不到type匹配的View,所以,其只能經過adapter.createViewHolder來建立ViewHolder,而後經過adapter.bindViewHolder來綁定內容。 - 當ViewHolder(position=11,type=1)進入屏幕的時候,發現ReccylerPool裏面能找到type=1的緩存,所以直接從ReccylerPool裏面取來使用。因爲內容是無效的,所以還須要調用bindViewHolder來綁定佈局。同時ViewHolder(position=4,type=3)須要出屏幕,其直接進入RecyclerPool(type=3)的緩存池中 - ViewHolder(position=12,type=2)同步驟6 - 屏幕往下拉ViewHolder(position=1)進入屏幕的狀況 - 因爲mCacheView裏面的有position=1的ViewHolder與之匹配,直接返回。因爲內容是有效的,所以無需再次綁定內容 - ViewHolder(position=0)同步驟8
SnapHelper有哪些重要的方法,其做用就是是什麼?
calculateDistanceToFinalSnap抽象方法
計算最終對齊要移動的距離
@SuppressWarnings("WeakerAccess") @Nullable public abstract int[] calculateDistanceToFinalSnap(@NonNull LayoutManager layoutManager, @NonNull View targetView);
- findSnapView抽象方法 - 找到要對齊的View - 該方法會找到當前 layoutManager 上最接近對齊位置的那個 view ,該 view 稱爲 SanpView ,對應的 position 稱爲 SnapPosition 。若是返回 null ,就表示沒有須要對齊的 View ,也就不會作滾動對齊調整。 ``` @SuppressWarnings("WeakerAccess") @Nullable public abstract View findSnapView(LayoutManager layoutManager); ``` - findTargetSnapPosition抽象方法 - 找到須要對齊的目標View的的Position。[博客](https://github.com/yangchong211/YCBlogs) - 更加詳細一點說就是該方法會根據觸發 Fling 操做的速率(參數 velocityX 和參數 velocityY )來找到 RecyclerView 須要滾動到哪一個位置,該位置對應的 ItemView 就是那個須要進行對齊的列表項。咱們把這個位置稱爲 targetSnapPosition ,對應的 View 稱爲 targetSnapView 。若是找不到 targetSnapPosition ,就返回RecyclerView.NO_POSITION 。 ``` public abstract int findTargetSnapPosition(LayoutManager layoutManager, int velocityX, int velocityY); ```
LinearSnapHelper中是如何實現滾動中止的?
SnapHelper繼承了 RecyclerView.OnFlingListener,實現了onFling方法。
@Override public boolean onFling(int velocityX, int velocityY) { LayoutManager layoutManager = mRecyclerView.getLayoutManager(); if (layoutManager == null) { return false; } RecyclerView.Adapter adapter = mRecyclerView.getAdapter(); if (adapter == null) { return false; } int minFlingVelocity = mRecyclerView.getMinFlingVelocity(); return (Math.abs(velocityY) > minFlingVelocity || Math.abs(velocityX) > minFlingVelocity) && snapFromFling(layoutManager, velocityX, velocityY); }
接着看看snapFromFling方法源代碼,就是經過該方法實現平滑滾動並使得在滾動中止時itemView對齊到目的座標位置
private boolean snapFromFling(@NonNull LayoutManager layoutManager, int velocityX, int velocityY) { if (!(layoutManager instanceof ScrollVectorProvider)) { return false; } RecyclerView.SmoothScroller smoothScroller = createSnapScroller(layoutManager); if (smoothScroller == null) { return false; } int targetPosition = findTargetSnapPosition(layoutManager, velocityX, velocityY); if (targetPosition == RecyclerView.NO_POSITION) { return false; } smoothScroller.setTargetPosition(targetPosition); layoutManager.startSmoothScroll(smoothScroller); return true; }
接着看下createSnapScroller這個方法源碼博客
在建立該LinearSmoothScroller的時候主要考慮兩個方面:
@Nullable protected LinearSmoothScroller createSnapScroller(LayoutManager layoutManager) { if (!(layoutManager instanceof ScrollVectorProvider)) { return null; } return new LinearSmoothScroller(mRecyclerView.getContext()) { @Override protected void onTargetFound(View targetView, RecyclerView.State state, Action action) { int[] snapDistances = calculateDistanceToFinalSnap(mRecyclerView.getLayoutManager(), targetView); final int dx = snapDistances[0]; final int dy = snapDistances[1]; final int time = calculateTimeForDeceleration(Math.max(Math.abs(dx), Math.abs(dy))); if (time > 0) { action.update(dx, dy, time, mDecelerateInterpolator); } } @Override protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) { return MILLISECONDS_PER_INCH / displayMetrics.densityDpi; } }; }
calculateDistanceToFinalSnap的做用是什麼
@Override public int[] calculateDistanceToFinalSnap( @NonNull RecyclerView.LayoutManager layoutManager, @NonNull View targetView) { int[] out = new int[2]; if (layoutManager.canScrollHorizontally()) { out[0] = distanceToCenter(layoutManager, targetView, getHorizontalHelper(layoutManager)); } else { out[0] = 0; } if (layoutManager.canScrollVertically()) { out[1] = distanceToCenter(layoutManager, targetView, getVerticalHelper(layoutManager)); } else { out[1] = 0; } return out; }
接着看看distanceToCenter方法
private int distanceToCenter(@NonNull RecyclerView.LayoutManager layoutManager, @NonNull View targetView, OrientationHelper helper) { final int childCenter = helper.getDecoratedStart(targetView) + (helper.getDecoratedMeasurement(targetView) / 2); final int containerCenter; if (layoutManager.getClipToPadding()) { containerCenter = helper.getStartAfterPadding() + helper.getTotalSpace() / 2; } else { containerCenter = helper.getEnd() / 2; } return childCenter - containerCenter; }
那麼out[0]和out[1]分別指什麼
須要實現的分割線功能
幾個重要的方法說明
//獲取當前view的位置信息,該方法主要是設置條目周邊的偏移量 public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) //在item背後draw public void onDraw(Canvas c, RecyclerView parent, State state) //在item上邊draw public void onDrawOver(Canvas c, RecyclerView parent, State state)
注意的是三個方法的調用順序
爲每一個item實現索引的思路
如何實現複雜type首頁需求
一般寫一個多Item列表的方法
主要操做步驟
代碼以下所示
public class HomeAdapter extends RecyclerView.Adapter { public static final int TYPE_BANNER = 0; public static final int TYPE_AD = 1; @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { switch (viewType){ case TYPE_BANNER: return new BannerViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.home_banner_layout,null)); case TYPE_AD: return new BannerViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.home_ad_item_layout,null)); } return null; } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { int type = getItemViewType(position); switch (type){ case TYPE_BANNER: // banner 邏輯處理 break; case TYPE_AD: // 廣告邏輯處理 break; // ... 此處省去N行代碼 } } @Override public int getItemViewType(int position) { if(position == 0){ return TYPE_BANNER;//banner在開頭 }else { return mData.get(position).type;//type 的值爲TYPE_AD,TYPE_IMAGE,TYPE_AD,等其中一個 } } public static class BannerViewHolder extends RecyclerView.ViewHolder{ public BannerViewHolder(View itemView) { super(itemView); } } public static class NewViewHolder extends RecyclerView.ViewHolder{ public VideoViewHolder(View itemView) { super(itemView); } } }
若是不封裝會出現什麼問題和弊端
RecyclerView 能夠用ViewType來區分不一樣的item,也能夠知足需求,但仍是存在一些問題,好比:
上面那樣寫的弊端
如何提升代碼的簡便性和高效性。具體封裝庫看:recyclerView複雜type封裝庫
核心目的就是三個
在getItemViewType方法中。
onCreateViewHolder
封裝後好處
關於rv設置item條目點擊事件有兩種方式:1.在onCreateViewHolder中寫;2.在onBindViewHolder中寫;3.在ViewHolder中寫。那麼到底是哪種好呢?
1.在onCreateViewHolder中寫
@NonNull @Override public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { final View view = LayoutInflater.from(mContext).inflate(R.layout.item_me_gv_grid, parent, false); final MyViewHolder holder = new MyViewHolder(view); view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (listener != null) { listener.onItemClick(view, holder.getLayoutPosition()); } } }); return holder; }
2.在onBindViewHolder中寫
@Override public void onBindViewHolder(@NonNull final MyViewHolder holder, int position) { holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (listener != null) { listener.onItemClick(holder.itemView, holder.getAdapterPosition()); } } }); }
RecyclerView滑動卡頓緣由有哪些
第一種:嵌套佈局滑動衝突
第二種:嵌套佈局層次太深,好比六七層等
如何解決嵌套佈局滑動衝突
如何解決RecyclerView實現畫廊卡頓?
//RecyclerView.SCROLL_STATE_IDLE //空閒狀態 //RecyclerView.SCROLL_STATE_FLING //滾動狀態 //RecyclerView.SCROLL_STATE_TOUCH_SCROLL //觸摸後狀態 recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); if (newState == RecyclerView.SCROLL_STATE_IDLE) { LoggerUtils.e("initRecyclerView"+ "恢復Glide加載圖片"); Glide.with(ImageBrowseActivity.this).resumeRequests(); }else { LoggerUtils.e("initRecyclerView"+"禁止Glide加載圖片"); Glide.with(ImageBrowseActivity.this).pauseRequests(); } } });
在onCreateViewHolder或者在onBindViewHolder中作了耗時的操做致使卡頓
RecyclerView常見的優化有哪些
DiffUtil刷新優化
佈局優化
減小 xml 文件 inflate 時間
減小 View 對象的建立
對itemView中孩子View的點擊事件優化
其餘的一些優化點
若是 Item 高度是固定的話,可使用 RecyclerView.setHasFixedSize(true); 來避免 requestLayout 浪費資源;
RecyclerView嵌套RecyclerView 條目自動上滾的Bug
一,recyclerview去除焦點
二,在代碼裏面 讓處於ScrollView或者RecyclerView1 頂端的某個控件得到焦點便可
三,能夠直接在RecyclerView父佈局中添加上descendantFocusability屬性的值有三種:android:descendantFocusability="beforeDescendants"
beforeDescendants:viewgroup會優先其子類控件而獲取到焦點 afterDescendants:viewgroup只有當其子類控件不須要獲取焦點時才獲取焦點 blocksDescendants:viewgroup會覆蓋子類控件而直接得到焦點
如何解決ScrollView嵌套RecyclerView滑動衝突?
第一種方式:
public class NoNestedScrollview extends NestedScrollView { @Override public boolean onInterceptTouchEvent(MotionEvent e) { int action = e.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: downX = (int) e.getRawX(); downY = (int) e.getRawY(); break; case MotionEvent.ACTION_MOVE: //判斷是否滑動,若滑動就攔截事件 int moveY = (int) e.getRawY(); if (Math.abs(moveY - downY) > mTouchSlop) { return true; } break; default: break; } return super.onInterceptTouchEvent(e); } }
第二種解決方式博客
recyclerView.setLayoutManager(new GridLayoutManager(mContext,2){ @Override public boolean canScrollVertically() { return false; } @Override public boolean canScrollHorizontally() { return super.canScrollHorizontally(); } }); recyclerView.setLayoutManager(new LinearLayoutManager(mContext, LinearLayout.VERTICAL,false){ @Override public boolean canScrollVertically() { return false; } });
可能會出現的問題博客
針對這種情形,使用網上的方法一種是使用 RelativeLayout 包裹 RecyclerView 並設置屬性:android:descendantFocusability="blocksDescendants"
<RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:descendantFocusability="blocksDescendants"> <android.support.v7.widget.RecyclerView android:id="@+id/rv_hot_review" android:layout_width="match_parent" android:layout_height="wrap_content" android:foregroundGravity="center" /> </RelativeLayout>
ViewPager嵌套水平RecyclerView橫向滑動到底後不滑動ViewPager
@Override public boolean dispatchTouchEvent(MotionEvent ev) { /*---解決垂ViewPager嵌套直RecyclerView嵌套水平RecyclerView橫向滑動到底後不滑動ViewPager start ---*/ ViewParent parent = this; while(!((parent = parent.getParent()) instanceof ViewPager)); // 循環查找viewPager parent.requestDisallowInterceptTouchEvent(true); return super.dispatchTouchEvent(ev); }
如何解決RecyclerView使用Glide加載圖片致使圖片錯亂問題
爲什麼會致使圖片加載後出現錯亂效果
第一種方法
//給ImageView打上Tag做爲特有標記 imageView.setTag(tag); //下載圖片 loadImage(); //根據tag判斷是否是須要設置給ImageView if(tag == iamgeView.getTag()) { imageView.setBitmapImage(iamge); }