欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android中recyclerView底部添加透明漸變效果

 更新時(shí)間:2018年04月21日 16:34:16   作者:Dynamic_2018  
這篇文章主要給大家介紹了關(guān)于Android中recyclerView如何實(shí)現(xiàn)底部添加透明漸變效果的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)各位Android開發(fā)者們具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起看看吧。

前言

最近實(shí)現(xiàn)一個(gè)recyclerView透明漸變的效果,遇到了一些坑,嘗試了一些方法,這里記錄一下。

效果圖


圖片在上面顯示2列,文字在下面顯示1列;底部要有個(gè)透明漸變的效果,直到完全看不到。

gridLayoutManager動(dòng)態(tài)設(shè)置列數(shù)

大概是分兩類,一類以圖片為item 一行2個(gè),一類以文字為item 一行一個(gè)。

這個(gè)第一反應(yīng)是用viewType去區(qū)分圖片類型,但是由于起初不知道gridLayout可以動(dòng)態(tài)列數(shù)。就在上面兩列,下面一列上為難起來(lái)了。

如果統(tǒng)一用一列吧,那就把兩個(gè)image當(dāng)成一個(gè)item,但是這樣要自己去計(jì)算position,而且還要考慮奇數(shù)情況下最后一行只有一個(gè)圖片的情況,這樣要多寫一些代碼和邏輯。

后面發(fā)現(xiàn)可以通過(guò)改變spanSize來(lái)根據(jù)viewType來(lái)改變spanCount

 //gridLayoutManager這里設(shè)置的spanCount=2
 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) {
  int type = getItemViewType(position);
  switch (type) {
  case TYPE_IMAGE:
  //占用1/2 表示2列
  Log.d("tag", "列數(shù)2");
  return 1;
  case TYPE_TEXT:
  //占用2/2 表示1列
  Log.d("tag", "列數(shù)1");
  return 2;
  default:
  Log.d("tag", "default列數(shù)2");
  return 2;
  }
  }
 });
 }

這樣item的layout就很干凈了,省去了一些麻煩。

recyclerView添加透明漸變

本來(lái)看著快搞完了,只差一個(gè)底部透明漸變了,結(jié)果就這一個(gè)效果高出了好多事情。

嘗試了下面三種方法

  • recycleView上面蓋一層漸變的layout
  • 原生的fadingEdeg,嘗試通過(guò)反射去掉頂部陰影
  • 圖層合并

第一反應(yīng)是再在recycleView上面蓋一層漸變的layout。

<shape xmlns:android="http://schemas.android.com/apk/res/android"
 android:shape="rectangle">
 <gradient
 android:angle="90"
 android:startColor="@color/color_FFFFFFFF"
 android:endColor="@color/color_00FFFFFF">
 </gradient>
</shape>

效果如下:


看起來(lái)“蒙”了一點(diǎn)哈

但是這樣有個(gè)問(wèn)題,就是layout使用這個(gè)shape的時(shí)候,是從開始到結(jié)束的漸變,沒(méi)有g(shù)randient的平鋪的效果,也就是只有最后一點(diǎn)是不透明的,不能實(shí)現(xiàn)最后是全不透明的。而且這個(gè)00FFFFFF其實(shí)不是真正意義上的不透明,而是白色的。

效果圖底下有一截是全透明的,這個(gè)和效果圖是有一定差距的,單純用shape實(shí)現(xiàn)不了。嘗試再在漸變下面添加一截全透明,就會(huì)慘不忍睹。


recyclerView的fadingEdge

組里的老司機(jī)提了可以用這個(gè)recyclerView原生自帶的屬性。

android:requiresFadingEdge="vertical"
android:fadingEdgeLength="40dp"


運(yùn)行起來(lái)看起來(lái)雖然和ui有點(diǎn)差距,但是好像可以接受了。

但是滑動(dòng)的時(shí)候就出現(xiàn)問(wèn)題了,這個(gè)自帶fadingEdge不僅底部有,頂部也有,而且更坑的是,recyclerView沒(méi)有提供取消頂部或者底部的接口。要么都不用,要么都要。


