摘要:是規(guī)則的瀑布流。普通的尺寸會(huì)出現(xiàn)錯(cuò)位的問題索引這個(gè)是右邊這個(gè)是左邊間距解決辦法,可以通過里的來判斷,這個(gè)方法不管你高度怎樣,他都是左右左右開始排列的。
目錄介紹
01.規(guī)則瀑布流實(shí)現(xiàn)
02.不規(guī)則瀑布流實(shí)現(xiàn)
2.1 實(shí)現(xiàn)方式
2.2 遇到問題
03.瀑布流上拉加載
04.給瀑布流設(shè)置分割線
05.自定義Manager崩潰
06.如何避免刷新抖動(dòng)
07.為何有時(shí)出現(xiàn)跳動(dòng)
08.瀑布流圖片優(yōu)化
09.onBindViewHolder優(yōu)化
10.瀑布流item點(diǎn)擊事件優(yōu)化
11.Glide加載優(yōu)化
12.建議指定圖片的寬高
歡迎同行探討瀑布流極致優(yōu)化方案
如果同行看到這篇文章,有好的瀑布流優(yōu)化方案,歡迎給出建議,或者給鏈接也可以。
需求:
瀑布流大概有10來中不同type的item視圖,然后視圖是根據(jù)動(dòng)態(tài)設(shè)置寬高,服務(wù)器會(huì)返回比例
瀑布流中item需要切割圓角
目前使用glide加載圖片
產(chǎn)品說讓參考抖音快手類的app,讓瀑布流滑動(dòng)效果特別流暢……但目前遇到問題是滑動(dòng)十幾頁沒什么問題,但是滑動(dòng)三四十頁的時(shí)候會(huì)出現(xiàn)卡頓。歡迎同行給出建議!
好消息
博客筆記大匯總【16年3月到至今】,包括Java基礎(chǔ)及深入知識(shí)點(diǎn),Android技術(shù)博客,Python學(xué)習(xí)筆記等等,還包括平時(shí)開發(fā)中遇到的bug匯總,當(dāng)然也在工作之余收集了大量的面試題,長(zhǎng)期更新維護(hù)并且修正,持續(xù)完善……開源的文件是markdown格式的!同時(shí)也開源了生活博客,從12年起,積累共計(jì)N篇[近100萬字,陸續(xù)搬到網(wǎng)上],轉(zhuǎn)載請(qǐng)注明出處,謝謝!
鏈接地址:https://github.com/yangchong2...
如果覺得好,可以star一下,謝謝!當(dāng)然也歡迎提出建議,萬事起于忽微,量變引起質(zhì)變!
01.規(guī)則瀑布流實(shí)現(xiàn)
最簡(jiǎn)單規(guī)則瀑布流實(shí)現(xiàn),下面這種是設(shè)置3列數(shù)據(jù),然后組數(shù)據(jù)高度是相同的。是規(guī)則的瀑布流。
adapter = new ImageAdapter(this);
recyclerView.setAdapter(adapter);
GridLayoutManager gridLayoutManager = new GridLayoutManager(this,3);
gridLayoutManager.setSpanSizeLookup(adapter.obtainGridSpanSizeLookUp(3));
recyclerView.setLayoutManager(gridLayoutManager);
SpaceViewItemLine itemDecoration = new SpaceViewItemLine(20);
recyclerView.addItemDecoration(itemDecoration);
02.不規(guī)則瀑布流實(shí)現(xiàn)
最簡(jiǎn)單的不規(guī)則瀑布流實(shí)現(xiàn),下面這種是設(shè)置2列數(shù)據(jù),然后數(shù)據(jù)的高度都不同,圖片的高度隨機(jī)。
adapter = new ImageStageredAdapter(this);
recyclerView.setAdapter(adapter);
StaggeredGridLayoutManager staggeredGridLayoutManager =
new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(staggeredGridLayoutManager);
SpaceViewItemLine itemDecoration = new SpaceViewItemLine(20);
recyclerView.addItemDecoration(itemDecoration);
這里是偽代碼。假設(shè)設(shè)置不同高度,代碼如下。簡(jiǎn)單設(shè)置不同圖片高度不同,這個(gè)是在onBindViewHolder中操作。
ViewGroup.LayoutParams params = imgPicture.getLayoutParams();
//假設(shè)有多種不同的類型
int type = getAdapterPosition()%5;
//計(jì)算View的高度
int height = 300;
switch (type){
case 0: height = 500; break; case 1: height = 750; break; case 2: height = 880; break; case 3: height = 360; break; case 4: height = 660; break; default: break;
}
params.height = height;
imgPicture.setLayoutParams(params);
2.2 遇到問題
遇到問題
1.RecyclerView 如何實(shí)現(xiàn)下拉加載更多;
2.StaggeredGridLayoutManager 顯示加載更多的時(shí)候,加載更多作為最后一個(gè)item沒有多帶帶占滿屏幕寬度,只顯示為一個(gè)item的寬度;
3.StaggeredGridLayoutManager 如何隨機(jī)設(shè)置item的高度;
4.StaggeredGridLayoutManager 上拉加載數(shù)據(jù)刷新UI時(shí),由于高度隨機(jī),造成頁面item抖動(dòng)問題;
5.RecyclerView莫名的Inconsistency detected崩潰;
卡頓和內(nèi)存釋放
瀑布流滑動(dòng)幾頁感覺還行,但是一旦滑動(dòng)了三四十頁,就感覺頁面有些卡頓了。
03.瀑布流上拉加載
首先添加監(jiān)聽方法,添加了這個(gè)方法就可以上拉加載更多數(shù)據(jù)呢。但是發(fā)現(xiàn)還有點(diǎn)問題,上拉加載更多的那個(gè)布局只是占1/spanCount列,這樣顯得特別難看。那么該如何處理呢,接著往下看……
首先要能夠監(jiān)聽recyclerView滑動(dòng)事件;
判斷recyclerView是否滑動(dòng)到最后一個(gè)item;
recyclerView 加載更多RecyclerView.Adapter的設(shè)置處理:RecyclerView.Adapter的相關(guān)代碼,主要定義兩個(gè)ViewHolder類型,footType表示為底部的viewHolder,normalType表示為正常的item的viewHolder,根據(jù)position的不同來顯示不同的viewholder;
// 實(shí)現(xiàn)上拉加載重要步驟,設(shè)置滑動(dòng)監(jiān)聽器,RecyclerView自帶的ScrollListener
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); // 在newState為滑到底部時(shí) if (newState == RecyclerView.SCROLL_STATE_IDLE) { // 如果沒有隱藏footView,那么最后一個(gè)條目的位置就比我們的getItemCount少1,自己可以算一下 if (!adapter.isFadeTips() && lastVisibleItem + 1 == adapter.getItemCount()) { handler.postDelayed(new Runnable() { @Override public void run() { updateRecyclerView(adapter.getRealLastPosition(), adapter.getRealLastPosition() + PAGE_COUNT); } }, 2500); } // 如果隱藏了提示條,我們又上拉加載時(shí),那么最后一個(gè)條目就要比getItemCount要少2 if (adapter.isFadeTips() && lastVisibleItem + 2 == adapter.getItemCount()) { handler.postDelayed(new Runnable() { @Override public void run() { updateRecyclerView(adapter.getRealLastPosition(), adapter.getRealLastPosition() + PAGE_COUNT); } }, 2500); } } } @Override public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); // 在滑動(dòng)完成后,拿到最后一個(gè)可見的item的位置 int positions[] = staggeredGridLayoutManager.findLastVisibleItemPositions(null); for(int pos : positions){ if(pos > lastVisibleItem){ lastVisibleItem = pos;//得到最后一個(gè)可見的item的position } } }
});
因?yàn)槭瞧俨剂鳎O(shè)置footerView占據(jù)一行,這個(gè)需要這樣設(shè)置,代碼如下所示
@Override
public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
super.onViewAttachedToWindow(holder); ViewGroup.LayoutParams layoutParams = holder.itemView.getLayoutParams(); if (layoutParams != null && layoutParams instanceof StaggeredGridLayoutManager.LayoutParams) { StaggeredGridLayoutManager.LayoutParams params = (StaggeredGridLayoutManager.LayoutParams) layoutParams; int position = holder.getLayoutPosition(); //如果是上拉加載更多類型,則設(shè)置setFullSpan為true,那么它就會(huì)占一行 if (getItemViewType(position) == footType) { params.setFullSpan(true); } }
}
04.給瀑布流設(shè)置分割線
先來看看出現(xiàn)錯(cuò)位,分割線出現(xiàn)問題的代碼。下面這種方式根據(jù)childCount來判斷奇數(shù)和偶數(shù)設(shè)置的不同間距。
那么比如說當(dāng)為奇數(shù)時(shí),設(shè)置該item到左為20,到右為5;當(dāng)為偶數(shù)時(shí),該item到左為5,到右為20。
如果奇數(shù)的item都在左邊,偶數(shù)的item都在右邊,那么間距就沒有問題。
如果第一個(gè)item在左邊【高度很高】,第2個(gè),第3個(gè),第4個(gè)item都在右邊,第5個(gè)在左邊……那么思考一下,這個(gè)時(shí)候第3個(gè)item在右邊,那么就會(huì)造成間距不規(guī)則。
顯然不能根據(jù)奇數(shù)或者偶數(shù)來設(shè)置item左右間距的大小的,會(huì)出現(xiàn)錯(cuò)位。
recyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {
@Override public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { super.getItemOffsets(outRect, view, parent, state); int position = parent.getChildAdapterPosition(view); int spanCount = 0; int spanIndex = 0; RecyclerView.Adapter adapter = parent.getAdapter(); RecyclerView.LayoutManager layoutManager = parent.getLayoutManager(); if (adapter==null || layoutManager==null){ return; } if (layoutManager instanceof StaggeredGridLayoutManager){ spanCount = ((StaggeredGridLayoutManager) layoutManager).getSpanCount(); spanIndex = ((StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams()).getSpanIndex(); } //普通Item的尺寸 //TODO 會(huì)出現(xiàn)錯(cuò)位的問題 int itemCount = adapter.getItemCount(); int childCount = layoutManager.getChildCount(); RefreshLogUtils.d("SpaceViewItemLine--count--"+itemCount + "-----"+childCount+"---索引--"+position+"---"+spanIndex); if (position});
解決辦法,可以通過StaggeredGridLayoutManager.LayoutParams里的getSpanIndex()來判斷,這個(gè)方法不管你高度怎樣,他都是左右左右開始排列的。
recyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {@Override public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { super.getItemOffsets(outRect, view, parent, state); int position = parent.getChildAdapterPosition(view); int spanCount = 0; int spanIndex = 0; RecyclerView.Adapter adapter = parent.getAdapter(); RecyclerView.LayoutManager layoutManager = parent.getLayoutManager(); if (adapter==null || layoutManager==null){ return; } if (layoutManager instanceof StaggeredGridLayoutManager){ spanCount = ((StaggeredGridLayoutManager) layoutManager).getSpanCount(); spanIndex = ((StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams()).getSpanIndex(); } //普通Item的尺寸 int itemCount = adapter.getItemCount(); int childCount = layoutManager.getChildCount(); RefreshLogUtils.d("SpaceViewItemLine--count--"+itemCount + "-----"+childCount+"---索引--"+position+"---"+spanIndex); if (position});
05.自定義Manager崩潰RecyclerView莫名的Inconsistency detected崩潰;
出現(xiàn)這個(gè)異常原因:
使用RecyclerView加官方下拉刷新的時(shí)候,如果綁定的List對(duì)象在更新數(shù)據(jù)之前進(jìn)行了clear,而這時(shí)用戶緊接著迅速上滑RV,就會(huì)造成崩潰,而且異常不會(huì)報(bào)到你的代碼上,屬于RV內(nèi)部錯(cuò)誤。
自定義一個(gè)CustomStaggeredGridLayoutManager 在onLayoutChildren對(duì)異常進(jìn)行捕獲:
public class CustomStaggeredGridLayoutManager extends StaggeredGridLayoutManager {private static final String TAG = "LOG_CustomStaggered"; public CustomStaggeredGridLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } public CustomStaggeredGridLayoutManager(int spanCount, int orientation) { super(spanCount, orientation); } @Override public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { try { super.onLayoutChildren(recycler, state); }catch (Exception e){ Log.i(TAG, "onLayoutChildren: e " + e.getMessage()); } }}
關(guān)于StaggeredGridLayoutManager異常說明
06.如何避免刷新抖動(dòng)StaggeredGridLayoutManager 上拉加載數(shù)據(jù)刷新UI時(shí),由于高度隨機(jī),造成頁面item抖動(dòng)問題; 這里由于直接調(diào)用 notifyDataSetChanged();那么是全局刷新,而刷新的時(shí)候item的高度重新隨機(jī)分配,導(dǎo)致數(shù)據(jù)刷新的時(shí)候會(huì)造成抖動(dòng)。建議采用notifyItemRangeChanged進(jìn)行局部刷新:
public void setDatas(List mDatas ) {this.dataList = mDatas; notifyDataSetChanged();}
/**
注意這個(gè)是未關(guān)注時(shí)候的瀑布流刷新數(shù)據(jù)
上拉加載更多時(shí),建議刷新上拉加載那一部分?jǐn)?shù)據(jù)即可,不用刷新所有數(shù)據(jù)
@param puBuList 瀑布流集合
*/
public void setMoreData(ListpuBuList) { int start = mayContentList.size(); if (puBuList!=null && puBuList.size()!=0){ mayContentList.addAll(puBuList); int end = mayContentList.size(); mRecommendPuBuAdapter.notifyItemRangeInserted(start,end); }}
07.為何有時(shí)出現(xiàn)跳動(dòng)由于我們加載的圖片高度不確定(寬度確定因?yàn)榭梢愿鶕?jù)屏幕寬度和每行Item數(shù)目進(jìn)行等分),而當(dāng)我們向RecyclerView下方滑動(dòng)一段距離后,由于ViewHolder的回收機(jī)制,item的尺寸并不確定,滑回到上方時(shí)Item需要重新自行繪制,于是這個(gè)又導(dǎo)致重繪,所以會(huì)有閃爍、跳動(dòng)、空白等問題。說到底,只要我們?cè)谥乩L前確定了Item的尺寸,那么就可以避免Item去重新計(jì)算自己的尺寸,就可以避免重繪導(dǎo)致的諸多問題。
08.瀑布流圖片優(yōu)化具體優(yōu)化方案
第一步:減少布局嵌套,并且在拿到服務(wù)器的尺寸后,在onBindViewHolder中給圖片控件設(shè)置寬高時(shí),避免創(chuàng)建大量臨時(shí)的LayoutParams對(duì)象
第二步:使用glide加載,綁定activity或者fragment的生命周期,盡量不用用全局上下文或者靜態(tài)上下文。注意with()方法中傳入的實(shí)例會(huì)決定Glide加載圖片的生命周期,如果傳入的是Activity或者Fragment的實(shí)例,那么當(dāng)這個(gè)Activity或Fragment被銷毀的時(shí)候,圖片加載也會(huì)停止。如果傳入的是ApplicationContext,那么只有當(dāng)應(yīng)用程序被殺掉的時(shí)候,圖片加載才會(huì)停止。
第三步:對(duì)于list條目,尤其是瀑布流,不建議使用TransitionOptions來加載設(shè)置的動(dòng)畫,尤其是不要使用自己自定義的動(dòng)畫
避免使用圓角的ImageView
在實(shí)際項(xiàng)目?jī)?nèi),經(jīng)常會(huì)用到一些帶圓角的圖片,或者直接就是圓形的圖片。圓形的圖片,多數(shù)用于一些用戶的頭像之類的顯示效果。
而在 Android 下,也有大量的類似 XxxImageView 的開源控件,用于操作 Bitmap 以達(dá)到一個(gè)圓角圖片的效果,例如 Github 上比較火的 RoundedImageView。
它們大部分的原理,是接收到你傳遞的 Bitmap ,然后再輸出一個(gè)與原來 Bitmap 等大的新 Bitmap ,在此基礎(chǔ)之上,進(jìn)行圓角的一些處理,這就導(dǎo)致了,實(shí)際上會(huì)在內(nèi)存中,多持有一個(gè) Bitmap ,一下一張圖片占用的內(nèi)存就被加倍了。
所以既然已經(jīng)選擇使用Glide,推薦使用glide-transformations這個(gè)開源庫(kù)配合使用,glide-transformations 利用 Glide 的 bitmapTransfrom() 接口,實(shí)現(xiàn)對(duì)加載的 Bitmap 的進(jìn)行一些變換操作。glide-transformations提供一系類對(duì)加載的圖片的變換操作,從形狀變換到色彩變換,全部支持,基本上滿足大部分開發(fā)需要,并且它會(huì)復(fù)用 Glide 的 BitmapPool ,來達(dá)到節(jié)約內(nèi)存的目的。
09.onBindViewHolder優(yōu)化在這個(gè)方法中,主要是做數(shù)據(jù)綁定到View視圖。由于瀑布流會(huì)有多種不同type類型的視圖,有些需要設(shè)置寬高,有的則要從服務(wù)器拿到寬高數(shù)據(jù)然后動(dòng)態(tài)修改視圖屬性。因此關(guān)于寬高的計(jì)算其實(shí)還可以做一些優(yōu)化。
先來看一下最初的代碼,這里只展示動(dòng)態(tài)設(shè)置寬高的代碼。如下所示
看了下面代碼,會(huì)發(fā)現(xiàn)這些問題。第一,頻繁計(jì)算瀑布流中不同類型的寬度,該寬度是屏幕寬度減去間距,然后是除以2,瀑布流為兩行。第二,頻繁創(chuàng)建LayoutParams對(duì)象,然后設(shè)置寬高的屬性。
@Override
public void onBindViewHolder(@NonNull BaseViewHolder holder, int position) {super.onBindViewHolder(holder, position); int width = 0; int height = 0; switch (holder.getItemViewType()) { case BasePubuBean.content_type9: break; //發(fā)布的短視頻的寬高也是限制為3:4 case BasePubuBean.content_type2: int videoWidth = (SysUtils.getScreenWidth((Activity) mContext)-SysUtils.Dp2Px(mContext,43)) / 2; int videoHeight = (int) (videoWidth * (4/3.0f)); RelativeLayout.LayoutParams puBuParams2 = ViewUtils.getPuBuParams(mContext, videoWidth, videoHeight); holder.getView(R.id.mImageView).setLayoutParams(puBuParams2); break; //活動(dòng)頭圖,自適應(yīng)拿到圖片寬度,然后寬高比是4:3 case BasePubuBean.content_type4: int imageWidth = (SysUtils.getScreenWidth((Activity) mContext)-SysUtils.Dp2Px(mContext,43)) / 2; int imageHeight = (int) (imageWidth * (3/4.0f)); RelativeLayout.LayoutParams puBuParams4 = ViewUtils.getPuBuParams(mContext,imageWidth, imageHeight); holder.getView(R.id.mImageView).setLayoutParams(puBuParams4); break; //推薦車系,寬高比是4:3 case BasePubuBean.content_type10: int imageWidth10 = (SysUtils.getScreenWidth((Activity) mContext)-SysUtils.Dp2Px(mContext,43)) / 2; int imageHeight10 = (int) (imageWidth10 * (3/4.0f)); ImageView imageView = holder.getView(R.id.mImageView); ViewGroup.LayoutParams layoutParams = imageView.getLayoutParams(); layoutParams.height = imageHeight10; layoutParams.width = imageWidth10; imageView.setLayoutParams(layoutParams); break; case BasePubuBean.content_type1: case BasePubuBean.content_type3: case BasePubuBean.content_type5: case BasePubuBean.content_type6: case BasePubuBean.content_type7: case BasePubuBean.content_type8: int imageWidth = (SysUtils.getScreenWidth((Activity) mContext)-SysUtils.Dp2Px(mContext,43)) / 2; width = mData.get(position).getWidth(); height = mData.get(position).getHeight(); if( width!=0 && height!=0){ RelativeLayout.LayoutParams puBuParams1 = ViewUtils.getPuBuParams(mContext,imageWidth, height); holder.getView(R.id.mImageView).setLayoutParams(puBuParams1); }else { int video_width = mData.get(position).getVideo_width(); int video_height = mData.get(position).getVideo_height(); if(video_width!=0 && video_height!=0){ holder.getView(R.id.mImageView).setLayoutParams(ViewUtils.getPuBuParams( mContext,imageWidth, video_height)); }else { holder.getView(R.id.mImageView).setLayoutParams(ViewUtils.getPuBuParams( mContext,imageWidth , 125)); } } break; default: break; }}
然后看一下優(yōu)化后的代碼。
那么下面這種代碼,就可以極大減少頻繁的動(dòng)態(tài)計(jì)算寬高等屬性。通過imageView34.getLayoutParams()方式獲取layoutParams,就可以避免上面那種通過new創(chuàng)建大量的對(duì)象。要知道,平時(shí)像上面代碼那么用也沒問題,但是在recyclerView瀑布流中,也可以細(xì)微優(yōu)化一下。
@Override
public void onBindViewHolder(@NonNull BaseViewHolder holder, int position) {super.onBindViewHolder(holder, position); //獲取屏幕寬度 if (screenWidth==0){ screenWidth = SysUtils.getScreenWidth((Activity) mContext); } //16+11+16 if (padding==0){ padding = SysUtils.Dp2Px(mContext,43); } if (imageWidth==0){ imageWidth = (screenWidth-padding) / 2; } //寬高為3:4的圖片高度 if (imageHeight34 ==0){ imageHeight34 = (int) (imageWidth * (4/3.0f)); } //寬高4:3的圖片高度 if (imageHeight43 ==0){ imageHeight43 = (int) (imageWidth * (3/4.0f)); } //長(zhǎng)寬為16:9的圖片高度 if (imageHeight169 ==0){ imageHeight169 = (int) (imageWidth * (16/9.0f)); } switch (holder.getItemViewType()) { case BasePubuBean.content_type9: break; //發(fā)布的短視頻的是限制為3:4 case BasePubuBean.content_type2: int width34 = imageWidth; int height34 = imageHeight34; ImageView imageView34 = holder.getView(R.id.mImageView); ViewGroup.LayoutParams layoutParams34 = imageView34.getLayoutParams(); layoutParams34.height = height34; layoutParams34.width = width34; imageView34.setLayoutParams(layoutParams34); break; //行情文章也是4:3 case BasePubuBean.content_type8: //活動(dòng)頭圖,自適應(yīng)拿到圖片寬度,然后是4:3 case BasePubuBean.content_type4: //文章詳情也是4:3 case BasePubuBean.content_type5: //推薦車系是4:3 case BasePubuBean.content_type10: int width43 = imageWidth; int height43 = imageHeight43; ImageView imageView43 = holder.getView(R.id.mImageView); ViewGroup.LayoutParams layoutParams43 = imageView43.getLayoutParams(); layoutParams43.height = height43; layoutParams43.width = width43; imageView43.setLayoutParams(layoutParams43); break; //長(zhǎng)視頻16:9 case BasePubuBean.content_type3: int width169 = imageWidth; int height169 = imageHeight169; ImageView imageView169= holder.getView(R.id.mImageView); ViewGroup.LayoutParams layoutParams169 = imageView169.getLayoutParams(); layoutParams169.height = height169; layoutParams169.width = width169; imageView169.setLayoutParams(layoutParams169); break; case BasePubuBean.content_type1: case BasePubuBean.content_type6: case BasePubuBean.content_type7: ImageView imageView= holder.getView(R.id.mImageView); int width = mData.get(position).getWidth(); int height = mData.get(position).getHeight(); if( width!=0 && height!=0){ //這種方式會(huì)創(chuàng)建大量的對(duì)象 //RelativeLayout.LayoutParams puBuParams1 = ViewUtils.getPuBuParams(mContext,width, height); //holder.getView(R.id.mImageView).setLayoutParams(puBuParams1); ViewGroup.LayoutParams layoutParams = imageView.getLayoutParams(); layoutParams.height = height; layoutParams.width = imageWidth; imageView.setLayoutParams(layoutParams); }else { int videoWidth = mData.get(position).getVideo_width(); int videoHeight = mData.get(position).getVideo_height(); if(videoWidth!=0 && videoHeight!=0){ ViewGroup.LayoutParams layoutParams = imageView.getLayoutParams(); layoutParams.height = videoHeight; layoutParams.width = imageWidth; imageView.setLayoutParams(layoutParams); //holder.getView(R.id.mImageView).setLayoutParams(ViewUtils.getPuBuParams( // mContext,imageWidth, video_height)); }else { ViewGroup.LayoutParams layoutParams = imageView.getLayoutParams(); layoutParams.height = 125; layoutParams.width = imageWidth; imageView.setLayoutParams(layoutParams); //holder.getView(R.id.mImageView).setLayoutParams(ViewUtils.getPuBuParams( // mContext,imageWidth,125)); } } break; default: break; }}
10.瀑布流item點(diǎn)擊事件優(yōu)化關(guān)于rv設(shè)置item條目點(diǎn)擊事件有兩種方式: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()); } } });}
3.在ViewHolder中寫
class MyViewHolder extends RecyclerView.ViewHolder {MyViewHolder(final View itemView) { super(itemView); itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (listener != null) { listener.onItemClick(itemView, getAdapterPosition()); } } }); }}
onBindViewHolder() 中頻繁創(chuàng)建新的 onClickListener 實(shí)例沒有必要,建議實(shí)際開發(fā)中應(yīng)該在 onCreateViewHolder() 中每次為新建的 View 設(shè)置一次就行。
11.Glide加載優(yōu)化glide優(yōu)化方案代碼,滑動(dòng)時(shí)候禁止加載圖片,停止滑動(dòng)后開始恢復(fù)加載圖片。
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {@Override public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); if (newState == RecyclerView.SCROLL_STATE_IDLE) { LogUtil.i("yc---initRecyclerView"+ "恢復(fù)Glide加載圖片"); Glide.with(RecommendFragment.this).resumeRequests(); }else { LogUtil.i("yc---initRecyclerView"+"禁止Glide加載圖片"); Glide.with(RecommendFragment.this).pauseRequests(); } }});
綁定控件的生命周期
當(dāng)一個(gè)界面離開之后,我們更希望當(dāng)前的圖片取消加載,那么 Glide 是怎么做到的呢?當(dāng)在recyclerView列表中,item從可見滑動(dòng)到不可見的時(shí)候,如何控制圖片請(qǐng)求的生命周期,那么可以與控件生命周期相綁定。
Glide.with(mImageView).load(imgUrl) .apply(RequestOptions.bitmapTransform(multiTransformation) .placeholder(R.drawable.glide_load) .error(R.drawable.glide_error)) .into(mImageView);低內(nèi)存的情況下主動(dòng)清除緩存,看最新版本glide,其實(shí)源碼中以及處理了下面相關(guān)的邏輯。
/**低內(nèi)存的時(shí)候執(zhí)行
*/
@Override
public void onLowMemory() {Log.d("Application", "onLowMemory"); super.onLowMemory(); Glide.get(this).clearMemory();}
/**
HOME鍵退出應(yīng)用程序
程序在內(nèi)存清理的時(shí)候執(zhí)行
*/
@Override
public void onTrimMemory(int level) {Log.d("Application", "onTrimMemory"); super.onTrimMemory(level); if (level == TRIM_MEMORY_UI_HIDDEN){ Glide.get(this).clearMemory(); } Glide.get(this).trimMemory(level);}
12.建議指定圖片的寬高Glide設(shè)置圖片控件wrap_content不建議支持的問題
官方說,不支持并且不建議imageview設(shè)置wrap_content。因?yàn)檫@樣glide不知道要加載多大的圖片給我們才好,在他的接口(Sizes and dimensions)中也有體現(xiàn)。普通的imageview其實(shí)也還好,如果放在列表(RecyclerView)中, 由于我們并不知道目標(biāo)圖片大小是多大的,所以我們選擇了wrap_content,那么在上下來回滾動(dòng)過程中,就會(huì)導(dǎo)致圖片一會(huì)大一會(huì)小的bug.
官方 issue 作者回答如下:
所以,如果可以,那么還是指定圖片控件的寬高吧!
Don"t use wrap_content.Even if you don"t use Glide, wrap_content necessarily means that the size of your views in RecyclerView are going to change from item to item. That"s going to cause all sorts of UI weirdness.
One option is to try to obtain the image dimensions in whatever metadata you"re using to populate the RecyclerView. Then you can set a fixed View size in onBindViewHolder so the view size at least doesn"t change when the image is loaded. You"re still likely to see weird scroll bar behavior though.
If nothing else, you can always pick a uniform size that"s large enough for all items and use the same consistent size for every item.
For the image file size, you can downscale or upscale by setting the ImageView size manually to 150dp x 150dp. Ultimately either you need uniform view sizes or predetermined view sizes. There"s nothing else that will prevent content from expanding or shrinking in your RecyclerView.
For the placeholder bit, I think that will be fixed by 648c58e, you can check by trying the 4.2.0-SNAPSHOT version: http://bumptech.github.io/gli...
01.關(guān)于博客匯總鏈接1.技術(shù)博客匯總
2.開源項(xiàng)目匯總
3.生活博客匯總
4.喜馬拉雅音頻匯總
5.其他匯總
02.關(guān)于我的博客github:https://github.com/yangchong211
知乎:https://www.zhihu.com/people/...
簡(jiǎn)書:http://www.jianshu.com/u/b7b2...
csdn:http://my.csdn.net/m0_37700275
喜馬拉雅聽書:http://www.ximalaya.com/zhubo...
開源中國(guó):https://my.oschina.net/zbj161...
泡在網(wǎng)上的日子:http://www.jcodecraeer.com/me...
郵箱:yangchong211@163.com
阿里云博客:https://yq.aliyun.com/users/a... 239.headeruserinfo.3.dT4bcV
segmentfault頭條:https://segmentfault.com/u/xi...
掘金:https://juejin.im/user/593943...
業(yè)余demo鏈接:https://github.com/yangchong2...
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/76076.html
摘要:支持復(fù)雜頁面,例如添加自定義頭部和底部布局,支持橫向滑動(dòng),還可以支持粘貼頭部類似微信好友分組,支持不規(guī)則瀑布流效果,支持側(cè)滑刪除功能。支持粘貼頭部的需求效果,這種效果類似微信好友分組的那種功能界面。 目錄介紹 1.復(fù)雜頁面庫(kù)介紹 2.本庫(kù)優(yōu)勢(shì)亮點(diǎn) 2.1 支持多種狀態(tài)切換管理 2.2 支持添加多個(gè)header和footer 2.3 支持側(cè)滑功能和拖拽移動(dòng) 2.4 其他亮點(diǎn)介紹 ...
摘要:支持復(fù)雜頁面,例如添加自定義頭部和底部布局,支持橫向滑動(dòng),還可以支持粘貼頭部類似微信好友分組,支持不規(guī)則瀑布流效果,支持側(cè)滑刪除功能。十分方便實(shí)現(xiàn)復(fù)雜的布局頁面,結(jié)構(gòu)上層次分明,便于維護(hù)。 目錄介紹 1.復(fù)雜頁面庫(kù)介紹 2.本庫(kù)優(yōu)勢(shì)亮點(diǎn) 2.1 支持多種狀態(tài)切換管理 2.2 支持添加多個(gè)header和footer 2.3 支持側(cè)滑功能和拖拽移動(dòng) 2.4 其他亮點(diǎn)介紹 3.如...
摘要:我們先實(shí)現(xiàn)一個(gè)瀑布流瀑布流的實(shí)現(xiàn)方式很多,本文采用結(jié)合的來實(shí)現(xiàn)。有了一個(gè)可用的瀑布流之后,下面我們就可以實(shí)現(xiàn)動(dòng)態(tài)聊天窗了動(dòng)態(tài)聊天窗的要點(diǎn)在于的大小由視頻的寬高比決定,因此及其對(duì)應(yīng)的就該注意不要寫死尺寸。 作者:聲網(wǎng)用戶,資深A(yù)ndroid工程師吳東洋本系列文章分享了基于Agora SDK 2.1實(shí)現(xiàn)多人視頻通話的實(shí)踐經(jīng)驗(yàn)。 在上一篇《Android 多人視頻聊天應(yīng)用的開發(fā)(一)一對(duì)一聊...
閱讀 2260·2023-04-25 14:50
閱讀 1234·2021-10-13 09:50
閱讀 1866·2019-08-30 15:56
閱讀 1839·2019-08-29 15:29
閱讀 2886·2019-08-29 15:27
閱讀 3548·2019-08-29 15:14
閱讀 1192·2019-08-29 13:01
閱讀 3299·2019-08-26 14:06