androidandroid-canvasandroid-custom-viewandroid-rect

Draw RectF on canvas


I have a view(Calendar) that contains multiple Rects(Events) drawn on it, now I am trying to implement drag/drop as another layer on top of that view. Example- I long-press on an event, it passes me the exact coordinates of the Rect(Event), no I have created a custom view which will draw the same Rect(because I have coordinates)

class DraggerView: View {


    constructor(context: Context) : this(context, null)
    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)


    override fun isInEditMode(): Boolean {
        return true
    }

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

    }
}

Now the listener will pass me the coordinates when long-press on an event.

Current situation: I put the above view in the XML(On Top of the calendar View) and just made it visible when I get the coordinates, but don't know how to draw Rect on it because it is already initialized.

If I miss something to provide as information, please let me know in the comments I'll update the question


Solution

  • I have created a custom view which will draw the event on the same coordinates and can move that event

    class DraggerView : View {
    
    
        constructor(context: Context) : this(context, null)
        constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
        constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
    
        private var availableWidth: Int = 0
        private var availableHeight: Int = 0
        private var title: String = ""
        private var rect: RectF? = null
        private val paintEvent = Paint()
        private val paintText: TextPaint = TextPaint(Paint.ANTI_ALIAS_FLAG or Paint.LINEAR_TEXT_FLAG).apply {
            isAntiAlias=true
            style = Paint.Style.FILL
            color = Color.WHITE
            textSize = 30f
            typeface = Typeface.create(Typeface.DEFAULT, Typeface.BOLD)
        }
        private var data: Event? = null
        private var draw = false
        var eventListener: EventListener? = null
    
        override fun isInEditMode(): Boolean {
            return true
        }
    
        @SuppressLint("NewApi")
        override fun onDraw(canvas: Canvas) {
            super.onDraw(canvas)
            if (draw) {
                canvas.save()
                canvas.drawColor(ContextCompat.getColor(context, R.color.shadow))
                rect?.let { rectF ->
                    canvas.drawRoundRect(rectF, 10f, 10f, paintEvent)
                    val x = rectF.left + 10
                    val y = rectF.top + 10
    
                    val layout = StaticLayout.Builder.obtain(title, 0, title.length, paintText, availableWidth)
                            .setAlignment(Layout.Alignment.ALIGN_NORMAL)
                            .setLineSpacing(0.0f, 1.0f)
                            .setIncludePad(false)
                            .build()
                    canvas.translate(x, y)
                    layout.draw(canvas)
    
                }
                canvas.restore()
            }
    
        }
    
        fun drawEvent(rectF: RectF, data: Event) {
            draw = true
            rect = rectF
            this.data = data
            title = data.title
            availableWidth = rectF.right.minus(rectF.left).toInt()
            availableHeight = rectF.bottom.minus(rectF.top).toInt()
            paintEvent.color = data.color
            invalidate()
        }
    
    
        @SuppressLint("ClickableViewAccessibility")
        override fun onTouchEvent(event: MotionEvent?): Boolean {
            val xMove = event?.x ?: 0f
            val yMove = event?.y ?: 0f
            when (event?.action) {
                MotionEvent.ACTION_UP -> {
                    draw = false
                    eventListener?.onEventDrop(rect, data)
                }
                MotionEvent.ACTION_MOVE -> {
                    val newLeft = xMove - (availableWidth / 2)
                    val newTop = yMove - (availableHeight / 2)
                    val newRight = xMove + (availableWidth / 2)
                    val newBottom = yMove + (availableHeight / 2)
    
                    rect?.let {
                        it.left = newLeft
                        it.top = newTop
                        it.right = newRight
                        it.bottom = newBottom
                    }
                    // we might needed to scroll weekview when event
                    // dragged to right side of the screen
                    if (xMove > (width * 0.90)) {
                        eventListener?.onEventScrollRight(rect, data)
                    }
                    if (xMove < (width * 0.10)) {
                        eventListener?.onEventScrollLeft(rect, data)
                    }
                }
            }
            invalidate()
            return draw
        }
    
        interface EventListener {
            fun onEventDrop(rectF: RectF?, data: Event?)
            fun onEventScrollRight(rectF: RectF?, data: Event?)
            fun onEventScrollLeft(rectF: RectF?, data: Event?)
        }
    }