在 canvas 上绘制 RectF
Draw RectF on canvas
我有一个视图(日历),其中包含绘制在其上的多个矩形(事件),现在我正在尝试将 drag/drop 实现为该视图之上的另一层。示例-我长按一个事件,它向我传递了 Rect(Event) 的确切坐标,不,我创建了一个自定义视图,它将绘制相同的 Rect(因为我有坐标)
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)
}
}
现在监听器会在长按事件时将坐标传给我。
现状:我把上面的视图放在XML(在日历视图的顶部),当我得到坐标时就让它可见,但是不知道如何在上面画Rect,因为它已经初始化了。
如果我遗漏了一些信息,请在评论中告诉我,我会更新问题
我假设您的日历视图和您将实现的视图大小相同,您可以在 xml 文件中实现它。要在每个位置更改时绘制一个矩形,您可以在自定义视图中创建一个方法 class.
fun onRectTranslated(dx:Int, y:Int){
mRect.offset(dx,dy)
postInvalidateOnAnimation()
}
然后在你onDraw()
回调:
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
canvas?.drawRect(mRect,mRectPaint)
}
在您的初始化阶段,您可以创建 mRect 对象,因为 Rect.Then 您在此矩形上应用更改,然后使视图无效,以便系统再次为您的视图调用 onDraw。此外,您必须为绘图创建一个绘画对象。
我创建了一个自定义视图,它将在同一坐标上绘制事件并可以移动该事件
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?)
}
}
我有一个视图(日历),其中包含绘制在其上的多个矩形(事件),现在我正在尝试将 drag/drop 实现为该视图之上的另一层。示例-我长按一个事件,它向我传递了 Rect(Event) 的确切坐标,不,我创建了一个自定义视图,它将绘制相同的 Rect(因为我有坐标)
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)
}
}
现在监听器会在长按事件时将坐标传给我。
现状:我把上面的视图放在XML(在日历视图的顶部),当我得到坐标时就让它可见,但是不知道如何在上面画Rect,因为它已经初始化了。
如果我遗漏了一些信息,请在评论中告诉我,我会更新问题
我假设您的日历视图和您将实现的视图大小相同,您可以在 xml 文件中实现它。要在每个位置更改时绘制一个矩形,您可以在自定义视图中创建一个方法 class.
fun onRectTranslated(dx:Int, y:Int){
mRect.offset(dx,dy)
postInvalidateOnAnimation()
}
然后在你onDraw()
回调:
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
canvas?.drawRect(mRect,mRectPaint)
}
在您的初始化阶段,您可以创建 mRect 对象,因为 Rect.Then 您在此矩形上应用更改,然后使视图无效,以便系统再次为您的视图调用 onDraw。此外,您必须为绘图创建一个绘画对象。
我创建了一个自定义视图,它将在同一坐标上绘制事件并可以移动该事件
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?)
}
}