日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

android实现评论列表_【Android视图效果】分组列表实现吸顶效果

發布時間:2023/12/2 Android 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android实现评论列表_【Android视图效果】分组列表实现吸顶效果 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

效果圖

效果圖

分析

先來分析一下,可以看到這是一個按月份分組的2行圖片列表,列表頂部一個懸浮欄,會隨著列表滑動而刷新,點擊頂部欄,彈出了一個篩選框。

思路

1.列表部分

可以用RecyclerView+GridLayoutManager,月份的標題欄可以使用多布局

首先是主體item的布局

<?xml ?version="1.0"?encoding="utf-8"?>
<android.support.v7.widget.CardView?xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@color/cffffff"app:cardCornerRadius="4dp">


???<android.support.constraint.ConstraintLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content">

???????<ImageView???????android:id="@+id/iv_pictrue"???????android:layout_width="match_parent"???????android:layout_height="0dp"???????app:layout_constraintDimensionRatio="1.78:1"?/>

???????<TextView???????android:id="@+id/tv_pictrue_title"???????android:layout_width="wrap_content"???????android:layout_height="wrap_content"???????android:layout_marginTop="10dp"???????android:textColor="@color/c151619"???????android:textSize="16sp"???????app:layout_constraintLeft_toLeftOf="parent"???????app:layout_constraintRight_toRightOf="parent"???????app:layout_constraintTop_toBottomOf="@id/iv_pictrue"???????tools:text="長沙會議圖集(210)"?/>

???????<TextView???????android:id="@+id/tv_pictrue_time"???????android:layout_width="wrap_content"???????android:layout_height="wrap_content"???????android:layout_marginTop="2dp"???????android:layout_marginBottom="10dp"???????tools:text="2018-11-10"???????android:textColor="@color/c969696"???????android:textSize="16sp"???????app:layout_constraintBottom_toBottomOf="parent"???????app:layout_constraintLeft_toLeftOf="parent"???????app:layout_constraintRight_toRightOf="parent"???????app:layout_constraintTop_toBottomOf="@id/tv_pictrue_title"?/>

???android.support.constraint.ConstraintLayout>
android.support.v7.widget.CardView>

PictureAdapter 這里使用了 BaseRecyclerViewAdapterHelper,需要繼承BaseMultiItemQuickAdapter,關于adapter多布局的使用,篇幅所限,這里不再細述。

public?class?PictureAdapter?extends?BaseMultiItemQuickAdapter<PictureModel,?BaseViewHolder>?{
????public?PictureAdapter(@Nullable?List?data)?{
????????super(data);
????????addItemType(PictureModel.PICTURE_CONTENT,?R.layout.item_pictures);
????????addItemType(PictureModel.PICTURE_TITLE,?R.layout.item_picture_month);
????}

????@Override
????protected?void?convert(BaseViewHolder?helper,?PictureModel?item)?{
????????if?(helper.getItemViewType()?==?PictureModel.PICTURE_CONTENT)?{
????????//標題/數量
????????helper.setText(R.id.tv_pictrue_title,?item.getTitle()?+?"("?+?item.getPicture_count()?+?")");
????????//時間
????????helper.setText(R.id.tv_pictrue_time,?item.getDate());
????????//封面圖
????????GlideUtils.loadImg(mContext,?item.getCover_image(),?(ImageView)?helper.getView(R.id.iv_pictrue));
????????}?else?if?(helper.getItemViewType()?==?PictureModel.PICTURE_TITLE)?{
????????helper.setText(R.id.tv_picture_month,?item.getDate());
????????}
????}

????@Override
????public?void?onAttachedToRecyclerView(RecyclerView?recyclerView)?{
????????super.onAttachedToRecyclerView(recyclerView);
????????FullSpanUtil.onAttachedToRecyclerView(recyclerView,?this,?PictureModel.PICTURE_TITLE);
????}

????@Override
????public?void?onViewDetachedFromWindow(@NonNull?BaseViewHolder?holder)?{
????????super.onViewDetachedFromWindow(holder);
????????FullSpanUtil.onViewAttachedToWindow(holder,?this,?PictureModel.PICTURE_TITLE);
????}
}

其中,由于月份的標題需要占滿一行,需要重寫onAttachedToRecyclerView和onViewDetachedFromWindow方法。

