一、Fragment切換致使RecylerView自動上滑問題android
問題描述服務器
該問題主要存在於Fragment可見狀態變化時(通常是生命週期更新或者Fragment之間相互切換):網絡
① RecylerView佈局中存在動態設置高度的ItemView;ide
② 存在使用ViewPager作輪播組件的時候;oop
解決方案:佈局
在RecyclerView的父佈局中設置post
android:descendantFocusability="blocksDescendants"
或者設置以下:this
android:focusable="true" android:focusableInTouchMode="true"
二、RecylerView中嵌套ViewPager事件衝突url
問題描述:spa
ViewPager嵌套在RecyclerView中,存在沒法捕獲滑動事件的問題,解決方式以下,重寫ViewPager的onTouchEvent事件
解決方案:
@Override public boolean onTouchEvent(MotionEvent ev) { final ViewParent parent = this.getParent(); switch (ev.getActionMasked()){ case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_MOVE: if (parent != null) { parent.requestDisallowInterceptTouchEvent(true); //解決ViewPager嵌套ViewPager致使沒法滑動的問題 } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: if (parent != null) { parent.requestDisallowInterceptTouchEvent(false); //解決ViewPager嵌套ViewPager致使沒法滑動的問題 } break; } return super.onTouchEvent(ev); }
注意:以上方案還一樣能夠解決ViewPager+Fragment + RecylerView + ViewPager(目標) 模式的問題。
三、TabLayout初始選項位置問題
TabLayout若是是MODE_SCROLLABLE模式,要嵌入到RecyclerView中,渲染時並無被add到RecylerView中(getWindowToken是空的),此時選中最後的幾項,可能沒有自動滑入可見區域,形成選中區域被遮擋。
解決方案:
使用主線程Looper隊列處理該問題
public void setSelectedTab(int i){ if(i<0) return; if(mTabLayout==null || mTabLayout.getTabCount()<=i) return; final TabLayout.Tab tab = mTabLayout.getTabAt(i); if(tab.isSelected()){ return; } mTabLayout.postDelayed(()->{ tab.select(); mTabLayout.setScrollPosition(i, 0, true); },0); }
四、垂直RecyclerView嵌套橫向RecylerView位移複用問題。
問題描述:
一個被滑動了一段距離的橫向RecylerView,存在複用位移問題,主要有三種現象。
①正常現象,狀態保留完美(少數手機),能自動保存位移,自動復位。
②橫向RecylerView位置自動復原位移到0的位置(多數手機)
③橫向A滑動一段距離,滑動到某一位置A被D複用後,其位置被D繼承了(明明沒有滑動D,可D存在了位移)(多數手機)
解決方案:
方案一:參考:https://blog.csdn.net/anjoyandroid/article/details/75544381,其中使用ScrollListener,可是存在一個問題,有可能形成多個Listener監聽問題。
方案二:在Recycler.Adapter存在2個生命週期方法以下:
onViewDetachedFromWindow(BaseViewHolder holder)和onViewAttachedToWindow(BaseViewHolder holder)
可是咱們只使用前者,咱們在onViewDetachedFromWindow以前的保存位置
@Override public void onDetachedFromWindow(BaseViewHolder helper) { super.onDetachedFromWindow(helper); if(recyclerView==null || recyclerView.getAdapter()==null || recyclerView.getAdapter().getItemCount()<1) return; LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); final int firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition(); dataEntity.scrollPosition = layoutManager.findFirstVisibleItemPosition(); View childView = layoutManager.findViewByPosition(firstVisibleItemPosition); if (childView != null) { RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) childView.getLayoutParams(); dataEntity.scrollOffset = childView.getLeft(); if(layoutParams!=null){ dataEntity.scrollOffset = childView.getLeft() - layoutParams.rightMargin; } } NCFLog.e("scrollPosition","brandItem="+dataEntity.getSort()+",scrollOffset="+ dataEntity.scrollOffset+" ,scrollPosition="+dataEntity.scrollPosition); }
而後下次再初始化的時候還原
if(childRecyclerViewAdapter.getItemCount()==0) return; LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); if(childRecyclerViewAdapter.getItemCount()<=2) { layoutManager.scrollToPositionWithOffset(0,0); return; } if(dataEntity.scrollPosition>=childRecyclerViewAdapter.getItemCount()){ dataEntity.scrollPosition = childRecyclerViewAdapter.getItemCount()-1; dataEntity.scrollOffset = 0; } layoutManager.scrollToPositionWithOffset(dataEntity.scrollPosition, dataEntity.scrollOffset);
五、Glide圖片大小自適應問題
問題描述
有時爲了網絡圖片看起來不被壓縮,通常設置ScaleType爲fitCenter便可,可是這種方案要求服務器返回不一樣尺寸的圖片才能適配各類手機。所以能夠說,FitXY實際上更常見。通常狀況下,在RecyclerView中圖片控件的寬度是已知的,所以咱們求出高度便可。
解決方案以下:
public class GlideTargetHeightAdapter extends SimpleTarget<Drawable> { private final int reqWidth; private final String url; private ImageView targetView; public static GlideTargetHeightAdapter helper(int reqWidth, ImageView iv, String url){ return new GlideTargetHeightAdapter(reqWidth,iv,url); } public void setPlaceHolder(int resId){ if(resId==0) return; if(this.targetView!=null && this.targetView.getDrawable()==null){ this.targetView.setImageResource(resId); } } public void setPlaceHolder(Drawable placeholder) { if(this.targetView!=null && this.targetView.getDrawable()==null){ this.targetView.setImageDrawable(placeholder); } } public GlideTargetHeightAdapter(int reqWidth, ImageView targetView, @NonNull String tag) { super(); this.targetView = targetView; this.reqWidth = reqWidth; this.url = tag; this.targetView.setImageResource(R.drawable.xsj_default_product_img); } public GlideTargetHeightAdapter(ImageView targetView, @NonNull String tag) { this(-1,targetView,tag); } @Override public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) { if(resource==null || this.targetView==null) return; final float width = resource.getIntrinsicWidth() * 1f; final float height = resource.getIntrinsicHeight() * 1f; int imageWidth = this.reqWidth; final ViewGroup.LayoutParams layoutParams = targetView.getLayoutParams(); float hspace = (this.targetView.getPaddingLeft() + this.targetView.getPaddingRight()); float vspace = (this.targetView.getPaddingTop() + this.targetView.getPaddingBottom()); float contentWidth = imageWidth - hspace; float contentHeight = contentWidth * (height/width); if(layoutParams!=null){ int oldHeight = layoutParams.height; layoutParams.height = (int) ( contentHeight + vspace); if(oldHeight!=layoutParams.height) { this.targetView.setLayoutParams(layoutParams); } } if(this.targetView.getScaleType()!= ImageView.ScaleType.FIT_XY){ this.targetView.setScaleType(ImageView.ScaleType.FIT_XY); } if(resource instanceof BitmapDrawable){ Bitmap createScaledBitmap = Bitmap.createScaledBitmap(((BitmapDrawable) resource).getBitmap(), (int)contentWidth, (int)contentHeight, false); this.targetView.setImageBitmap(createScaledBitmap); }else if(resource instanceof GifDrawable) { NcfGlide.with(this.targetView).placeholder(R.drawable.xsj_default_product_img).load(this.url).into(this.targetView); } } }
用法
final int widthPixels = mImageIv.getResources().getDisplayMetrics().widthPixels; Glide.with(mImageIv).placeholder(R.drawable.icon_default_img).load(imageUrl).into(GlideTargetHeightAdapter.helper(widthPixels,mImageIv,imageUrl));
六、Handler或者定時器問題
問題描述:
定時器什麼時候移除,如何移除?
解決方案:
因爲RecyclerView是能夠複用的,所以ItemView必然會onAttachToWindow和onDetachFromWindow,所以咱們需藥在onDetachFromWindow終止這些定時器。可是這裏咱們可能遇到某些低版本handler.removeCallbacks失效的問題,所以咱們須要在Runnable中設置一個變量,相似結束線程的方式終止定時器循環。
此外,禁止使用以下方法,該方法可能形成系統中的消息、事件丟失,從而形成下拉刷新控件下拉以後沒法恢復到初始狀態。
removeCallbacksAndMessages