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參數)是哪一種類型的佈局
public final void notifyDataSetChanged() { mObservable.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); } }
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(); }
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; }
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) { //代碼省略了,有須要的小夥伴能夠本身看看,這裏面邏輯實在太複雜呢 }
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); } } }
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(); }
LinearSnapHelper snapHelper = new LinearSnapHelper(); snapHelper.attachToRecyclerView(mRecyclerView);
PagerSnapHelper snapHelper = new PagerSnapHelper(); snapHelper.attachToRecyclerView(mRecyclerView);
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; } } });
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的正確尺寸並設置偏移量。
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(); }
@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
以LinearLayoutManager爲例 忽略ItemDecoration 忽略ItemAnimator 忽略Measure過程 假設RecyclerView的width和height是肯定的 Recycler 忽略mViewCacheExtension
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; }
@SuppressWarnings("WeakerAccess") @Nullable public abstract int[] calculateDistanceToFinalSnap(@NonNull LayoutManager layoutManager, @NonNull View targetView);
@SuppressWarnings("WeakerAccess") @Nullable public abstract View findSnapView(LayoutManager layoutManager);
public abstract int findTargetSnapPosition(LayoutManager layoutManager, int velocityX, int velocityY);
SnapHelper繼承了 RecyclerView.OnFlingListener,實現了onFling方法。android
@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對齊到目的座標位置git
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這個方法源碼博客程序員
@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; } }; }
@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; }
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; }
//獲取當前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)
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); } } }
@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; }
@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.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(); } } });
beforeDescendants:viewgroup會優先其子類控件而獲取到焦點 afterDescendants:viewgroup只有當其子類控件不須要獲取焦點時才獲取焦點 blocksDescendants:viewgroup會覆蓋子類控件而直接得到焦點
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
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>
@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); }
//給ImageView打上Tag做爲特有標記 imageView.setTag(tag); //下載圖片 loadImage(); //根據tag判斷是否是須要設置給ImageView if(tag == iamgeView.getTag()) { imageView.setBitmapImage(iamge); }