public?class?FullSpanUtil?{

????public?static?void?onAttachedToRecyclerView(RecyclerView?recyclerView,?final?RecyclerView.Adapter?adapter,?final?int?pinnedHeaderType)?{
????????//?如果是網格布局,這里處理標簽的布局占滿一行
????????final?RecyclerView.LayoutManager?layoutManager?=?recyclerView.getLayoutManager();
????????if?(layoutManager?instanceof?GridLayoutManager)?{
????????final?GridLayoutManager?gridLayoutManager?=?(GridLayoutManager)?layoutManager;
????????final?GridLayoutManager.SpanSizeLookup?oldSizeLookup?=?gridLayoutManager.getSpanSizeLookup();
????????gridLayoutManager.setSpanSizeLookup(new?GridLayoutManager.SpanSizeLookup()?{
????@Override
????public?int?getSpanSize(int?position)?{
????????if?(adapter.getItemViewType(position)?==?pinnedHeaderType)?{
????????return?gridLayoutManager.getSpanCount();
????????}
????????if?(oldSizeLookup?!=?null)?{
????????return?oldSizeLookup.getSpanSize(position);
????????}
????????return?1;
????????????}
????????});
????????}
????}

????public?static?void?onViewAttachedToWindow(RecyclerView.ViewHolder?holder,?RecyclerView.Adapter?adapter,?int?pinnedHeaderType)?{
????????//?如果是瀑布流布局,這里處理標簽的布局占滿一行
????????final?ViewGroup.LayoutParams?lp?=?holder.itemView.getLayoutParams();
????????if?(lp?instanceof?StaggeredGridLayoutManager.LayoutParams)?{
????????final?StaggeredGridLayoutManager.LayoutParams?slp?=?(StaggeredGridLayoutManager.LayoutParams)?lp;
????????slp.setFullSpan(adapter.getItemViewType(holder.getLayoutPosition())?==?pinnedHeaderType);
????????}
????}
}

PictureModel需要繼承MultiItemEntity,然后重寫getItemType方法,adapter即可通過model的type來判斷該使用哪個布局。
注:get和set方法這里就不貼了

public?class?PictureModel?implements?MultiItemEntity?{

????public?static?final?int?PICTURE_TITLE?=?1;
????public?static?final?int?PICTURE_CONTENT?=?0;
????private?int?type;
????private?String?id;
????private?String?title;
????private?String?date_time;
????private?String?create_time;
????private?String?picture_count;
????private?String?status;
????private?String?cover_image;
????private?String?date;

????public?PictureModel(int?type)?{
????????this.type?=?type;
????}
????public?int?getType()?{
????????return?type;
????}
????public?void?setType(int?type)?{
????????this.type?=?type;
????}

????@Override
????public?int?getItemType()?{
????????return?type;
????}
}

最后,是在Activity使用

?pictureAdapter?=?new?PictureAdapter(null);
?rvPictrues.setLayoutManager(new?GridLayoutManager(context,?2));
?SpaceDecoration?spaceDecoration?=?new?SpaceDecoration(dp2px(context,?10));
?spaceDecoration.setPaddingStart(false);
?rvPictrues.addItemDecoration(spaceDecoration);
?rvPictrues.setAdapter(pictureAdapter);
?pictureAdapter.bindToRecyclerView(rvPictrues);
??/**
?????*?dp轉px
?????*?@param?context
?????*?@param?dpVal
?????*?@return
?????*/
????public?static?int?dp2px(Context?context,?float?dpVal)?{
????????return?(int)?TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,?dpVal,
????context.getResources().getDisplayMetrics());
????}

SpaceDecoration

