CodeFlys
12/21/2019 - 6:09 AM

CameraView

class CameraView @JvmOverloads constructor(
    context: Context, @Nullable attrs: AttributeSet? = null,
    defStyleAttr: Int = 0,
    defStyleRes: Int = 0
) : View(context, attrs, defStyleAttr, defStyleRes) {

    private var bitmapWidth: Float = dp2px(200F)
    private var bitmap: Bitmap
    private val paint: Paint = Paint(Paint.ANTI_ALIAS_FLAG)
    private val camera: Camera = Camera()

    var topFlip: Float = -0F // -45
        set(value) {
            field = value
            invalidate()
        }

    var bottomFlip: Float = 0F // 45
        set(value) {
            field = value
            invalidate()
        }
    var flipRotate: Float = 0F // 90
        set(value) {
            field = value
            invalidate()
        }

    init {
        bitmap = getTargetWidthBitmap(bitmapWidth.toInt())
    }


    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)


        camera.save()
        canvas.save()
        canvas.translate(width / 2F, height / 2F)
        canvas.rotate(-flipRotate)
        camera.rotateX(topFlip)
        camera.setLocation(0F, 0F, -4 * resources.displayMetrics.density)
        camera.applyToCanvas(canvas)
        canvas.clipRect(-bitmapWidth, -bitmapWidth, bitmapWidth, 0F)
        canvas.rotate(flipRotate)
        canvas.translate(-width / 2F, -height / 2F)
        canvas.drawBitmap(bitmap, width / 2 - bitmapWidth / 2, height / 2 - bitmapWidth / 2, paint)
        canvas.restore()
        camera.restore()

        camera.save()
        canvas.save()
        canvas.translate(width / 2F, height / 2F)
        canvas.rotate(-flipRotate)
        camera.rotateX(bottomFlip)
        camera.setLocation(0F, 0F, -4 * resources.displayMetrics.density)
        camera.applyToCanvas(canvas)
        canvas.clipRect(-bitmapWidth, 0F, bitmapWidth, bitmapWidth)
        canvas.rotate(flipRotate)
        canvas.translate(-width / 2F, -height / 2F)
        canvas.drawBitmap(bitmap, width / 2 - bitmapWidth / 2, height / 2 - bitmapWidth / 2, paint)
        canvas.restore()
        camera.restore()
    }

    private fun getTargetWidthBitmap(targetWidth: Int): Bitmap {
        val options: BitmapFactory.Options = BitmapFactory.Options()
        options.inJustDecodeBounds = true
        BitmapFactory.decodeResource(resources, R.drawable.wechat, options)
        options.inJustDecodeBounds = false
        options.inDensity = options.outWidth
        options.inTargetDensity = targetWidth
        return BitmapFactory.decodeResource(resources, R.drawable.wechat, options)
    }

    private fun dp2px(dp: Float) = TypedValue.applyDimension(
        TypedValue.COMPLEX_UNIT_DIP,
        dp,
        Resources.getSystem().displayMetrics
    )

    /**
     * 动画
     */
    fun playAnimatorSet() {
        val animatorSet: AnimatorSet = AnimatorSet()

        val topFlipAnimator = ObjectAnimator.ofFloat(this, "topFlip", 0F, -45F)
        topFlipAnimator.startDelay = 1000
        topFlipAnimator.duration = 1000

        val bottomFlipAnimator = ObjectAnimator.ofFloat(this, "bottomFlip", 0F, 45F)
        bottomFlipAnimator.startDelay = 1000
        bottomFlipAnimator.duration = 1000

        val flipRotateAnimator = ObjectAnimator.ofFloat(this, "flipRotate", 0F, 90F)
        flipRotateAnimator.startDelay = 1000
        flipRotateAnimator.duration = 1000

        animatorSet.playSequentially(bottomFlipAnimator, flipRotateAnimator, topFlipAnimator)
        animatorSet.startDelay = 1000
        animatorSet.start()
    }
}