繁体   English   中英

如何获得 Canvas 绘制弧形触摸监听器? (安卓)

[英]How to get Canvas draw arc touch listener? (Android)

如何获得画布弧形触摸监听器。

我正在创建一个带有动态弧的饼图。 单击圆弧时我需要执行一些任务(为此我需要知道单击了哪个圆弧)。

View 的 onTouchEvent 只是给出了我们可以从中获得 x & y 坐标的事件,但这里的弧线有厚度。

如何获得每个弧的点击侦听器?

注意 - 请不要推荐任何图书馆

需要建立这种饼图https://camo.githubusercontent.com/7e8a4a3c938c21d032d44d999edd781b6e146f2a/68747470733a2f2f7261772e6769746875622e636f6d2f5068696c4a61792f4d50416e64726f696443686172742f6d61737465722f73637265656e73686f74732f73696d706c6564657369676e5f7069656368617274312e706e67

我目前的实施

private lateinit var mRectF: RectF
    private lateinit var mRectFInner: RectF
    private lateinit var mPaint: Paint

    private lateinit var mCanvas: Canvas
    private var isTouched = false
    private lateinit var mBitmap:Bitmap

    private var pieChartItemList = arrayListOf<PieChartItem>()
    private var innerOuterCircleGap: Float = 0F

    constructor(context: Context) : super(context) {
        init(null)
    }

    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
        init(attrs)
    }

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

    private fun init(@Nullable set: AttributeSet?) {
        mPaint = Paint(Paint.ANTI_ALIAS_FLAG)
        var typedArray = context.obtainStyledAttributes(set, R.styleable.MyCustomView)
        innerOuterCircleGap = typedArray.getFloat(R.styleable.MyCustomView_innerOuterCircleGap, 0F)
    }

    //onDraw is called several times - so don't
    override fun onDraw(canvas: Canvas?) {
        drawPieChart(canvas)
    }

    private fun drawPieChart(canvas: Canvas?) {
        var unselectedConstant = 10
        mPaint.color = Color.BLACK
        canvas?.drawRect(0F, 0F, width.toFloat() - unselectedConstant, width.toFloat() - unselectedConstant, mPaint)
        mRectF = RectF(0F, 0F, width.toFloat() - unselectedConstant, height.toFloat() - unselectedConstant)
        mRectFInner = RectF(innerOuterCircleGap, innerOuterCircleGap, width.toFloat() - innerOuterCircleGap - unselectedConstant,
                height.toFloat() - innerOuterCircleGap - unselectedConstant)

        var startAngle = 0F
        var sweepAngle: Float
        var radius: Float = width.toFloat() / 2
        Log.e("ANKUSH", "width = $width height = $height radius = $radius")
        for (i in 0 until pieChartItemList.size) {
            sweepAngle = (pieChartItemList[i].percent * 3.6).toFloat()
            Log.e("ANKUSH - SweepAngle $i", sweepAngle.toString())
            mPaint.color = pieChartItemList[i].color
            canvas?.drawArc(mRectF, startAngle, sweepAngle, true, mPaint)
            startAngle += sweepAngle
        }

        if (isTouched) {
            mRectF = RectF(0F, 0F, width.toFloat() - unselectedConstant, height.toFloat() - unselectedConstant)
            mPaint.color = Color.RED
            canvas?.drawArc(mRectF, 0F, 45F, true, mPaint)
        }
        mPaint.color = Color.WHITE
        canvas?.drawArc(mRectFInner, 0F, 360F, true, mPaint)
    }

    fun setPieChartItems(itemList: ArrayList<PieChartItem>) {
        pieChartItemList = itemList
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        val w = MeasureSpec.getSize(widthMeasureSpec)
        val h = MeasureSpec.getSize(heightMeasureSpec)
        mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888)
        mCanvas = Canvas()
        mCanvas.setBitmap(mBitmap)
    }

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        if (event?.action == MotionEvent.ACTION_DOWN) {
            isTouched = true
            Log.e("ANKUSH", mBitmap?.getPixel(event.x.toInt(), event.y.toInt()).toString())
            invalidate()
        }
        return super.onTouchEvent(event)
    }

面临同样的问题。 终于找到了使用此函数将点击坐标转换为角度的解决方案。

    private fun convertTouchEventPointToAngle(xPos: Float, yPos: Float): Double {
    var x = xPos - (width * 0.5f)
    val y = yPos - (height * 0.5f)

    var angle = Math.toDegrees(atan2(y.toDouble(), x.toDouble()) + Math.PI / 2)
    angle = if (angle < 0) angle + 360 else angle
    return angle
}

在文章https://enginebai.com/2018/05/07/android-custom-view/上找到,所以可能会有所帮助。

您需要存储事件并根据以下内容绘制它:

override fun onTouchEvent(event: MotionEvent?): Boolean {
    if (event?.action == MotionEvent.ACTION_DOWN) {
        isTouched = true
        touchedAtX = event.x.toInt()
        touchedAtY = event.x.toInt()
        Log.e("ANKUSH", mBitmap?.getPixel(event.x.toInt(), event.y.toInt()).toString())
        invalidate()
    }
    return super.onTouchEvent(event)
}

并修改onDraw

for (i in 0 until pieChartItemList.size) {
        sweepAngle = (pieChartItemList[i].percent * 3.6).toFloat()
        Log.e("ANKUSH - SweepAngle $i", sweepAngle.toString())
        mPaint.color = pieChartItemList[i].color
        canvas?.drawArc(mRectF, startAngle, sweepAngle, true, mPaint)
        startAngle += sweepAngle
        if (isTouched && mRectF.contains(touchedAtX, touchedAtY) {
            canvas?.drawArc(mRectF, startAngle - 15, sweepAngle + 15, true, mPaint)
        }
    }

请注意,我的代码在进行碰撞检测时没有考虑 startAngle 和扫描角度,但是您需要根据其坐标接触到哪个特定拱门的内容来了解​​。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM