国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android自定義View控件實現多種水波紋漣漪擴散效果

2019-12-12 01:03:34
字體:
來源:轉載
供稿:網友

效果圖

實現思路

這個效果實現起來并不難,重要的是思路

此View滿足了多種水波紋漣漪擴散效果,這要求它能滿足很多的變化

根據上面的樣式,可以看出此View需要滿足以下變化

  • 圓圈從中心可循環向外擴散
  • 圓圈之間的擴散間距可以改變
  • 可控制擴散圓的漸變度
  • 圓圈可以是線條樣式或者實心樣式
  • 圓圈擴散的速度可以控制
  • 適配圓圈不同大小下的擴散效果

具體實現

創建自定義屬性

首先為View創建自定義的xml屬性

在工程的values目錄下新建attrs.xml文件

 <declare-styleable name="mRippleView"> <attr name="cColor" format="color"/> <attr name="cSpeed" format="integer"/> <attr name="cDensity" format="integer"/> <attr name="cIsFill" format="boolean"/> <attr name="cIsAlpha" format="boolean"/> </declare-styleable>

各個屬性的作用如下

  • cColor:View控件的顏色
  • cSpeed:向外擴散的速度
  • cDensity:圓形波紋擴散的間距
  • cIsFill:是否開啟填充模式,true為實心圓
  • cIsAlpha:是否開啟漸變效果,true為開啟

創建自定義View控件

新建RippleView類繼承View類,重寫它的三個構造方法,獲取用戶設置的屬性,同時指定默認值

 public RippleView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); // 獲取用戶配置屬性 TypedArray tya = context.obtainStyledAttributes(attrs, R.styleable.mRippleView); mColor = tya.getColor(R.styleable.mRippleView_cColor, Color.BLUE); mSpeed = tya.getInt(R.styleable.mRippleView_cSpeed, 1); mDensity = tya.getInt(R.styleable.mRippleView_cDensity, 10); mIsFill = tya.getBoolean(R.styleable.mRippleView_cIsFill, false); mIsAlpha = tya.getBoolean(R.styleable.mRippleView_cIsAlpha, false); tya.recycle(); init(); }

使用TypedArray讀取完自定義的屬性后一定要記得調用recycle方法釋放掉

重寫onMeasure

測量onMeasure,首先需要測量出View的寬和高,并指定View在wrap_content時的最小范圍,對于View繪制流程還不熟悉的同學,可以先去了解下具體的繪制流程

//m.survivalescaperooms.com/article/118775.htm

重寫onMeasure方法,其中我們要考慮當View的寬高被指定為wrap_content時的情況,如果我們不對wrap_content的情況進行處理,那么當使用者指定View的寬高為wrap_content時將無法正常顯示出View

 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int myWidthSpecMode = MeasureSpec.getMode(widthMeasureSpec); int myWidthSpecSize = MeasureSpec.getSize(widthMeasureSpec); int myHeightSpecMode = MeasureSpec.getMode(heightMeasureSpec); int myHeightSpecSize = MeasureSpec.getSize(heightMeasureSpec); // 獲取寬 if (myWidthSpecMode == MeasureSpec.EXACTLY) {  // match_parent/精確值  mWidth = myWidthSpecSize; } else {  // wrap_content  mWidth = DensityUtil.dip2px(mContext, 120); } // 獲取高 if (myHeightSpecMode == MeasureSpec.EXACTLY) {  // match_parent/精確值  mHeight = myHeightSpecSize; } else {  // wrap_content  mHeight = DensityUtil.dip2px(mContext, 120); } // 設置該view的寬高 setMeasuredDimension(mWidth, mHeight); }

MeasureSpec的狀態分為三種EXACTLY、AT_MOST、UNSPECIFIED,這里只要單獨指定非精確值EXACTLY之外的情況就好了

本文中使用到的DensityUtil類,是為了將dp轉換為px來使用,以便適配不同的屏幕顯示效果

 public static int dip2px(Context context, float dpValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); }

重寫onDraw

設計的整體思路如下圖所示


先要實現圓形向外擴散的效果

  • 初始化第一個圓

這里的動畫效果本來是想使用ValueAnimator屬性動畫的數值發生器來實現,但是我們這里有很多的計算需求,所以最后還是選擇使用算法來實現,方便控制圓的一些參數

想要實現擴散的效果,這里思路是在每次更新View時動態改變圓的半徑,同時還需要給圓設置漸變度數,所以決定用一個類來保存圓的狀態,所有圓都存在一個List里

// 添加第一個圓圈mRipples = new ArrayList<>();Circle c = new Circle(0, 255);mRipples.add(c);

傳入Circle類里的兩個參數,第一個0表示圓的初始寬度,第二個255表示初始透明度

  • 添加新圓

要想實現不斷有圓向外擴散,就需要在第一個圓擴散到一定范圍時在圓心處再添加一個圓,這個的范圍可以由圓的半徑來控制,當List集合中最后一個圓的半徑增加到某個值mDensity時,新的圓就從圓心處創建出來

// 添加圓if (mRipples.size() > 0) { // 控制第二個圓出來的間距 if (mRipples.get(mRipples.size() - 1).width > DensityUtil.dip2px(mContext, mDensity)) { mRipples.add(new Circle(0, 255)); }}
  • 刪除List中多余的圓

List中的圓存儲的數量不宜過多,多了內存消耗大,需要在當圓的半徑超過View的寬度時就刪掉這個圓

// 當圓超出View的寬度后刪除if (c.width > mWidth / 2) { mRipples.remove(i);}

我們也可以在外切正方形的頂點處刪除這個圓,需要用到勾股定律來計算擴散圓到外切正方形頂點的位置


如上圖所示,得出計算公式為

// 使用勾股定律求得一個外切正方形中心點離頂點的距離sqrtNumber = (int) (Math.sqrt(mWidth * mWidth + mHeight * mHeight) / 2);

這樣就需要修改刪除圓的位置了

if (c.width > sprtNumber) { mRipples.remove(i);}
  • 控制擴散圓的漸變度

當圓在向View的邊緣擴散時,漸變度數的改變需要動態來計算,漸變的計算算法要適配不同的圓寬度大小,我們知道透明度是0~255之間的,0表示完全透明,255表示百分百不透明,計算的時候就是需要將這個數值等份分配到圓的寬度里

這里要區分一點,對于圓來說,寬度是由圓心從0開始向外遞增,而漸變度數則是由圓心從255開始向外遞減,當圓與最外圍的正方形內切時漸變度必須變為0,由此分析得知,公式如下

透明度 = 255 - 圓的寬度 * (255 / View寬度)

double alpha = 255 - c.width * (255 / ((double) mWidth / 2));c.alpha = (int) alpha;

GitHub地址

https://github.com/zhuwentao2150/RippleView

總結

關于自定義View的總結部分在我的其它博客中已經寫過蠻多了,有興趣的可以去看看

好了,以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對武林網的支持。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 南宫市| 马关县| 科技| 黔西县| 什邡市| 清新县| 横山县| 通榆县| 山东省| 建水县| 贵州省| 湘潭市| 蒙城县| 米泉市| 将乐县| 五指山市| 温州市| 长葛市| 谷城县| 浪卡子县| 青川县| 定陶县| 和平县| 东丽区| 台北市| 铁力市| 泌阳县| 慈溪市| 城步| 封开县| 大名县| 正宁县| 香河县| 乡宁县| 武山县| 蒙城县| 庆安县| 枝江市| 铜山县| 通州市| 达孜县|