Draw RectF on canvas

863 views Asked by At

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

2

There are 2 answers

1
Lakhwinder Singh On BEST ANSWER

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?)
    }
}
5
M.ekici On

I assume that your calendar view and the view you will implement in the same size you can achieve it the xml file. To draw a rect each position change you can create a method in the your custom view class.

fun onRectTranslated(dx:Int, y:Int){
    mRect.offset(dx,dy)
    postInvalidateOnAnimation()
}

Then in you onDraw() callback:

 override fun onDraw(canvas: Canvas?) {
    super.onDraw(canvas)
    canvas?.drawRect(mRect,mRectPaint)
}

In you initialisation phase you can create the mRect object as Rect.Then you apply changes on this rect then invalidates the view so the system calls onDraw again for your view. Additionally, you have to create a paint object for the drawing.