Android自訂view實現水波紋進度球效果_Android

來源:互聯網
上載者:User

今天我們要實現的這個view沒有太多互動性的view,所以就繼承view。

自訂view的套路,套路很深

      1、擷取我們自訂屬性attrs(可省略)

      2、重寫onMeasure方法,計算控制項的寬和高

      3、重寫onDraw方法,繪製我們的控制項

這麼看來,自訂view的套路很清晰嘛。

我們看下今天的效果圖,其中一個是放慢的效果(時間調的長)


我們按照套路來。

一.自訂屬性

 <declare-styleable name="WaveProgressView">  <attr name="radius" format="dimension|reference" />  <attr name="radius_color" format="color|reference" />  <attr name="progress_text_color" format="color|reference" />  <attr name="progress_text_size" format="dimension|reference" />  <attr name="progress_color" format="color|reference" />  <attr name="progress" format="float" />  <attr name="maxProgress" format="float" /> </declare-styleable>

看下效果圖我們就知道因該需要哪些屬性。就不說了。

然後就是擷取我們的這些屬性,就是用TypedArray來擷取。當然是在構造中擷取,一般我們會複寫構造方法,少參數調用參數多的,然後走到參數最多的那個。

TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.WaveProgressView, defStyleAttr, R.style.WaveProgressViewDefault);  radius = (int) a.getDimension(R.styleable.WaveProgressView_radius, radius);  textColor = a.getColor(R.styleable.WaveProgressView_progress_text_color, 0);  textSize = a.getDimensionPixelSize(R.styleable.WaveProgressView_progress_text_size, 0);  progressColor = a.getColor(R.styleable.WaveProgressView_progress_color, 0);  radiusColor = a.getColor(R.styleable.WaveProgressView_radius_color, 0);  progress = a.getFloat(R.styleable.WaveProgressView_progress, 0);  maxProgress = a.getFloat(R.styleable.WaveProgressView_maxProgress, 100);  a.recycle();

註: R.style.WaveProgressViewDefault是這個控制項的預設樣式。

二.onMeasure測量

我們重寫這個方法主要是更具父看見的寬和高來設定自己的寬和高。

 @Override  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  //計算寬和高  int exceptW = getPaddingLeft() + getPaddingRight() + 2 * radius;  int exceptH = getPaddingTop() + getPaddingBottom() + 2 * radius;  int width = resolveSize(exceptW, widthMeasureSpec);  int height = resolveSize(exceptH, heightMeasureSpec);  int min = Math.min(width, height);  this.width = this.height = min;  //計算半徑,減去padding的最小值  int minLR = Math.min(getPaddingLeft(), getPaddingRight());  int minTB = Math.min(getPaddingTop(), getPaddingBottom());  minPadding = Math.min(minLR, minTB);  radius = (min - minPadding * 2) / 2;  setMeasuredDimension(min, min); }

首先該控制項的寬和高肯定是一樣的,因為是個圓嘛。其實是寬和高與半徑和內邊距有關,這裡的內邊距,我們取上下左右最小的一個。寬和高也選擇取最小的。

this.width = this.height = min; 包含左右邊距。

resolveSize這個方法很好的為我們實現了我們想要的寬和高我慢看下源碼。

 public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) {  final int specMode = MeasureSpec.getMode(measureSpec);  final int specSize = MeasureSpec.getSize(measureSpec);  final int result;  switch (specMode) {   case MeasureSpec.AT_MOST:    if (specSize < size) {     result = specSize | MEASURED_STATE_TOO_SMALL;    } else {     result = size;    }    break;   case MeasureSpec.EXACTLY:    result = specSize;    break;   case MeasureSpec.UNSPECIFIED:   default:    result = size;  }  return result | (childMeasuredState & MEASURED_STATE_MASK); }

如果我們自己寫也是這樣寫。

最後通過setMeasuredDimension設定寬和高。

三.onDraw繪製

關於繪製有很多android 提供了很多API,這裡就不多說了。

繪製首先就是一些畫筆的初始化。

需要提一下繪製path路徑的畫筆設定為PorterDuff.Mode.SRC_IN模式,這個模式只顯示重疊的部分。

 pathPaint = new Paint(Paint.ANTI_ALIAS_FLAG);  pathPaint.setColor(progressColor);  pathPaint.setDither(true);  pathPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));

我們要將所有的繪製 繪製到一個透明的bitmap上,然後將這個bitmap繪製到canvas上。

