[英]How to get Canvas draw arc touch listener? (Android)
如何获得画布弧形触摸监听器。
我正在创建一个带有动态弧的饼图。 单击圆弧时我需要执行一些任务(为此我需要知道单击了哪个圆弧)。
View 的 onTouchEvent 只是给出了我们可以从中获得 x & y 坐标的事件,但这里的弧线有厚度。
如何获得每个弧的点击侦听器?
注意 - 请不要推荐任何图书馆
我目前的实施
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.