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);
}
複製代碼