I. Any areaclickableThe line chart

Maybe we’re out of cool here, right? For many custom views, it is possible to manipulate every text or area you want to click on. And go do something you can’t even imagine doing? Let’s say I click on the text above. Fly up in a bubble? Ha-ha. So we’re gonna try to play?

. As you can see in the picture below, each text box I click is correctly calculated to the position, so how exactly to calculate the desired position?

1. Click the event in the canvas area

  • Next I click in the upper left corner of my custom View and print the coordinates in onTouch(event.x,event.y):
   @SuppressLint("ClickableViewAccessibility")
    override fun onTouchEvent(event: MotionEvent): Boolean {
        if (event.action == MotionEvent.ACTION_DOWN) {
           Log.e("onTouchEvent"."onTouchEvent:x"+event.x )
           Log.e("onTouchEvent"."onTouchEvent:y"+event.y )
     
        return super.onTouchEvent(event)
    }
 }
 // Click the upper-left result:
E/onTouchEvent: onTouchEvent:x0. 0
E/onTouchEvent: onTouchEvent:y8996094.
E/onTouchEvent: onTouchEvent:x0. 0
E/onTouchEvent: onTouchEvent:y19501953.

// Click the sitting corner
E/onTouchEvent: onTouchEvent:x0. 0
E/onTouchEvent: onTouchEvent:y7303877.

// Click on the upper right corner

E/onTouchEvent: onTouchEvent:y2308789.
E/onTouchEvent: onTouchEvent:x10272656.
E/onTouchEvent: onTouchEvent:y2308789.
E/onTouchEvent: onTouchEvent:x10272656.
E/onTouchEvent: onTouchEvent:y2308789.

// Click on the lower right corner
E/onTouchEvent: onTouchEvent:x10272656.
E/onTouchEvent: onTouchEvent:y7233418.
E/onTouchEvent: onTouchEvent:x10272656.
E/onTouchEvent: onTouchEvent:y7233418.

Copy the code

X and event.y are not the same as our transformed coordinate system. We’re just changing the canvas coordinate system. But the View’s on-screen click coordinate doesn’t change.

  • The same planetheAny two coordinate systemsCan pass,rotating.The zoom.translationI’m going to transform and overlap. X,envent.y) and (Canvas. x,canvas.y)One-to-one mapping. And both coordinate systems are defined bypixelAs the unit. In case of confusion, the figure above draws two overlapping coordinate systems, red is the click event coordinate system and black is the Canvas coordinate system. The mapping relationship can be derived from this:
1.After we click on the click event coordinate system is got in (event. X, event, y) = (measureWidth measureHeight)2.MeasureWidth = measureWidth, measureWidth = measureWidth, measureWidth = measureWidth0)3.X,canvas.y) = (Event. X, MeasureWidth-Event. Y)4.Because our canvas frame sets the margin here we get (canvas. X, canvas, y) = (event. X-ray marginXAndY measureHeight - event. Y - marginXAndY)Copy the code

Here we simply get the relation of direct mapping of two coordinates:

(canvas. X, canvas, y) = (event. X-ray marginXAndY measureHeight - event. Y - marginXAndY)

We have no problem with coordinate mapping here. How do you verify whether it’s wrong or correct? For the text we drew, we did Paint. There was no Paint. SetOnclick click. This is passive, but Rect provides the Contais function to determine whether a point is inside a rectangular region.

Of course, apis need to be looked at and worked on. How do you tell if a point is in a region inside a plane coordinate system? I don’t want to talk about the following code.

  • x >= left && x < right && y >= top && y < bottom

This gives us a big break. We remember that the layout drew the text and drew the background of the text through Rect. Each fixed point corresponds to a text and the corresponding text Rect background. So we store the Rect when we draw the text background. Of course, if you think that’s what you want to click on in the canvas, you can go through Rect.

  • Store the Rect
rctArrayList.add(Rect(pointList[index].x.toInt(), pointList[index].y.toInt(), (pointList[index].x+titleWidth).toInt(), (pointList[index].y+getTextHeight(text_paint)).toInt()))
Copy the code

For the interception of click events we operate in onTachEvent, do not clear another click event close article.

