2017年4月20日 星期四

Android: 製作Heart Beat視圖

前言

做了一個心跳的效果動畫,名為HeartBeatView,不靠Animation或Animator即可達到的客製化視圖,當中還包括可以直接在xml設定其速度和跳動幅度,效果如下:


這邊我歸納幾個實現的步驟:
  1. 定義HeartBeatView的屬性(declare-styleaqle)
  2. 實作HeartBeatView
  3. 初始化資源檔內容與Paint物件
  4. 繪製愛心
  5. 繪製跳動與幅度

定義HeartBeatView的屬性(declare-styleaqle) 

<resources>
    <declare-styleable name="HeartBeatImageView">
        <attr name="animMoveFactor" format="float" />
        <attr name="animCounter" format="integer" />
        <attr name="heartColor" format="color" />
    </declare-styleable>
</resources>

實作HeartBeatView

public class HeartBeatImageView extends View {
}

初始化資源檔內容與Paint物件

這邊則是在呼叫HeartBeatView的建構子時,順便將我們在xml裡設定的屬性給帶進來(要是你有使用到的話!),可以透過AttributeSet這個參數獲取其在xml設定的內容,程式碼如下。

    public HeartBeatImageView(Context context) {
        this(context, null);
    }

    public HeartBeatImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public HeartBeatImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.initParams(context, attrs);
        this.initPaint();
    }

    private void initParams(Context context, AttributeSet attrs) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.HeartBeatImageView);
        this.animMoveFactor = typedArray.getFloat(R.styleable.HeartBeatImageView_animMoveFactor, DEFAUT_ANIM_MOVE_FACTOR);
        this.animCounter = typedArray.getInt(R.styleable.HeartBeatImageView_animCounter, DEFAULT_ANIM_COUNTER);
        this.heartColor = typedArray.getColor(R.styleable.HeartBeatImageView_heartColor, DEFAULT_COLOR);
        typedArray.recycle();
    }

    private void initPaint() {
        this.redCirclePaint = new Paint();
        this.redCirclePaint.setAntiAlias(true);
        this.redCirclePaint.setColor(this.heartColor);
    }

繪製愛心

先繪製一個正方形,再加上兩個圓形,並將之轉成45度即可,程式碼如下。

        int centerX = canvas.getWidth() / 2;
        int centerY = canvas.getHeight() / 2;
        float radius = this.getCircleRadius(canvas.getWidth() / 6, this.animCounter, this.animMoveFactor);

        canvas.rotate(45, centerX, centerY);

        canvas.drawRect(centerX - radius, centerY - radius, centerX + radius, centerY + radius, this.redCirclePaint);
        canvas.drawCircle(centerX - radius, centerY, radius, this.redCirclePaint);
        canvas.drawCircle(centerX, centerY - radius, radius, this.redCirclePaint);

繪製跳動與幅度

這邊是透過animCounter與step這兩個參數來控制增減,並期重新更新radius數值,程式碼如下。


    private void drawHeart(Canvas canvas) {
        this.animCounter = this.animCounter + this.step;

        int centerX = canvas.getWidth() / 2;
        int centerY = canvas.getHeight() / 2;
        float radius = this.getCircleRadius(canvas.getWidth() / 6, this.animCounter, this.animMoveFactor);

        canvas.rotate(45, centerX, centerY);

        canvas.drawRect(centerX - radius, centerY - radius, centerX + radius, centerY + radius, this.redCirclePaint);
        canvas.drawCircle(centerX - radius, centerY, radius, this.redCirclePaint);
        canvas.drawCircle(centerX, centerY - radius, radius, this.redCirclePaint);

        if (this.animCounter >= ANIM_COUNTER_MAX) {
            this.step = -1;
        } else if (this.animCounter <= 0) {
            this.step = 1;
        }
    }

    private float getCircleRadius(int radius, int animCounter, double animFactor) {
        return (float) (radius + animCounter * animFactor);
    }

沒有留言:

張貼留言