Android 自定义View 使用Kotlin编写雷达扫描效果
2017-07-22 19:18 阅读(338)

效果图

radar

使用SweepGradient作为paint的shader,用于绘制 
paint的color也会影响shader 
利用handler不断发送消息,不断改变canvas.drawArc()中的起始角度

kotlin中认为类似”0xffffffff”这样,0x后面跟8位数的是long值,在用于颜色时,必须转为Int 
在声明Handler成员属性时,不要声明成handler,因为View中有个方法为public Handler getHander(); 所以kotlin会认为你重写定义了一个属性

package com.stone.stoneviews.widget

import android.content.Context
import android.graphics.*
import android.os.Handler
import android.os.Message
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View

/**
 * desc   :
 * author : stone
 * email  : aa86799@163.com
 * time   : 22/07/2017 11 37
 */

class RadarView: View {

    private var mRadius = 0f
    private var mPaint = Paint()
    private var mShader: SweepGradient? = null
    private var mRx = 0f
    private var mRy = 0f
    private val mRingCount = 4
    private var mRect: RectF = RectF()
    private var mSweepStartAngle = 0f
    private var mSweepAngle = 120f
    private var mSweepAngleSpeed = 10f
    private var mIsStartSweep = false
    private val STATE_START = 1
    private val STATE_STOP = 2

    private val mHandler = object : Handler() {
        override fun handleMessage(msg: Message) {
            val what = msg.what
            when (what) {
                STATE_START -> {
                    mSweepStartAngle += mSweepAngleSpeed
                    invalidate()
                    sendMessageDelayed(Message.obtain(this, STATE_START), 50)
                }

                STATE_STOP -> {
                    removeCallbacksAndMessages(null)
                }
            }
        }
    }

    constructor(context: Context) : super(context) {
        initParams(context, null, 0)
    }

    constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
        initParams(context, attrs, 0)
    }

    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
        initParams(context, attrs, defStyleAttr)
    }

    fun  initParams(context: Context, attrs: AttributeSet?, defStyleAttr: Int) {
        val w = resources.displayMetrics.widthPixels
        val h = resources.displayMetrics.heightPixels
        val min = Math.min(w, h)
        mRadius = (min / 2 - 50).toFloat()
        mRx = (w / 2).toFloat()
        mRy = (h / 2).toFloat()

        mPaint.isAntiAlias = true

        mRect = RectF(mRx - mRadius, mRy - mRadius, mRx + mRadius, mRy + mRadius)

    }

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

        mPaint.style = Paint.Style.FILL_AND_STROKE
        mPaint.color = Color.BLUE
        mPaint.shader = null
        canvas.drawCircle(mRx, mRy, mRadius, mPaint)

        mPaint.color = Color.parseColor("#abc07f")
        mPaint.style = Paint.Style.STROKE
        canvas.drawLine(mRx - mRadius, mRy, mRadius + mRx, mRy, mPaint)
        canvas.drawLine(mRx, mRy - mRadius, mRx, mRy + mRadius, mPaint)
        val eachRingUnit = mRadius / mRingCount
        var curRingRadius: Float = 0f
        (1 until mRingCount).forEach {
            curRingRadius += eachRingUnit
            canvas.drawCircle(mRx, mRy, curRingRadius, mPaint)
        }

//        mShader = SweepGradient(mRx, mRy, 0xddff00f0.toInt(), 0xffabc777.toInt())
        mShader = SweepGradient(mRx, mRy, intArrayOf(0xee191970.toInt(), 0xddff000f.toInt(), 0xddff00f0.toInt(), 0xaaff0000.toInt()),
                floatArrayOf(0.0f, 0.1f, 0.6f, 0.98f))
        mPaint.shader = mShader
        mPaint.style = Paint.Style.FILL_AND_STROKE
        mPaint.color = Color.parseColor("#ccffffff")
        canvas.drawArc(mRect, mSweepStartAngle, mSweepAngle, true, mPaint)

    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                mIsStartSweep = !mIsStartSweep
                if (mIsStartSweep) {
                    Message.obtain(mHandler, STATE_START).sendToTarget()
                } else {
                    Message.obtain(mHandler, STATE_STOP).sendToTarget()
                }
                return true
            }
        }

        return super.onTouchEvent(event)
    }
}