我正在尝试创建一个自定义视图,它填充了一个黑屏,然后可以通过在屏幕上绘制来显示下面的图像来进行擦除。我发现了一个旧的SO问题,它有一个旧的解决方案,但将其转换为Kotlin会给出关于第34行的高度为0的错误。下面是正在使用的代码。请注意,width被正确设置为1440,但height和measuredHeight也都为0。我以为将代码添加到this.doOnLayout中可以确保该函数只在视图展开后运行,但这似乎并不正确。
package com.imdevinc.mapcaster
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import android.view.View
import androidx.core.view.doOnLayout
class DrawView @JvmOverloads
constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0)
: View(context, attrs, defStyleAttr), View.OnTouchListener {
private val bmPaint = Paint()
private val drawPaint = Paint()
private val path = Path()
private var layoutUpdated = false
private lateinit var cv: Canvas
private lateinit var bm: Bitmap
init {
isFocusable = true
isFocusableInTouchMode = true
setOnTouchListener(this)
this.doOnLayout {
initCanvas()
}
}
fun initCanvas() {
Log.d("DrawView", "onDraw(): filling canvas")
// Create a new bitmap and canvas, fill it with a black mask
bm = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
cv = Canvas()
cv = Canvas()
cv.setBitmap(bm)
cv.drawColor(Color.BLACK)
Log.d("DrawView", "onDraw(): drawing black")
// Make the painting stroke fatter
drawPaint.style = Paint.Style.STROKE
drawPaint.strokeWidth = width / 15f
Log.d("DrawView", "onDraw(): updating stroke style")
// Clear pixels instead of painting new ones
drawPaint.xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR)
Log.d("DrawView", "onDraw(): setting xfer mode")
layoutUpdated = true
}
override fun onTouch(view: View?, event: MotionEvent): Boolean {
val xPos = event.x
val yPos = event.y
when(event.action) {
MotionEvent.ACTION_DOWN -> path.moveTo(xPos, yPos)
MotionEvent.ACTION_MOVE -> path.moveTo(xPos, yPos)
else -> return false
}
invalidate()
return true
}
override fun onDraw(canvas: Canvas) {
if (layoutUpdated) {
cv.drawPath(path, drawPaint)
Log.d("DrawView", "onDraw(): drawPath")
canvas.drawBitmap(bm, 0f, 0f, bmPaint)
Log.d("DrawView", "onDraw(): drawBitmap")
}
super.onDraw(canvas)
}
}和视图布局,以防需要
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@mipmap/ic_launcher"/>
<com.imdevinc.mapcaster.DrawView
android:id="@+id/draw"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>堆栈跟踪
2020-01-02 18:50:18.173 10081-10081/com.imdevinc.mapcaster E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.imdevinc.mapcaster, PID: 10081
java.lang.IllegalArgumentException: width and height must be > 0
at android.graphics.Bitmap.createBitmap(Bitmap.java:1033)
at android.graphics.Bitmap.createBitmap(Bitmap.java:1000)
at android.graphics.Bitmap.createBitmap(Bitmap.java:950)
at android.graphics.Bitmap.createBitmap(Bitmap.java:911)
at com.imdevinc.mapcaster.DrawView.initCanvas(DrawView.kt:42)
at com.imdevinc.mapcaster.DrawView$$special$$inlined$doOnLayout$1.onLayoutChange(View.kt:339)
at android.view.View.layout(View.java:20690)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1812)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1656)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1565)
at android.view.View.layout(View.java:20672)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:20672)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at com.android.internal.widget.ActionBarOverlayLayout.onLayout(ActionBarOverlayLayout.java:508)
at android.view.View.layout(View.java:20672)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at com.android.internal.policy.DecorView.onLayout(DecorView.java:753)
at android.view.View.layout(View.java:20672)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2792)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2319)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1460)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7183)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:949)
at android.view.Choreographer.doCallbacks(Choreographer.java:761)
at android.view.Choreographer.doFrame(Choreographer.java:696)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:935)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)发布于 2020-01-05 08:51:46
解决了我的问题。我使用的是一个LinearLayout,它把我的自定义视图压到了我的ImageView下面。切换到RelativeLayout允许自定义视图位于ImageView之上,并解决了这个问题。
发布于 2020-01-03 06:52:41
我认为用addOnLayoutChangeListener代替doOnLayout是更好的方式
https://stackoverflow.com/questions/59570948
复制相似问题