public?class?SpaceDecoration?extends?RecyclerView.ItemDecoration?{

????private?int?space;
????private?int?headerCount?=?-1;
????private?int?footerCount?=?Integer.MAX_VALUE;
????private?boolean?mPaddingEdgeSide?=?true;
????private?boolean?mPaddingStart?=?true;
????private?boolean?mPaddingHeaderFooter?=?false;
????private?ColorDrawable?mColorDrawable;
????private?boolean?mDrawLastItem?=?true;
????private?boolean?mDrawHeaderFooter?=?false;

????public?SpaceDecoration(int?space)?{
????????this.mColorDrawable?=?new?ColorDrawable(Color.parseColor("#e7e7e7"));
????????this.space?=?space;
????}
????public?SpaceDecoration(int?space,?int?color)?{
????????this.mColorDrawable?=?new?ColorDrawable(color);
????????this.space?=?space;
????}
????public?void?setPaddingEdgeSide(boolean?mPaddingEdgeSide)?{
????????this.mPaddingEdgeSide?=?mPaddingEdgeSide;
????}
????public?void?setPaddingStart(boolean?mPaddingStart)?{
????????this.mPaddingStart?=?mPaddingStart;
????}
????public?void?setPaddingHeaderFooter(boolean?mPaddingHeaderFooter)?{
????????this.mPaddingHeaderFooter?=?mPaddingHeaderFooter;
????}

@Override
public?void?getItemOffsets(Rect?outRect,?View?view,?RecyclerView?parent,?RecyclerView.State?state)?{
????int?position?=?parent.getChildAdapterPosition(view);
????int?spanCount?=?0;
????int?orientation?=?0;
??? int?spanIndex?=?0;
????int?headerCount?=?0,?footerCount?=?0;
????if?(parent.getAdapter()?instanceof?BaseQuickAdapter)?{
????????headerCount?=?((BaseQuickAdapter)?parent.getAdapter()).getHeaderLayoutCount();
????????footerCount?=?((BaseQuickAdapter)?parent.getAdapter()).getFooterLayoutCount();
????????}
????????RecyclerView.LayoutManager?layoutManager?=?parent.getLayoutManager();
????????if?(layoutManager?instanceof?StaggeredGridLayoutManager)?{
????????orientation?=?((StaggeredGridLayoutManager)?layoutManager).getOrientation();
????????spanCount?=?((StaggeredGridLayoutManager)?layoutManager).getSpanCount();
????????spanIndex?=?((StaggeredGridLayoutManager.LayoutParams)?view.getLayoutParams()).getSpanIndex();
????????}?else?if?(layoutManager?instanceof?GridLayoutManager)?{
????????orientation?=?((GridLayoutManager)?layoutManager).getOrientation();
????????spanCount?=?((GridLayoutManager)?layoutManager).getSpanCount();
????????spanIndex?=?((GridLayoutManager.LayoutParams)?view.getLayoutParams()).getSpanIndex();
????????}?else?if?(layoutManager?instanceof?LinearLayoutManager)?{
????????orientation?=?((LinearLayoutManager)?layoutManager).getOrientation();
????????spanCount?=?1;
????????spanIndex?=?0;
????????}

????????/**
?????????*?普通Item的尺寸
?????????*/
????????if?((position?>=?headerCount?&&?position?if?(orientation?==?VERTICAL)?{
????float?expectedWidth?=?(float)?(parent.getWidth()?-?space?*?(spanCount?+?(mPaddingEdgeSide???1?:?-1)))?/?spanCount;
????float?originWidth?=?(float)?parent.getWidth()?/?spanCount;
????float?expectedX?=?(mPaddingEdgeSide???space?:?0)?+?(expectedWidth?+?space)?*?spanIndex;
????float?originX?=?originWidth?*?spanIndex;
????outRect.left?=?(int)?(expectedX?-?originX);
????outRect.right?=?(int)?(originWidth?-?outRect.left?-?expectedWidth);
????if?(position?-?headerCount?????????outRect.top?=?space;
????}
????outRect.bottom?=?space;
????return;
}?else?{
????float?expectedHeight?=?(float)?(parent.getHeight()?-?space?*?(spanCount?+?(mPaddingEdgeSide???1?:?-1)))?/?spanCount;
????float?originHeight?=?(float)?parent.getHeight()?/?spanCount;
????float?expectedY?=?(mPaddingEdgeSide???space?:?0)?+?(expectedHeight?+?space)?*?spanIndex;
????float?originY?=?originHeight?*?spanIndex;
????outRect.bottom?=?(int)?(expectedY?-?originY);
????outRect.top?=?(int)?(originHeight?-?outRect.bottom?-?expectedHeight);
????if?(position?-?headerCount?????????outRect.left?=?space;
????}
????outRect.right?=?space;
????return;
}
????????}?else?if?(mPaddingHeaderFooter)?{
if?(orientation?==?VERTICAL)?{
????outRect.right?=?outRect.left?=?mPaddingEdgeSide???space?:?0;
????outRect.top?=?mPaddingStart???space?:?0;
}?else?{
????outRect.top?=?outRect.bottom?=?mPaddingEdgeSide???space?:?0;
????outRect.left?=?mPaddingStart???space?:?0;
}
????????}
????}

????@Override
????public?void?onDraw(Canvas?c,?RecyclerView?parent,?RecyclerView.State?state)?{
????????if?(parent.getAdapter()?==?null)?{
????????return;
????????}
????????int?orientation?=?0;
????????int?headerCount?=?0,?footerCount?=?0,?dataCount;

????????if?(parent.getAdapter()?instanceof?BaseQuickAdapter)?{
headerCount?=?((BaseQuickAdapter)?parent.getAdapter()).getHeaderLayoutCount();
footerCount?=?((BaseQuickAdapter)?parent.getAdapter()).getFooterLayoutCount();
dataCount?=?parent.getAdapter().getItemCount();
????????}?else?{
dataCount?=?parent.getAdapter().getItemCount();
????????}
????????int?dataStartPosition?=?headerCount;
????????int?dataEndPosition?=?headerCount?+?dataCount;

????????RecyclerView.LayoutManager?layoutManager?=?parent.getLayoutManager();
????????if?(layoutManager?instanceof?StaggeredGridLayoutManager)?{
orientation?=?((StaggeredGridLayoutManager)?layoutManager).getOrientation();
????????}?else?if?(layoutManager?instanceof?GridLayoutManager)?{
orientation?=?((GridLayoutManager)?layoutManager).getOrientation();
????????}?else?if?(layoutManager?instanceof?LinearLayoutManager)?{
orientation?=?((LinearLayoutManager)?layoutManager).getOrientation();
????????}
????????int?start,?end;
????????if?(orientation?==?OrientationHelper.VERTICAL)?{
start?=?parent.getPaddingLeft();
end?=?parent.getWidth()?-?parent.getPaddingRight();
????????}?else?{
start?=?parent.getPaddingTop();
end?=?parent.getHeight()?-?parent.getPaddingBottom();
????????}

????????int?childCount?=?parent.getChildCount();
????????for?(int?i?=?0;?i?View?child?=?parent.getChildAt(i);
int?position?=?parent.getChildAdapterPosition(child);

if?(position?>=?dataStartPosition?&&?position?1//數據項除了最后一項
????????||?(position?==?dataEndPosition?-?1?&&?mDrawLastItem)//數據項最后一項
????????||?(!(position?>=?dataStartPosition?&&?position?//header&footer且可繪制
????????)?{

????if?(orientation?==?OrientationHelper.VERTICAL)?{
????????RecyclerView.LayoutParams?params?=?(RecyclerView.LayoutParams)?child.getLayoutParams();
????????int?top?=?child.getBottom()?+?params.bottomMargin;
????????int?bottom?=?top;
????????mColorDrawable.setBounds(start,?top,?end,?bottom);
????????mColorDrawable.draw(c);
????}?else?{
????????RecyclerView.LayoutParams?params?=?(RecyclerView.LayoutParams)?child.getLayoutParams();
????????int?left?=?child.getRight()?+?params.rightMargin;
????????int?right?=?left;
????????mColorDrawable.setBounds(left,?start,?right,?end);
????????mColorDrawable.draw(c);
????}
}
????????}
????}
}

2.頂部欄部分

這里可以使用ItemDecoration,難點在于如何設置點擊點擊事件。感謝作者,提供了一種新的思路 StickyItemDecoration,這里只說如何使用,原理閱讀作者源碼即可。按照這個思路,我們可以將頭部布局單獨出來,這樣的話,處理點擊事件就很簡單。
activity布局

<RelativeLayoutandroid:layout_width="match_parent"android:layout_height="match_parent">


<android.support.v7.widget.RecyclerViewandroid:id="@+id/rv_pictrues"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@color/cf7f8fa"android:nestedScrollingEnabled="false"?/>

<com.leda.yunke.widget.sticky.StickyHeadContainerandroid:id="@+id/shc_pictrues"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@color/cffffff">

???<LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center_horizontal"android:orientation="vertical">

??????<TextViewandroid:id="@+id/tv_picture_time"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="8dp"android:layout_marginBottom="8dp"android:drawableRight="@mipmap/unfold"android:drawablePadding="10dp"android:gravity="center"android:text="2018年11月"android:textColor="@color/c969696"android:textSize="16sp"?/>

??????<TextView?style="@style/line_f3f3f3"?/>
??LinearLayout>

com.leda.yunke.widget.sticky.StickyHeadContainer>
RelativeLayout>

StickyHeadContainer

public?class?StickyHeadContainer?extends?ViewGroup?{

????private?int?mOffset;
????private?int?mLastOffset?=?Integer.MIN_VALUE;
????private?int?mLastStickyHeadPosition?=?Integer.MIN_VALUE;
????private?int?mLeft;
????private?int?mRight;
????private?int?mTop;
????private?int?mBottom;

????private?DataCallback?mDataCallback;

????public?StickyHeadContainer(Context?context)?{
????????this(context,?null);
????}
????public?StickyHeadContainer(Context?context,?AttributeSet?attrs)?{
????????this(context,?attrs,?0);
????}
????public?StickyHeadContainer(Context?context,?AttributeSet?attrs,?int?defStyleAttr)?{
????????super(context,?attrs,?defStyleAttr);
????????setOnClickListener(new?OnClickListener()?{
@Override
public?void?onClick(View?v)?{
????//?TODO:?2017/1/9?屏蔽點擊事件
}
????????});
????}

????@Override
????protected?void?onMeasure(int?widthMeasureSpec,?int?heightMeasureSpec)?{
????????int?desireHeight;
????????int?desireWidth;
????????int?count?=?getChildCount();
????????if?(count?!=?1)?{
throw?new?IllegalArgumentException("只允許容器添加1個子View!");
????????}
????????final?View?child?=?getChildAt(0);
????????//?測量子元素并考慮外邊距
????????measureChildWithMargins(child,?widthMeasureSpec,?0,?heightMeasureSpec,?0);
????????//?獲取子元素的布局參數
????????final?MarginLayoutParams?lp?=?(MarginLayoutParams)?child.getLayoutParams();
????????//?計算子元素寬度,取子控件最大寬度
????????desireWidth?=?child.getMeasuredWidth()?+?lp.leftMargin?+?lp.rightMargin;
????????//?計算子元素高度
????????desireHeight?=?child.getMeasuredHeight()?+?lp.topMargin?+?lp.bottomMargin;
????????//?考慮父容器內邊距
????????desireWidth?+=?getPaddingLeft()?+?getPaddingRight();
????????desireHeight?+=?getPaddingTop()?+?getPaddingBottom();
????????//?嘗試比較建議最小值和期望值的大小并取大值
????????desireWidth?=?Math.max(desireWidth,?getSuggestedMinimumWidth());
????????desireHeight?=?Math.max(desireHeight,?getSuggestedMinimumHeight());
????????//?設置最終測量值
????????setMeasuredDimension(resolveSize(desireWidth,?widthMeasureSpec),?resolveSize(desireHeight,?heightMeasureSpec));
????}

????@Override
????protected?void?onLayout(boolean?changed,?int?l,?int?t,?int?r,?int?b)?{

????????final?View?child?=?getChildAt(0);
????????MarginLayoutParams?lp?=?(MarginLayoutParams)?child.getLayoutParams();
????????final?int?paddingLeft?=?getPaddingLeft();
????????final?int?paddingTop?=?getPaddingTop();
????????mLeft?=?paddingLeft?+?lp.leftMargin;
????????mRight?=?child.getMeasuredWidth()?+?mLeft;
????????mTop?=?paddingTop?+?lp.topMargin?+?mOffset;
????????mBottom?=?child.getMeasuredHeight()?+?mTop;
????????child.layout(mLeft,?mTop,?mRight,?mBottom);
????}

????//?生成默認的布局參數
????@Override
????protected?LayoutParams?generateDefaultLayoutParams()?{
????????return?super.generateDefaultLayoutParams();
????}
????//?生成布局參數,將布局參數包裝成我們的
????@Override
????protected?LayoutParams?generateLayoutParams(LayoutParams?p)?{
????????return?new?MarginLayoutParams(p);
????}
????//?生成布局參數,從屬性配置中生成我們的布局參數
????@Override
????public?LayoutParams?generateLayoutParams(AttributeSet?attrs)?{
????????return?new?MarginLayoutParams(getContext(),?attrs);
????}
????//?查當前布局參數是否是我們定義的類型這在code聲明布局參數時常常用到
????@Override
????protected?boolean?checkLayoutParams(LayoutParams?p)?{
????????return?p?instanceof?MarginLayoutParams;
????}
????public?void?scrollChild(int?offset)?{
????????if?(mLastOffset?!=?offset)?{
mOffset?=?offset;
ViewCompat.offsetTopAndBottom(getChildAt(0),?mOffset?-?mLastOffset);
????????}
????????mLastOffset?=?mOffset;
????}
????protected?int?getChildHeight()?{
????????return?getChildAt(0).getHeight();
????}
????protected?void?onDataChange(int?stickyHeadPosition)?{
????????if?(mDataCallback?!=?null?&&?mLastStickyHeadPosition?!=?stickyHeadPosition)?{
mDataCallback.onDataChange(stickyHeadPosition);
????????}
????????mLastStickyHeadPosition?=?stickyHeadPosition;
????}
????public?void?reset()?{
????????mLastStickyHeadPosition?=?Integer.MIN_VALUE;
????}
????public?interface?DataCallback?{
????????void?onDataChange(int?pos);
????}
????public?void?setDataCallback(DataCallback?dataCallback)?{
????????mDataCallback?=?dataCallback;
????}
}

在activity中完整使用

StickyItemDecoration?stickyItemDecoration?=?new?StickyItemDecoration(shcPictrues,?PictureModel.PICTURE_TITLE);
stickyItemDecoration.setOnStickyChangeListener(new?OnStickyChangeListener()?{
@Override
public?void?onScrollable(int?offset)?{
????//可見時
????shcPictrues.scrollChild(offset);
????shcPictrues.setVisibility(View.VISIBLE);
}

@Override
public?void?onInVisible()?{
??//不可見時
????shcPictrues.reset();
????shcPictrues.setVisibility(View.INVISIBLE);
}
????????});
????????shcPictrues.setDataCallback(new?StickyHeadContainer.DataCallback()?{
@Override
public?void?onDataChange(int?pos)?{
??//數據更新
????List?listModels?=?pictureAdapter.getData();if?(listModels.size()?>?pos)?{
????????tvPictureTime.setText(listModels.get(pos).getDate());
????}
}
????????});//添加至rv
????????rvPictrues.addItemDecoration(stickyItemDecoration);
????????pictureAdapter?=?new?PictureAdapter(null);
????????rvPictrues.setLayoutManager(new?GridLayoutManager(context,?2));
????????rvPictrues.addItemDecoration(stickyItemDecoration);
????????SpaceDecoration?spaceDecoration?=?new?SpaceDecoration(DensityUtils.dp2px(context,?10));
????????spaceDecoration.setPaddingStart(false);
????????rvPictrues.addItemDecoration(spaceDecoration);
????????rvPictrues.setAdapter(pictureAdapter);
????????pictureAdapter.bindToRecyclerView(rvPictrues);

StickyItemDecoration

public?class?StickyItemDecoration?extends?RecyclerView.ItemDecoration?{

????private?int?mStickyHeadType;
????private?int?mFirstVisiblePosition;
????//private?int?mFirstCompletelyVisiblePosition;
????private?int?mStickyHeadPosition;
????private?int[]?mInto;
????private?RecyclerView.Adapter?mAdapter;
????private?StickyHeadContainer?mStickyHeadContainer;
????private?boolean?mEnableStickyHead?=?true;

????private?OnStickyChangeListener?mOnStickyChangeListener;
????public?void?setOnStickyChangeListener(OnStickyChangeListener?onStickyChangeListener){
????????this.mOnStickyChangeListener?=?onStickyChangeListener;
????}
????public?StickyItemDecoration(StickyHeadContainer?stickyHeadContainer,?int?stickyHeadType)?{
????????mStickyHeadContainer?=?stickyHeadContainer;
????????mStickyHeadType?=?stickyHeadType;
????}
????//?當我們調用mRecyclerView.addItemDecoration()方法添加decoration的時候,RecyclerView在繪制的時候,去會繪制decorator,即調用該類的onDraw和onDrawOver方法,
????//?1.onDraw方法先于drawChildren
????// 2.onDrawOver在drawChildren之后,一般我們選擇復寫其中一個即可。
????// 3.getItemOffsets 可以通過outRect.set()為每個Item設置一定的偏移量,主要用于繪制Decorator。
????@Override
????public?void?onDraw(Canvas?c,?RecyclerView?parent,?RecyclerView.State?state)?{
????????super.onDraw(c,?parent,?state);
????????checkCache(parent);
????????if?(mAdapter?==?null)?{
//?checkCache的話RecyclerView未設置之前mAdapter為空
return;
????????}
????????calculateStickyHeadPosition(parent);
????????if?(mEnableStickyHead?/*&&?mFirstCompletelyVisiblePosition?>?mStickyHeadPosition*/?&&?mFirstVisiblePosition?>=?mStickyHeadPosition?&&?mStickyHeadPosition?!=?-1)?{
View?belowView?=?parent.findChildViewUnder(c.getWidth()?/?2,?mStickyHeadContainer.getChildHeight()?+?0.01f);
mStickyHeadContainer.onDataChange(mStickyHeadPosition);
int?offset;
if?(isStickyHead(parent,?belowView)?&&?belowView.getTop()?>?0)?{
????offset?=?belowView.getTop()?-?mStickyHeadContainer.getChildHeight();
}?else?{
????offset?=?0;
}
if?(mOnStickyChangeListener!=null){
????mOnStickyChangeListener.onScrollable(offset);
}
????????}?else?{
if?(mOnStickyChangeListener!=null){
????mOnStickyChangeListener.onInVisible();
}
????????}
????}

????public?void?enableStickyHead(boolean?enableStickyHead)?{
????????mEnableStickyHead?=?enableStickyHead;
????????if?(!mEnableStickyHead)?{
mStickyHeadContainer.setVisibility(View.INVISIBLE);
????????}
????}

????private?void?calculateStickyHeadPosition(RecyclerView?parent)?{
????????final?RecyclerView.LayoutManager?layoutManager?=?parent.getLayoutManager();

????????// mFirstCompletelyVisiblePosition?=?findFirstCompletelyVisiblePosition(layoutManager);
????????//?獲取第一個可見的item位置
????????mFirstVisiblePosition?=?findFirstVisiblePosition(layoutManager);
????????//?獲取標簽的位置,
????????int?stickyHeadPosition?=?findStickyHeadPosition(mFirstVisiblePosition);
????????if?(stickyHeadPosition?>=?0?&&?mStickyHeadPosition?!=?stickyHeadPosition)?{
//?標簽位置有效并且和緩存的位置不同
mStickyHeadPosition?=?stickyHeadPosition;
????????}
????}

????/**
?????*?從傳入位置遞減找出標簽的位置
?????*?@param?formPosition
?????*?@return
?????*/
????private?int?findStickyHeadPosition(int?formPosition)?{
????????for?(int?position?=?formPosition;?position?>=?0;?position--)?{
????????//?位置遞減,只要查到位置是標簽,立即返回此位置
????????final?int?type?=?mAdapter.getItemViewType(position);
????????if?(isStickyHeadType(type))?{
????return?position;
}
????????}
????????return?-1;
????}

????/**
?????*?通過適配器告知類型是否為標簽
?????*?@param?type
?????*?@return
?????*/
????private?boolean?isStickyHeadType(int?type)?{
????????return?mStickyHeadType?==?type;
????}

????/**
?????*?找出第一個可見的Item的位置
?????*?@param?layoutManager
?????*?@return
?????*/
????private?int?findFirstVisiblePosition(RecyclerView.LayoutManager?layoutManager)?{
????????int?firstVisiblePosition?=?0;
????????if?(layoutManager?instanceof?GridLayoutManager)?{
firstVisiblePosition?=?((GridLayoutManager)?layoutManager).findFirstVisibleItemPosition();
????????}?else?if?(layoutManager?instanceof?LinearLayoutManager)?{
firstVisiblePosition?=?((LinearLayoutManager)?layoutManager).findFirstVisibleItemPosition();
????????}?else?if?(layoutManager?instanceof?StaggeredGridLayoutManager)?{
mInto?=?new?int[((StaggeredGridLayoutManager)?layoutManager).getSpanCount()];
((StaggeredGridLayoutManager)?layoutManager).findFirstVisibleItemPositions(mInto);
firstVisiblePosition?=?Integer.MAX_VALUE;
for?(int?pos?:?mInto)?{
????firstVisiblePosition?=?Math.min(pos,?firstVisiblePosition);
}
????????}
????????return?firstVisiblePosition;
????}

????/**
?????*?找出第一個完全可見的Item的位置
?????*?@param?layoutManager
?????*?@return
?????*/
????private?int?findFirstCompletelyVisiblePosition(RecyclerView.LayoutManager?layoutManager)?{
????????int?firstVisiblePosition?=?0;
????????if?(layoutManager?instanceof?GridLayoutManager)?{
firstVisiblePosition?=?((GridLayoutManager)?layoutManager).findFirstCompletelyVisibleItemPosition();
????????}?else?if?(layoutManager?instanceof?LinearLayoutManager)?{
firstVisiblePosition?=?((LinearLayoutManager)?layoutManager).findFirstCompletelyVisibleItemPosition();
????????}?else?if?(layoutManager?instanceof?StaggeredGridLayoutManager)?{
mInto?=?new?int[((StaggeredGridLayoutManager)?layoutManager).getSpanCount()];
((StaggeredGridLayoutManager)?layoutManager).findFirstCompletelyVisibleItemPositions(mInto);
firstVisiblePosition?=?Integer.MAX_VALUE;
for?(int?pos?:?mInto)?{
????firstVisiblePosition?=?Math.min(pos,?firstVisiblePosition);
}
????????}
????????return?firstVisiblePosition;
????}

????/**
?????*?檢查緩存
?????*
?????*?@param?parent
?????*/
????private?void?checkCache(final?RecyclerView?parent)?{

????????final?RecyclerView.Adapter?adapter?=?parent.getAdapter();
????????if?(mAdapter?!=?adapter)?{
mAdapter?=?adapter;
//?適配器為null或者不同,清空緩存
mStickyHeadPosition?=?-1;

mAdapter.registerAdapterDataObserver(new?RecyclerView.AdapterDataObserver()?{
????@Override
????public?void?onChanged()?{
????????reset();
????}
????@Override
????public?void?onItemRangeChanged(int?positionStart,?int?itemCount)?{
????????reset();
????}
????@Override
????public?void?onItemRangeChanged(int?positionStart,?int?itemCount,?Object?payload)?{
????????reset();
????}
????@Override
????public?void?onItemRangeInserted(int?positionStart,?int?itemCount)?{
????????reset();
????}
????@Override
????public?void?onItemRangeRemoved(int?positionStart,?int?itemCount)?{
????????reset();
????}
????@Override
????public?void?onItemRangeMoved(int?fromPosition,?int?toPosition,?int?itemCount)?{
????????reset();
????}
});
????????}
????}

????private?void?reset()?{
????????mStickyHeadContainer.reset();
????}

????/**
?????*?查找到view對應的位置從而判斷出是否標簽類型
?????*?@param?parent
?????*?@param?view
?????*?@return
?????*/
????private?boolean?isStickyHead(RecyclerView?parent,?View?view)?{
????????final?int?position?=?parent.getChildAdapterPosition(view);
????????if?(position?==?RecyclerView.NO_POSITION)?{
return?false;
????????}
????????final?int?type?=?mAdapter.getItemViewType(position);
????????return?isStickyHeadType(type);
????}
}

3.點擊頂部欄彈窗

偷個懶,不貼代碼了。

最后,就是組裝數據然后設置給pictureAdapter即可。

完整源碼
https://github.com/18702953620/PicRvDemo

大家都在看

Android自定義頻道選擇器、頻道定制

Flutter 學習及實戰分享

你必須要掌握的Android冷啟動優化

Android自定義View:快遞時間軸實現

歡迎前往安卓巴士博客區投稿,技術成長于分享

期待巴友留言,共同探討學習

總結

以上是生活随笔為你收集整理的android实现评论列表_【Android视图效果】分组列表实现吸顶效果的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。