敞开成长之旅!这是我参加「日新方案 2 月更文挑战」的第 27 天,点击检查活动概况
扫码功能都用过吧,打开扫码功能后都会有类似封面图的作用。其实就是一个自定义View的遮罩,话不多说,今日这篇咱们就来解说如何完成一个扫面框动效。
首先,咱们先剖析下动效的组成,有利于待会拆分完成:
- 四周类似角标的白线
- 角标框住的浅白色布景
- 一条由上而下由快到慢移动的扫描线
一经剖析,其实十分简略,整体作用就是由这几个简略的元素组成。接下来咱们就创立一个ScanView继承自View来完成这个动效。(由于代码陈旧,这儿运用Java)
public final class ScanView extends View {
private Paint paint, scanLinePaint,reactPaint;//三种画笔
private Rect frame;//整个区域
public ScanView(Context context) {
this(context, null);
}
public ScanView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ScanView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initPaint()
}
private void initPaint() {
/*遮罩画笔*/
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(color);
paint.setAlpha(CURRENT_POINT_OPACITY);
paint.setStyle(Paint.Style.FILL);
/*边框线画笔*/
reactPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
reactPaint.setColor(reactColor);
reactPaint.setStyle(Paint.Style.FILL);
/*扫描线画笔*/
scanLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
scanLinePaint.setStyle(Paint.Style.FILL);
scanLinePaint.setDither(true);
scanLinePaint.setColor(scanLineColor);
}
}
三种画笔初始化完成接下来就是运用画笔在画布上制作作用图了,重写onDraw()方法
public void onDraw(Canvas canvas) {
//制作取景边框
drawFrameBounds(canvas, frame);
//制作遮罩
drawMaskView(canvas, frame);
//制作扫描线
drawScanLight(canvas, frame);
}
再来剖析,边框的四个角其实拆开来看,就是两条线组成,或者说是两个填充的矩形框笔直相交组成,那么四个角就能够依照这个思路完成,遮罩其实就是一个矩形框。
//制作四个角,留意是外线而不是内线
private void drawFrameBounds(Canvas canvas, Rect frame) {
// 左上角
canvas.drawRect(frame.left - corWidth, frame.top, frame.left, frame.top + corLength, reactPaint);
canvas.drawRect(frame.left - corWidth, frame.top - corWidth, frame.left + corLength, frame.top, reactPaint);
// 右上角
canvas.drawRect(frame.right, frame.top, frame.right + corWidth,frame.top + corLength, reactPaint);
canvas.drawRect(frame.right - corLength, frame.top - corWidth, frame.right + corWidth, frame.top, reactPaint);
// 左下角
canvas.drawRect(frame.left - corWidth, frame.bottom - corLength,frame.left, frame.bottom, reactPaint);
canvas.drawRect(frame.left - corWidth, frame.bottom, frame.left + corLength, frame.bottom + corWidth, reactPaint);
// 右下角
canvas.drawRect(frame.right, frame.bottom - corLength, frame.right + corWidth, frame.bottom, reactPaint);
canvas.drawRect(frame.right - corLength, frame.bottom, frame.right + corWidth, frame.bottom + corWidth, reactPaint);
}
//制作遮罩
private void drawMaskView(Canvas canvas, Rect frame) {
canvas.drawRect(frame.left, frame.top, frame.right, frame.bottom, paint);
}
到此,咱们还剩最终一个扫描线的动画作用,这条线其实就是一张图片,首先需要将图片以Bitmap形式制作在扫描区域内,然后经过ValueAnimator来操控图片Y坐标点,这样就能到达图片上下移动的作用,至于由快到慢的作用是增加了插值器,这儿运用内置的DecelerateInterpolator,同学们能够根据自己想要的作用自己搭配。
if (valueAnimator == null) {
valueAnimator = ValueAnimator.ofInt(frame.top, frame.bottom-10);//图片Y坐标取值规模
valueAnimator.setDuration(3000);//单次动画时间3秒
valueAnimator.setInterpolator(new DecelerateInterpolator());//由快到慢插值器
valueAnimator.setRepeatMode(ValueAnimator.RESTART);//重复动画
valueAnimator.setRepeatCount(ValueAnimator.INFINITE);//无限次数
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
scanLineTop = (int) animation.getAnimatedValue();//当时时间获取的Y值
invalidate();//改写视图
}
});
valueAnimator.start();
}
到此就能够完成封面的作用,乃至能够增加其他酷炫作用,只要你敢想敢做。
总结
其实一些动效看似很杂乱,但经过仔细剖析,咱们能够将其拆分成多个简略的小块,将每个小块完成后再逐个拼装,最终到达完整的作用。本节主要是经过自定义View完成,用到制作矩形框(drawRect),属性动画(ValueAnimator),两者运用也是十分简略。别的需要留意动画的运用和开释,防止导致不必要的内存泄漏。
好了,以上就是本篇所有内容,期望对大家有所协助!
敞开成长之旅!这是我参加「日新方案 2 月更文挑战」的第 27 天,点击检查活动概况