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