美文网首页
简单的星球旋转自定义View

简单的星球旋转自定义View

作者: Android小豆渣 | 来源:发表于2022-02-25 10:03 被阅读0次

效果图:


企业微信截图_1645408447599.png

代码如下:

/**
 * @CreateDate: 2021/1/28 11:32
 * @Author: ZZJ
 * @Description: pk匹配View
 */
class PkMatchingView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {

    /**
     * 画笔
     * */
    private val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        style = Paint.Style.STROKE
        strokeCap = Paint.Cap.ROUND
    }

    /**
     *中间球形大小  默认364像素
     * */
    private var mSphereSize = 182f.px

    /**
     *小弧形半径
     * */
    private var smallRadius = 0f

    /**
     *大弧形半径
     * */
    private var largeRadius = 0f

    /**
     * 中间球形到小弧形的距离 默认60f
     * */
    private var smallDistance = 100f

    /**
     * 大弧形到小弧形的距离 默认60f
     * */
    private var largeDistance = 80f

    /**
     * 弧线宽度
     * */
    private var arcWide = 12f

    /**
     * 小弧线长度(对应角度)
     * */
    private var smallLength = 90f

    /**
     * 大弧线长度(对应角度)
     * */
    private var largeLength = 90f

    /**
     * 圆形大小
     * */
    private var circleSize = 40f

    /**
     * 圆形颜色
     * */
    private var circleColor = Color.parseColor("#47CBDE")

    /**
     * 渐变颜色集(有透明度)
     * */
    private val mColors = intArrayOf(
        Color.parseColor("#4c92f0fe"),
        Color.parseColor("#9925e2fd"),
        Color.parseColor("#1992f0fe"),
        Color.parseColor("#9925e2fd"),
        Color.parseColor("#1992f0fe"),
        Color.parseColor("#9925e2fd"),
        Color.parseColor("#4c92f0fe")
    )

    /**
     * 小弧形区域
     * */
    private val smallRectF = RectF()

    /**
     * 大弧形区域
     * */
    private val largeRectF = RectF()

    /**
     * 小弧形圆点增值
     * */
    private var smallValue = 0.0

    /**
     * 小弧形圆点增值速度
     * */
    private var smallSpeed = 0.3

    /**
     * 用于保存小弧圆点角度
     * */
    private var smallDegrees = 0.0

    /**
     * 小弧形圆点是否相反移动
     * */
    private var smallContrary = true

    /**
     * 大弧形圆点增值
     * */
    private var largeValue = 0.0

    /**
     * 小弧形圆点增值速度
     * */
    private var largeSpeed = 0.25

    /**
     * 用于保存大弧圆点角度
     * */
    private var largeDegrees = 0.0

    /**
     * 大弧形圆点是否相反移动
     * */
    private var largeContrary = true

    /**
     * 渐变色Shader
     * */
    private var mShader: Shader? = null

    /**
     * view的最小宽高
     * */
    private var miniSize =
        (mSphereSize + (smallDistance + largeDistance + arcWide) * 2 + circleSize / 2).toInt()

    /**
     * 旋转角度
     * */
    @SuppressLint("AnimatorKeep")
    var rotationAngle = 0f
        set(value) {
            field = value
            invalidate()
        }

    /**
     * 小弧形开始角度
     * */
    @SuppressLint("AnimatorKeep")
    var smallStartAngle = 225f
        set(value) {
            field = value
            invalidate()
        }

    /**
     * 大弧形开始角度
     * */
    @SuppressLint("AnimatorKeep")
    var largeStartAngle = 225f
        set(value) {
            field = value
            invalidate()
        }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        val width = resolveSize(miniSize, widthMeasureSpec)
        val height = resolveSize(miniSize, heightMeasureSpec)
        setMeasuredDimension(min(width, height), min(width, height))
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        //根据控件宽高 重新校对值(中间球大小取决于弧形边距)
        if (miniSize > width) {
            mSphereSize = ((width - circleSize) / 2 - smallDistance - largeDistance) * 2
        }
        smallRadius = smallDistance + (mSphereSize / 2)
        largeRadius = smallRadius + largeDistance

        smallRectF.set(
            width / 2f - smallRadius,
            height / 2f - smallRadius,
            width / 2f + smallRadius,
            height / 2f + smallRadius
        )
        largeRectF.set(
            width / 2f - largeRadius,
            height / 2f - largeRadius,
            width / 2f + largeRadius,
            height / 2f + largeRadius
        )

        mShader = SweepGradient(width / 2f, height / 2f, mColors, null)

        val rotationAnimator = ObjectAnimator.ofFloat(this, "rotationAngle", 0f, 360f)
        rotationAnimator.repeatMode = ObjectAnimator.RESTART//匀速
        rotationAnimator.repeatCount = ValueAnimator.INFINITE//永久循环


        val radianAnimator1 = ObjectAnimator.ofFloat(this, "smallStartAngle", 360f, 0f)
        radianAnimator1.repeatMode = ObjectAnimator.RESTART//匀速
        radianAnimator1.repeatCount = ValueAnimator.INFINITE//永久循环

        val radianAnimator2 = ObjectAnimator.ofFloat(this, "largeStartAngle", 80f, 440f)
        radianAnimator2.repeatMode = ObjectAnimator.RESTART//匀速
        radianAnimator2.repeatCount = ValueAnimator.INFINITE//永久循环


        val animatorSet = AnimatorSet()
        animatorSet.playTogether(rotationAnimator, radianAnimator1, radianAnimator2)
        animatorSet.duration = 4000
        animatorSet.interpolator = LinearInterpolator()
        animatorSet.start()
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        //画中间球
        drawRotateBitmap(
            canvas,
            paint,
            getAvatar(mSphereSize),
            rotationAngle,
            (width - mSphereSize) / 2,
            (height - mSphereSize) / 2
        )

        //画圆弧
        paint.shader = mShader
        paint.strokeWidth = arcWide

        canvas.drawArc(smallRectF, smallStartAngle, 90f, false, paint)

        canvas.drawArc(smallRectF, smallStartAngle + 90f + 90f, 90f, false, paint)

        canvas.drawArc(largeRectF, largeStartAngle, 90f, false, paint)

        canvas.drawArc(largeRectF, largeStartAngle + 90f + 90f, 90f, false, paint)

        //画圆点

        paint.strokeWidth = circleSize
        paint.shader = null
        paint.color = circleColor

        //画小弧点
        //degrees 225..315
        smallDegrees = smallStartAngle + smallValue
        if (smallDegrees >= (smallStartAngle + smallLength)) {
            smallContrary = false
        } else if (smallDegrees <= smallStartAngle) {
            smallContrary = true
        }

        if (smallContrary) {
            smallValue += smallSpeed
        } else {
            smallValue -= smallSpeed
        }
        paint.strokeWidth = circleSize - 5
        var radians1 = Math.toRadians(smallDegrees)
        canvas.drawPoint(
            (width / 2f + cos(radians1) * smallRadius).toFloat(),
            (height / 2f + sin(radians1) * smallRadius).toFloat(),
            paint
        )

        //degrees 405..495
        paint.strokeWidth = circleSize
        radians1 = Math.toRadians((smallStartAngle + 180 + smallValue))
        canvas.drawPoint(
            (width / 2f + cos(radians1) * smallRadius).toFloat(),
            (height / 2f + sin(radians1) * smallRadius).toFloat(),
            paint
        )


        //画大弧点
        //degrees 125..215
        largeDegrees = largeStartAngle + largeValue
        if (largeDegrees >= (largeStartAngle + largeLength)) {
            largeContrary = false
        } else if (largeDegrees <= largeStartAngle) {
            largeContrary = true
        }
        if (largeContrary) {
            largeValue += largeSpeed
        } else {
            largeValue -= largeSpeed
        }
        paint.strokeWidth = circleSize - 5
        var degrees2 = largeStartAngle + largeValue
        var radians2 = Math.toRadians(degrees2)
        canvas.drawPoint(
            (width / 2f + cos(radians2) * largeRadius).toFloat(),
            (height / 2f + sin(radians2) * largeRadius).toFloat(),
            paint
        )

        //degrees 305..395
        paint.strokeWidth = circleSize
        degrees2 = largeStartAngle + 180 + largeValue
        radians2 = Math.toRadians(degrees2)
        canvas.drawPoint(
            (width / 2f + cos(radians2) * largeRadius).toFloat(),
            (height / 2f + sin(radians2) * largeRadius).toFloat(),
            paint
        )

    }

    private fun drawRotateBitmap(
        canvas: Canvas, paint: Paint, bitmap: Bitmap,
        rotation: Float, posX: Float, posY: Float
    ) {
        val matrix = Matrix()
        val offsetX = bitmap.width / 2f
        val offsetY = bitmap.height / 2f
        matrix.postTranslate(-offsetX, -offsetY)
        matrix.postRotate(rotation)
        matrix.postTranslate(posX + offsetX, posY + offsetY)
        canvas.drawBitmap(bitmap, matrix, paint)
    }

    //获取指定大小的Bitmap
    private fun getAvatar(width: Float): Bitmap {
        val options = BitmapFactory.Options()
        options.inJustDecodeBounds = true
        BitmapFactory.decodeResource(resources, R.drawable.ic_pk_matching, options)
        options.inJustDecodeBounds = false
        options.inDensity = options.outWidth
        options.inTargetDensity = width.toInt()
        return BitmapFactory.decodeResource(resources, R.drawable.ic_pk_matching, options)
    }
}

相关文章

网友评论

      本文标题:简单的星球旋转自定义View

      本文链接:https://www.haomeiwen.com/subject/peiblrtx.html