1. 程式人生 > >實現支付寶AR掃描動畫效果

實現支付寶AR掃描動畫效果

實現支付寶AR掃描效果動畫

之前一個網友說想要一個支付寶掃描動畫的效果demo,所以又花了點時間做了下這個東西,先看效果圖
效果圖
說一下實現的思路,如圖中最外圍的藍色的是用兩個相距180°的圓弧實現的,再往裡又是兩個紅色的圓弧再往裡面是一個紅色的圓,最裡面的白色的是由4個間隔的白色圓弧組成的,其實說明白的就是簡單的圖形的堆積.然後通過控制繪製圓弧的起始角度進行旋轉的動畫.掃描的紅色線條是一張漸變的圖片,通過平移動畫實現掃描的效果.
這個自定義View 的程式碼如下:

package cn.com.hadon.scanner;

import android.content.Context;
import
android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; import android.support.annotation.Nullable; import android.util.AttributeSet; import
android.view.View; /** * Created by Mr.Wang on 2017/5/8. */ public class ScanView extends View { private Paint blueCirclePaint;//藍色圈的畫筆 private Paint redCirclePaint;//紅色圈的畫筆 private Paint whiteCirclePaint;//白色圈的畫筆 public static final int STATE_READY = 1; public static final int STATE_SCANING = 2
; public static final int STATE_SUCCESS = 3; //定義圓弧的寬度 private static final int BLUE_CIRCLE_BORDER_WIDTH = 8; private static final int INSIDER_RED_CIRCLE_BORDER_WIDTH = 20; private static final int OUTSIDER_CIRCLE_BORDER_WIDTH = 20; private static final int WHITE_CIRCLE_BORDER_WIDTH = 20; private int minLength;//中心最大圓的直徑 private int radius;//中心最大圓的半徑 private int centerX;//中心點X座標 private int centerY;//中心點Y座標 private Bitmap scanerbitmap;//條形掃描圖片 private int curState = STATE_SCANING;//初始狀態 public ScanView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); //初始化一些變數 scanerbitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.scaner); blueCirclePaint = new Paint(); redCirclePaint = new Paint(); whiteCirclePaint = new Paint(); blueCirclePaint.setColor(Color.BLUE); blueCirclePaint.setAntiAlias(true); blueCirclePaint.setStyle(Paint.Style.STROKE); blueCirclePaint.setStrokeWidth(BLUE_CIRCLE_BORDER_WIDTH); redCirclePaint.setColor(Color.RED); redCirclePaint.setAntiAlias(true); redCirclePaint.setStyle(Paint.Style.STROKE); redCirclePaint.setStrokeWidth(INSIDER_RED_CIRCLE_BORDER_WIDTH); whiteCirclePaint.setColor(Color.WHITE); whiteCirclePaint.setAntiAlias(true); whiteCirclePaint.setStyle(Paint.Style.STROKE); whiteCirclePaint.setStrokeWidth(WHITE_CIRCLE_BORDER_WIDTH); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); centerX = width / 2; centerY = height / 2; //獲取直徑和半徑以及中心帶你座標方便後面的計算 minLength = Math.min(width, height); radius = minLength / 2; } /** * 公開方法設定當前的狀態值 * @param state */ public void setState(int state) { this.curState = state; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(Color.TRANSPARENT); switch (curState) { case STATE_READY: drawWhiteCircle(canvas); drawInsiderRedCircle(canvas); drawOutsiderRedCircle(canvas); break; case STATE_SCANING: drawWhiteCircle(canvas); drawBlueCircle(canvas); drawInsiderRedCircle(canvas); drawOutsiderRedCircle(canvas); drawScaner(canvas); break; case STATE_SUCCESS: drawWhiteCircle(canvas); drawInsiderRedCircle(canvas); break; } updateValues(); invalidate(); } private int blueStartAngle = 0;//藍色圓圈的開始角度 private int blueCircleSpace = BLUE_CIRCLE_BORDER_WIDTH;//藍色弧距離最短邊的距離用於計算自身的半徑用 private static final int BLUE_CIRCLE_SWEP_ANGLE = 20;//藍色弧掃過的角度 /** * 繪製藍色弧 * @param canvas */ private void drawBlueCircle(Canvas canvas) { canvas.drawArc(centerX - radius + blueCircleSpace, blueCircleSpace, centerX + radius - blueCircleSpace, minLength - blueCircleSpace, blueStartAngle, BLUE_CIRCLE_SWEP_ANGLE, false, blueCirclePaint); canvas.drawArc(centerX - radius + blueCircleSpace, blueCircleSpace, centerX + radius - blueCircleSpace, minLength - blueCircleSpace, blueStartAngle + 180, BLUE_CIRCLE_SWEP_ANGLE, false, blueCirclePaint); } /** * 根據當前的狀態來更改變數達到動畫的效果 */ private void updateValues() { switch (curState) { case STATE_READY: if (insideRedCircleSpace >= BLUE_CIRCLE_BORDER_WIDTH + INSIDER_RED_CIRCLE_BORDER_WIDTH+ OUTSIDER_CIRCLE_BORDER_WIDTH) { insideRedCircleSpace -= 2; } whiteStartAngle = 5 / 2; outsiderRedCircleStartAndle = -OUTSIDER_RED_CIRCLE_SWEP_ANGLE / 2; break; case STATE_SCANING: if (insideRedCircleSpace >= BLUE_CIRCLE_BORDER_WIDTH + INSIDER_RED_CIRCLE_BORDER_WIDTH+ OUTSIDER_CIRCLE_BORDER_WIDTH) { insideRedCircleSpace -= 2; } blueStartAngle += 4; outsiderRedCircleStartAndle += 2; if (is2Max) { if (whiteStartAngle == 30) { is2Max = false; } else { whiteStartAngle++; } } else { if (whiteStartAngle == -30) { is2Max = true; } else { whiteStartAngle--; } } scanerY += 6; if (scanerY > minLength) { scanerY = 0; } break; case STATE_SUCCESS: whiteStartAngle = 5 / 2; if (insideRedCircleSpace < whiteCircleSpace + INSIDER_RED_CIRCLE_BORDER_WIDTH) { insideRedCircleSpace += 2; } break; } } private int insideRedCircleSpace = BLUE_CIRCLE_BORDER_WIDTH + INSIDER_RED_CIRCLE_BORDER_WIDTH + OUTSIDER_CIRCLE_BORDER_WIDTH; private int outsiderRedCircleSpace = BLUE_CIRCLE_BORDER_WIDTH + INSIDER_RED_CIRCLE_BORDER_WIDTH + OUTSIDER_CIRCLE_BORDER_WIDTH / 2; private static final int OUTSIDER_RED_CIRCLE_SWEP_ANGLE = 30; private int outsiderRedCircleStartAndle = -OUTSIDER_RED_CIRCLE_SWEP_ANGLE / 2; /** * 繪製內部的紅色圓圈 * @param canvas */ private void drawInsiderRedCircle(Canvas canvas) { canvas.drawCircle(centerX, centerY, radius - insideRedCircleSpace, redCirclePaint); } /** * 繪製外部紅色的兩個弧 * @param canvas */ private void drawOutsiderRedCircle(Canvas canvas) { canvas.drawArc(centerX - radius + outsiderRedCircleSpace, outsiderRedCircleSpace, centerX + radius - outsiderRedCircleSpace, minLength - outsiderRedCircleSpace, outsiderRedCircleStartAndle, OUTSIDER_RED_CIRCLE_SWEP_ANGLE, false, redCirclePaint); canvas.drawArc(centerX - radius + outsiderRedCircleSpace, outsiderRedCircleSpace, centerX + radius - outsiderRedCircleSpace, minLength - outsiderRedCircleSpace, outsiderRedCircleStartAndle + 180, OUTSIDER_RED_CIRCLE_SWEP_ANGLE, false, redCirclePaint); } private int whiteStartAngle = 0; private static final int WHITE_CIRCLE_SWEP_ANGLE = 85; private int whiteCircleSpace = BLUE_CIRCLE_BORDER_WIDTH + INSIDER_RED_CIRCLE_BORDER_WIDTH + OUTSIDER_CIRCLE_BORDER_WIDTH + WHITE_CIRCLE_BORDER_WIDTH; private RectF whiteCircleRect; private boolean is2Max = true; /** * 繪製白色的弧 * @param canvas */ private void drawWhiteCircle(Canvas canvas) { if (whiteCircleRect == null) { whiteCircleRect = new RectF(centerX - radius + whiteCircleSpace, whiteCircleSpace, centerX + radius - whiteCircleSpace, minLength - whiteCircleSpace); } canvas.drawArc(whiteCircleRect, whiteStartAngle, WHITE_CIRCLE_SWEP_ANGLE, false, whiteCirclePaint); canvas.drawArc(whiteCircleRect, whiteStartAngle + 90, WHITE_CIRCLE_SWEP_ANGLE, false, whiteCirclePaint); canvas.drawArc(whiteCircleRect, whiteStartAngle + 180, WHITE_CIRCLE_SWEP_ANGLE, false, whiteCirclePaint); canvas.drawArc(whiteCircleRect, whiteStartAngle + 270, WHITE_CIRCLE_SWEP_ANGLE, false, whiteCirclePaint); } private int scanerY = 0; /** * 繪製掃描圖片 * @param canvas */ private void drawScaner(Canvas canvas) { int p1, p2, hw; if (scanerY >= radius) { p1 = (scanerY - radius) * (scanerY - radius); } else { p1 = (radius - scanerY) * (radius - scanerY); } p2 = radius * radius; hw = (int) Math.sqrt(p2 - p1); Rect rect = new Rect(centerX - hw, scanerY - 10, centerX + hw, scanerY + 10); canvas.drawBitmap(scanerbitmap, null, rect, null); } }

下面是我偶讀github地址