if (bitmap == null) {   bitmap = Bitmap.createBitmap(this.width, this.height, Bitmap.Config.ARGB_8888);   bitmapCanvas = new Canvas(bitmap);  }

為了方便計算和繪製,我將座標系平移padding的距離

 bitmapCanvas.save();  //移動座標系  bitmapCanvas.translate(minPadding, minPadding); // .... some thing bitmapCanvas.restore();

3.1繪製圓

  bitmapCanvas.drawCircle(radius, radius, radius, circlePaint);

3.2繪製PATH 路徑.

一是要實現波紋的左右飄,和上下的振幅慢慢的減小

繪製這個之前我們需要知道二階貝茲路徑的大致原理。

簡單的說就是知道:P1起始點,P2是終點,P1是控制點.利用塞爾曲線的公式就可以得道沿途的一些點,最後把點連起來就是嘍。

下面這個圖片來於網路:


二階貝茲路徑

在android-sdk裡提供了繪製貝茲路徑的函數rQuadTo方法

public void rQuadTo(float dx1, float dy1, float dx2, float dy2)

      dx1:控制點X座標,表示相對上一個終點X座標的位移座標,可為負值,正值表示相加,負值表示相減;

      dy1:控制點Y座標,相對上一個終點Y座標的位移座標。同樣可為負值,正值表示相加,負值表示相減;

      dx2:終點X座標,同樣是一個相對座標,相對上一個終點X座標的位移值,可為負值,正值表示相加,負值表示相減;

      dy2:終點Y座標,同樣是一個相對,相對上一個終點Y座標的位移值。可為負值,正值表示相加,負值表示相減;

這四個參數都是傳遞的都是相對值,相對上一個終點的位移值。

要實現振幅慢慢的減小我們可以調節控制點的y座標即可,即:

float percent=progress * 1.0f / maxProgress;

就可以得到[0,1]的

一個閉區間,[0,1]這貨好啊,我喜歡,可以來做很多事情。

這樣我們就可以根據percent來調節控制點的y座標了。

//根據直徑計算繪製貝賽爾曲線的次數   int count = radius * 4 / 60;   //控制-控制點y的座標   float point = (1 - percent) * 15;   for (int i = 0; i < count; i++) {    path.rQuadTo(15, -point, 30, 0);    path.rQuadTo(15, point, 30, 0);   }

要實現左右波紋只需要控制閉合路徑的左上方的x座標即可,當然也是根據percent嘍。

大家可以結合下面這個圖來理解下上面的話。

path繪製的完整程式碼片段。

 //繪製PATH  //重設繪製路線  path.reset();  float percent=progress * 1.0f / maxProgress;  float y = (1 - percent) * radius * 2;  //移動到右上邊  path.moveTo(radius * 2, y);  //移動到最右下方  path.lineTo(radius * 2, radius * 2);  //移動到最左下邊  path.lineTo(0, radius * 2);  //移動到左上邊  // path.lineTo(0, y);  //實現左右波動,根據progress來平移  path.lineTo(-(1 -percent) * radius*2, y);  if (progress != 0.0f) {   //根據直徑計算繪製貝賽爾曲線的次數   int count = radius * 4 / 60;   //控制-控制點y的座標   float point = (1 - percent) * 15;   for (int i = 0; i < count; i++) {    path.rQuadTo(15, -point, 30, 0);    path.rQuadTo(15, point, 30, 0);   }  }  //閉合  path.close();  bitmapCanvas.drawPath(path, pathPaint);

3.3繪製進度的文字

這個就比較簡單了,繪製在控制項的中間即可。關於文字的座標計算還是很好理解的。

 //繪製文字  String text = progress + "%";  float textW = textPaint.measureText(text);  Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();  float baseLine = radius - (fontMetrics.ascent + fontMetrics.descent) / 2;  bitmapCanvas.drawText(text, radius - textW / 2, baseLine, textPaint);

最後別忘了把我們的bitmap繪製到canvas上。

canvas.drawBitmap(bitmap, 0, 0, null);

哦,最後是實用方法,這裡我們不用thread+handler,我們用屬性動畫。

你懂的!!!,like

 ObjectAnimator objectAnimator0 = ObjectAnimator.ofFloat(waveProgressView_0, "progress", 0f, 100f);  objectAnimator0.setDuration(3300);  objectAnimator0.setInterpolator(new LinearInterpolator());  objectAnimator0.start();

結束語

至此,也就實現了我們的效果。以上就是本文的全部內容,希望本文的內容對大家開發Android能有所協助。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.