1. 程式人生 > >自定義View詳解(3)

自定義View詳解(3)

大家教師節快樂啊,不知道勤學的Coder們有沒有去嘗試下繪製上篇文章中最後留下的進階效果,不管怎樣,還是一起動手寫一遍吧!看看套路是否一致。

水波紋

首先來看圖-水波紋中的效果,其具有以下特點:

  • 從內到外四層,內圓外環;

  • 從內到外四個色值;

  • 最內部圓局於View中心;

  • 圓和環同心;

看出以下幾點,我們就可以開始按照套路畫圖了,老套路走起(在以後自定義View部分新建專案及類相關的描述不再贅述)。

宣告畫筆和寬高

1.宣告畫筆及寬高 如上分析,我們需要兩個畫筆,一個用於繪製內圓,一個用於繪製外環。

/**
   * 繪製最中心圓的Paint
   */
  private Paint mInnerCirclePaint;

  /**
   * 繪製外部圓環的Paint
   */
  private Paint mOutterRingPaint;

  /**
   * View寬度
   */
  private int mWidth;

  /**
   * View高度
   */
  private int mHeight;

  /**
   * 外環寬度
   */
  private int mOuttterRingWidth = 50;

2.初始化畫筆並在建構函式內呼叫 由於外部為圓環,所以外部畫筆樣式設定為空心,內部圓畫筆樣式設定為實心,同時設定畫筆寬度為外部圓環寬度。

  public WaveView(Context context) {
    super(context);
    init();
  }

  public WaveView(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
    init();
  }

  public WaveView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init();
  }

  private void init() {
    mInnerCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mInnerCirclePaint.setColor(Color.BLUE);
    /** 內部畫筆為實心 **/
    mInnerCirclePaint.setStyle(Style.FILL);

    mOutterRingPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mOutterRingPaint.setColor(Color.BLUE);
    /** 外部畫筆為空心 **/
    mOutterRingPaint.setStyle(Style.STROKE);
    mOutterRingPaint.setStrokeWidth(mOuttterRingWidth);
  }

3.初始化寬高

  @Override
  protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    if (w > 0 && h > 0){
      mWidth = w;
      mHeight = h;
    }
  }

計算Points

宣告內圓半徑,圓環寬度,計算各圓的半徑,同心圓及圓環,圓心位於View中心。

如圖-水波紋內部距離說明,外環所在圓依次為(radius為外環半徑,mInnerRadius為內圓半徑,mOutterRingWidth為環寬度):

一環:半徑與內圓半徑一致,radius = mInnerRadius+(mOutterRingWidth/2)1; 二環:半徑等於內圓半徑+圓環寬度,radius = mInnerRadius + (mOutterRingWidth/2)3; … 依次類推,我們可以得到外部圓環半徑公式:

radius = mInnerRadius + (mOutterRingWidth/2) * i;(i取1,3,5,7,9…)

如此我們就可以開始擼碼了。

  /*  宣告必要變數 */
  /**
   * 內圓半徑
   */
  private int mInnerRadius = 50;

  /**
   * 儲存計算所得的外環半徑
   */
  private int[] mRadius = new int[4];
  /* 計算外環半徑 */
  private void calculateRadius() {
    for (int i = 0; i < 4; i++) {
      mRadius[i] = mInnerRadius + (i * 2 + 1) * mOuttterRingWidth / 2;
    }
  }

獲取畫布繪製圓及圓環

重寫onDraw函式獲取canvas,並繪製圓環及內圓。

  @Override
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    calculateRadius();
    canvas.drawCircle(mWidth / 2, mHeight / 2, mInnerRadius, mInnerCirclePaint);
    for (int i = 0; i < 4; i++) {
      /** 改變外環的顏色透明度 **/
      mOutterRingPaint.setAlpha(255 - (int) (255 * ((float) (i + 1) / 5)));
      canvas.drawCircle(mWidth / 2, mHeight / 2, mRadius[i], mOutterRingPaint);
    }
  }

至於執行效果,大家自己動手試一下嘍!

動起來的水波紋

雖然我們畫出來了水波紋,但是和藹的產品還是會批鬥你的,他會說,你家水波紋靜態的哦?這一秒鐘心裡是不是有一萬隻羊駝奔騰?哈哈!奔騰歸奔騰,需求我們還是要實現下滴。

那麼我們來觀察下現實中的水波紋,不難發現與圖-水波紋形成 相似的過程。

我們可以看出水波紋動態形成的本質是,外部圓環逐步擴張增加形成的。那麼我們只需要動態控制外部圓環的繪製個數,就可以讓它動起來了。

屬性動畫

說到控制外環個數動態增長,做過動畫的朋友第一個直覺肯定就是屬性動畫嘍,這樣是值變化,所以我們使用ValueAnimator即可(關於屬性動畫,幀動畫,View動畫相關的細節,我們在後續文章中單獨說明)。

1.宣告動畫相關的成員

  /**
   * 控制外環個數變化的屬性動畫物件
   */
  private ValueAnimator mValueAnimator;

  /**
   * 繪製的外環總個數
   */
  private int mOutterRingCount = 4;

2.初始化動畫物件並開始

public void startAnimation(){
    //建立ValueAnimator物件,按照整型值從0變化到4
    mValueAnimator = ValueAnimator.ofInt(0,5);
    //設定動畫重複型別,RESTART--重新開始,REVERSE--值反轉
    mValueAnimator.setRepeatMode(ValueAnimator.RESTART);
    //設定動畫重複次數,-1--不限制次數
    mValueAnimator.setRepeatCount(-1);
    mValueAnimator.setDuration(2000);
    mValueAnimator.addUpdateListener(new AnimatorUpdateListener() {
      @Override
      public void onAnimationUpdate(ValueAnimator valueAnimator) {
        mOutterRingCount = (int) valueAnimator.getAnimatedValue();
        postInvalidate();
      }
    });
    mValueAnimator.start();
  }

3.更新onDraw迴圈引數

  @Override
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    calculateRadius();
    canvas.drawCircle(mWidth / 2, mHeight / 2, mInnerRadius, mInnerCirclePaint);
    for (int i = 0; i < mOutterRingCount; i++) {
      mOutterRingPaint.setAlpha(255 - (int) (255 * ((float) (i + 1) / 5)));
      canvas.drawCircle(mWidth / 2, mHeight / 2, mRadius[i], mOutterRingPaint);
    }
  }

執行效果見gif,至此我們就完成了水波紋自定義View的開發,怎麼樣?是不是很有趣啊.