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); }