參考網(wǎng)上的一種方法,通過(guò)反射去設(shè)置頂部的edge寬高,從而使得頂部陰影不顯示。

如何屏蔽RecyclerView單邊滑動(dòng)到頭陰影(fadingEdge)

本來(lái)以為這樣就ok了,誰(shuí)知道這樣設(shè)置竟然沒(méi)有效果。

參考給的代碼是這樣設(shè)置的:

但是進(jìn)api27的RecyclerView里面看,這個(gè)mTopGlow是EdgeEffect類型


mRecycleView.setOnScrollListener(new RecyclerView.OnScrollListener() {
 @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
 super.onScrolled(recyclerView, dx, dy);
 EdgeEffect mTopGlow = null;
 try {
  Field topGlow = mRecycleView.getClass().getDeclaredField("mTopGlow");
  if (topGlow != null) {
  topGlow.setAccessible(true);
  mTopGlow = (EdgeEffect) topGlow.get(mRecycleView);
  }
 } catch (Exception e) {
  e.printStackTrace();
 }

 if (mTopGlow != null) {
  //設(shè)置TOP頂部的矩形陰影大?。醋⑨尯痛a大概是這個(gè)作用)
  mTopGlow.setSize(0, 0);
  mTopGlow.finish();
 }
 }
 });

這樣大部分情況topGlow也是空的。查看代碼,發(fā)現(xiàn)貌似只有這個(gè)方法才會(huì)給mTopGlow初始化


強(qiáng)行在獲取topGlow對(duì)象前插入ensureTopGlow,使得它不為空:

 public void makeTopGlowNoneNull() {
 final Class<?> clazz = RecyclerView.class;
 try {
 Method method = clazz.getDeclaredMethod("ensureTopGlow");
 method.setAccessible(true);
 method.invoke(mRecycleView);
 } catch (NoSuchMethodException e) {
 e.printStackTrace();
 } catch (IllegalAccessException e) {
 e.printStackTrace();
 } catch (InvocationTargetException e) {
 e.printStackTrace();
 }
 }

好了,經(jīng)過(guò)上面的操作,mtopFlow取出來(lái)并且設(shè)置size(0,0)了,講道理頂部陰影只有一個(gè)長(zhǎng)0,寬0的矩形,就相當(dāng)于沒(méi)有了。

然而。。。

頂部陰影還是存在,而且去調(diào)試系統(tǒng)創(chuàng)建上下陰影的場(chǎng)景,也發(fā)現(xiàn)沒(méi)有調(diào)用setSize就把陰影畫出來(lái)了。之后又折騰了一陣子也沒(méi)看出來(lái)這個(gè)陰影在recyclerView里面怎么是怎么畫出來(lái)的,有知道的大兄弟麻煩告知一下。

通過(guò)圖層合并添加透明效果

參考Android實(shí)現(xiàn)直播聊天區(qū)域頂部漸變效果

 /**
 * 利用itemDecoration的onDraw和onDrawOver回調(diào)時(shí)機(jī),進(jìn)行兩個(gè)圖層的合并
 *
 */
 mRecycleView.addItemDecoration(new RecyclerView.ItemDecoration() {
 @SuppressLint("NewApi") @Override public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
 super.onDraw(c, parent, state);
 layerId = c.saveLayer(0.0f, 0.0f, (float) parent.getWidth(), (float) parent.getHeight(), mPaint);
 }

 @Override public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
 super.onDrawOver(c, parent, state);
 if (linearGradient == null) {
  linearGradient = new LinearGradient(0f,parent.getHeight()-dpToPixel(54), 0f,
  parent.getHeight()-dpToPixel(15), new int[] {startColor,endColor },new float[]{0.2f,0.8f},
  Shader.TileMode.CLAMP);
 }
 mPaint.setXfermode(xfermode);
 mPaint.setShader(linearGradient);
 c.drawRect(0f,parent.getHeight()-dpToPixel(54),parent.getWidth(),parent.getHeight(),mPaint);
 mPaint.setXfermode(null);
 c.restoreToCount(layerId);
 /**
  * 第一次進(jìn)去的時(shí)候發(fā)現(xiàn)畫出來(lái)的東西很奇怪 暫未找到原因
  * 需要滑動(dòng)之后才會(huì)正常顯示,所以第一次進(jìn)去的時(shí)候,手動(dòng)調(diào)用一次刷新
  */

 if (recycleViewfirstComeInFlag == false) {
  recycleViewfirstComeInFlag = true;
  mRecycleView.postInvalidate();
 }
 }

 @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
  RecyclerView.State state) {
 super.getItemOffsets(outRect, view, parent, state);
 }
 });
 }

