首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >创建位图时自定义视图崩溃

创建位图时自定义视图崩溃
EN

Stack Overflow用户
提问于 2020-01-03 06:39:43
回答 2查看 165关注 0票数 0

我正在尝试创建一个自定义视图,它填充了一个黑屏,然后可以通过在屏幕上绘制来显示下面的图像来进行擦除。我发现了一个旧的SO问题,它有一个旧的解决方案,但将其转换为Kotlin会给出关于第34行的高度为0的错误。下面是正在使用的代码。请注意,width被正确设置为1440,但height和measuredHeight也都为0。我以为将代码添加到this.doOnLayout中可以确保该函数只在视图展开后运行,但这似乎并不正确。

代码语言:javascript
运行
复制
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)
    }
}

和视图布局,以防需要

代码语言:javascript
运行
复制
<?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>

堆栈跟踪

代码语言:javascript
运行
复制
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)
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-01-05 08:51:46

解决了我的问题。我使用的是一个LinearLayout,它把我的自定义视图压到了我的ImageView下面。切换到RelativeLayout允许自定义视图位于ImageView之上,并解决了这个问题。

票数 0
EN

Stack Overflow用户

发布于 2020-01-03 06:52:41

我认为用addOnLayoutChangeListener代替doOnLayout是更好的方式

票数 -2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59570948

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档