自定义 View 实现扫描效果

演示效果如下:
在这里插入图片描述

实现内容:

  1. 控制动画是竖向或者横向
  2. 控制动画初始是从底部/左边开始,或者从上边/右边开始
  3. 控制动画的时常
  4. 可以自定义动画素材

具体实现:

自定义属性:

<declare-styleable name="ScanView" tools:ignore="ResourceName">
    <!--扫描的图片-->
    <attr name="unit_scan_img" format="reference" />
    <!--动画时长-->
    <attr name="anim_duration" format="integer" />
</declare-styleable>

自定义 View:

实现原理,就是对 bitmap 做 Translate、preScale 转换,然后不断的 draw bitmap。其中 Translate 是为了实现位移效果,preScale 则是为了来回转换方向。

class ScanView : View {
   

    /**
     * 扫描的图片drawable
     */
    private var scanImg: Drawable? = null
    private lateinit var paint: Paint
    /**
     * 控件的宽
     */
    private var viewWidth: Int = 0
    /**
     * 控件的高
     */
    private var viewHeight: Int = 0
    private var bitmapMatrix = Matrix()
    
    private var scanBitmap: Bitmap? = null
    
    /**
     * 扫描图片需要显示的高度
     */
    private var showBitmapHeight: Float = 0F

	/**
     * 控制动画是竖向或者横向
     */
    private var isVertical = true
    /**
     * 控制动画初始是从底部/左边开始(true),或者从上边/右边开始(false)
     */
    private var isStartFromBottom = true

    private var isPositive = true

    fun setVertical(isVertical: Boolean) {
   
        this.isVertical = isVertical
        stopScanAnimAndReset()
        setScanBitmap()
    }

    fun setStartFromBootom(isFromBottom: Boolean) {
   
        this.isStartFromBottom = isFromBottom
        stopScanAnimAndReset()
    }

    /**
     * 属性动画
     */
    private var valueAnimator: ValueAnimator? = null

    /**
     * 动画时长
     */
    private var animDuration: Long = 1000L

    constructor(context: Context) : this(context, null)
    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
   
        initAttribute(context, attrs)
        init()
    }

    private fun initAttribute(context: Context, attrs: AttributeSet?) {
   
        attrs?.let {
   
            val typedArray = context.obtainStyledAttributes(attrs, R.styleable.ScanView)
            scanImg = typedArray.getDrawable(R.styleable.ScanView_unit_scan_img)
            animDuration = typedArray.getInt(R.styleable.ScanView_anim_duration, 1000).toLong()
            typedArray.recycle()
        }
    }

    fun setAnimDuration(time: Long) {
   
        animDuration = time
    }

    private fun init() {
   
        paint = Paint(Paint.ANTI_ALIAS_FLAG)
        paint.style = Paint.Style.FILL
    }

    private fun getBitmapFromDrawable(drawable: Drawable): Bitmap? {
   
        var unitImgBitmap = drawable.toBitmap()

        if (unitImgBitmap.isRecycled) {
   
            return null
        }

        if (unitImgBitmap.isRecycled) {
   
            return null
        }

        // 处理横置的时候图片的旋转(因为视觉给的图一般是一个竖向的图,因此在横置的时候,手动将图片同步横置)
        if (!isVertical) {
   
            val matrix = Matrix(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值