原理參考文章里面也說(shuō)了,借助ItemDecoration的draw和drawOver方法將兩個(gè)圖層進(jìn)行合并,用DES_IN模式,使得SRC圖層底部有了DES圖層的透明漸變。

看起來(lái)抄就完事兒了的東西,我卻搞了好一陣子。

參考demo就是一個(gè)recyclerView,我的是dialog里面裝一個(gè)recyclerView。dialog顯示在中間,因?yàn)閷?duì)canvas.drawRec()參數(shù)坐標(biāo)以及l(fā)inearGradient的使用不太熟悉,搞出來(lái)一些事情。

關(guān)于LinearGrandient的參數(shù)

前面的xy用來(lái)標(biāo)明方向的。如果是Y垂直方向的漸變,只需要(0,startY)到(0,endY),X就沒(méi)啥作用,保證在Y上是垂直就行。但是這個(gè)startY和endY之前我就理解成絕對(duì)坐標(biāo)了,以為手機(jī)左上角是坐標(biāo)原點(diǎn)(0,0);

后面那個(gè)postion其實(shí)是對(duì)應(yīng)各種color的位置吧,配合CLAMP模式(超出起點(diǎn)和終點(diǎn)外的默認(rèn)是起點(diǎn)和終點(diǎn)的顏色向外延伸)還是挺好用的。

比起第一種直接用XML shape LienarGradient的startColor endColor要靈活很多。

然而view里面沒(méi)有像motionEvent那樣直接getRowX的方法,就通過(guò)百分比計(jì)算來(lái)找位置,又增加了復(fù)雜度。

實(shí)際情況比這些影響因素(同時(shí)還在調(diào)fadingEdge)要多,有點(diǎn)自找麻煩的感覺,一時(shí)陷入僵局。

倒著回去想,既然Google沒(méi)有提供獲取絕對(duì)左邊的方法,而且linearGradient也是設(shè)給paint給canvas用,那里面的坐標(biāo)應(yīng)該是和cavas是一致的。而canvas在很多地方如view的draw里面也能拿到,那明顯設(shè)置成相當(dāng)于canvas的坐標(biāo)要方便一些。

重新清醒一下頭腦,把暫時(shí)該注釋掉的注釋掉,通過(guò)最小粒度的改變來(lái)調(diào)試效果(不然一下子改變很多,出來(lái)的效果會(huì)讓人懵逼),最后總算是搞出來(lái)了。

然而事情并沒(méi)有結(jié)束。。。。。

估計(jì)是我在dialog里面顯示recyclerView的關(guān)系,通過(guò)圖層合并后,會(huì)形成很奇怪的效果,必須要滑動(dòng)一下才可以正常顯示。如果recyclerView不是裝在dialog里面就不會(huì)這樣,只是單存的使用就不會(huì)這樣。

很奇怪,不過(guò)這樣可以看到SRC和DES圖層 ==

暫時(shí)處理是第一次進(jìn)來(lái)在drawOver完成后再postInvalidate一次,有知道原因的老哥幫忙提點(diǎn)一下!

 if (recycleViewfirstComeInFlag == false) {
   recycleViewfirstComeInFlag = true;
    mRecycleView.postInvalidate();
  }

最終效果


遺留的問(wèn)題

  • recyclerView fadingEdge的實(shí)現(xiàn),不是flow.setSize,在調(diào)試代碼時(shí)沒(méi)看出來(lái)。
  • dialog上添加recyclerView的圖層合并,最開始顯示異常的原因。

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

最新評(píng)論