override fun onTouchEvent(event: MotionEvent): Boolean { if (event.action == MotionEvent.ACTION_DOWN) { clickDow=true return true } if (event.action == ACTION_UP&&clickDow) {for (index in 0 until rctarrayList.size){// Convert the coordinates to val to determine whether the text background box is inside the region contais=rctArrayList[index].contains((event.x.toInt()-marginXAndY).toInt(), (Measuredheight-marginxandy - event.y.toint ()).toint ()) if (contais){ToastUtils. ShowLong (" Click text =$index") break}} clickDow=false } return super.onTouchEvent(event) }Copy the code

It’s very accurate. What can’t we do at this point? Click each time to modify the content in the upper right corner of canvas, basic operation.

Here we can also pinpoint click events so that good interactions can be created

1. Regional click brings excitement

Echars all have a special effect can we implement it?

Here we first implement the above effect “click the section to pop up a box to display the content”. For curve what animation is base operation, don’t say curve, learned the basic principle of Bessel curve. We knife, people, building…… Anything that can be seen can be drawn with reason. Here’s an example to keep the soldiers calm.

We have precisely located the position in the canvas through the above clickable event and the Canvas coordinate transformation mapping, and the next code operation.

1.Define a Rect globally2.Click inside the event to create an initial dynamic 🉐️Rect3.Set the timer to set the display of disappearing time and other operations.Copy the code
  • The first step is easy. The second step is to create the Rect below the circle in the image. For the content, you can see the data itself. Why do we have a little black box. Keep it simple. It’ll take a few minutes to draw a frame. Rect let’s not die like me. Now that we’ve learned how to measure fonts so you can be strict, I’ll just write it down here.
Don't forget the formula above: (canvas. X, canvas, y) = (event. X-ray marginXAndY measureHeight - event. Y - marginXAndY) var x = event. The X-ray marginXAndY var Rect(left,top,right,bottom)=Rect(x-100,y,x+100,y-200); Rect(left,top,right,bottom)=Rect(x-100,y,x+100,y-200)Copy the code

  • Step 1: Create a global variable and initialize it in the click event.
/ / global... Of course you can get the coordinates. I can do whatever I want to do.
 var blackRect: Rect? = null
 // use it to determine whether to display black boxes
 var visible = false
 


 
 
 
//2. Click time to initialize Rect
@SuppressLint("ClickableViewAccessibility")
    override fun onTouchEvent(event: MotionEvent): Boolean {
        if (event.action == MotionEvent.ACTION_DOWN) {
            clickDow = true
            return true
        }
        if (event.action == MotionEvent.ACTION_UP && clickDow) {
            for (index in 0 until rctArrayList.size) {
                // Convert the coordinates to
                val contais = rctArrayList[index].contains((event.x.toInt() - marginXAndY).toInt(), (measuredHeight - marginXAndY - event.y.toInt()).toInt())
                if (contais) {
                    ToastUtils.showLong("Click text =$index")
                    rightTopSubject = titleList[index]
                    // Initialize Rect
                    val x = event.x - marginXAndY
                    val y = measuredHeight - event.y - marginXAndY
                    // It is important to specify the direction of the coordinate system
                    blackRect = Rect((x - 70).toInt(), y.toInt(), (x + 70).toInt(), (y - 200).toInt())
                    / / can be displayed
                    visible=true
                    invalidate()
                    // Of course animation can be refreshed... It's just a little bit of an easy thing to do here
                    postDelayed({
                        visible=false
                        invalidate()
                    }, 2000)
                    break
                }
            }
            clickDow = false
        }
        return super.onTouchEvent(event)
    }
    
    
//3. Draw the code of the pop-up box
 private fun drawWindowRect(canvas: Canvas) {
        if(blackRect ! =null && visible) {
            val rrPaint = Paint()
            rrPaint.color = Color.BLACK
            rrPaint.style = Paint.Style.FILL
            rrPaint.strokeWidth = 1f
            rrPaint.setShadowLayer(5f, -5f, -5f, Color.argb(50.111.111.111))
            // Make a rounded corner here... Avoid too uglycanvas.drawRoundRect(blackRect!! .left.toFloat(), blackRect!! .top.toFloat(), blackRect!! .right.toFloat(), blackRect!! .bottom.toFloat(),10f.10f, rrPaint) canvas.save() canvas.translate(blackRect!! .left.toFloat(), blackRect!! .top.toFloat()) canvas.scale(1f, -1f)

            val ttPaint = Paint()
            ttPaint.color = Color.WHITE
            ttPaint.style = Paint.Style.FILL
            ttPaint.strokeWidth = 1f
            ttPaint.strokeCap = Paint.Cap.ROUND
            ttPaint.textSize = 24f
            //0f,0f is the dot, 20f,30f is the offset that I am not going to measure the text directly.
            canvas.drawText("M:${rightTopSubject}".0f + 20f.0f + 30f, ttPaint)
        }

    }
   
Copy the code

Look at the effect as follows: looks like this effect has, as for the pop-up to avoid repeated appearance, you can optimize…