oiooooio 2023-02-11 11:31 采纳率: 77.8%
浏览 27
已结题

安卓自定义组件导致预览整个不显示,但运行ok


代码在最后, 如下图所示, 不用自定义组件 预览是好的, 用了自定义组件, 整个预览都不显示了, 但是在真机上运行是好的~


找了写教程看了, 但是没有看出个所以然来~~ 求帮忙看看到底什么问题导致的不显示~


img



组件代码(正常情况复制出去就能用):



class QXButton @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {

    val TAG = QXButton::class.simpleName ?: "QXButton"

    val _context = context

    val _attrsMap = mutableMapOf<String, Int>()
    val _paint = TextPaint()
    var _text = "按钮"
    var _textSize = 16f

    // 避免重复点击
    var _interval = 0L
    var _intervalConf = 0

    init {
        if (attrs != null) {
            for (i in 0 until attrs.attributeCount) {
                _attrsMap[attrs.getAttributeName(i)] = i

                // Log.d(TAG, " ${attrs.getAttributeName(i)} = ${attrs.getAttributeValue(i)}")
            }
        }

        _text = getResource(context, attrs, "text", _text) as String
        _textSize = parseTextSize(getResource(context, attrs, "textSize", sp2px(_textSize)))
        _intervalConf = parseInt(getResource(context, attrs, "interval", _intervalConf))

        _paint.color = Color.parseColor("#ffffff")
        _paint.isAntiAlias = true
        _paint.textSize = sp2px(_textSize)
    }

    private fun sp2px(spValue: Float): Float {
        val fontScale = Utils.getContext().resources.displayMetrics.scaledDensity
        return spValue * fontScale + 0.5f
    }

    private fun parseInt(value: Any): Int {
        return if (value.javaClass.simpleName == "String") (value as String).toInt()
        else value as Int
    }

    private fun parseTextSize(value: Any): Float {
        if (value.javaClass.simpleName == "String") {
            var x = value as String
            x = x.replace("dp", "sp")  // xml可以使用dp, 为了防止真的有人用dp~
            return x.substring(0, x.indexOf("sp")).toFloat()
        }
        return value as Float
    }

    private fun getResource(
        context: Context,
        attrs: AttributeSet?,
        key: String,
        defValue: Any
    ): Any {
        if (attrs == null)
            return defValue

        val x = _attrsMap[key]?.let { attrs.getAttributeValue(it) } ?: return defValue

        return if (x.javaClass.simpleName == "String") {
            if (x[0] == '@') context.getString(x.substring(1).toInt())
            else x
        } else {
            x
        }
    }

    /**
     * 次方法并不会一直处于更新状态
     */
    override fun draw(canvas: Canvas?) {
        super.draw(canvas)

        if (canvas == null)
            return

        val tW = _paint.measureText(_text)
        val tH = _paint.ascent() + _paint.descent()

        val startX = (width - tW) / 2
        val startY = (height - tH) / 2

        canvas.drawText(_text, startX, startY, _paint)
    }

    @SuppressLint("ClickableViewAccessibility")
    override fun onTouchEvent(event: MotionEvent?): Boolean {
        if (event == null) {
            return super.onTouchEvent(event)
        }

        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                // https://blog.csdn.net/qq_44912644/article/details/89362276#:~:text=除了字体类型设置之外,还可以为字体类型设置字体风格,如设置粗体: Paint mp = new Paint ();,Typeface font = Typeface.create (Typeface.SANS_SERIF, Typeface.BOLD); p.setTypeface (font);
                _paint.typeface = Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD)

                // 下面这种加粗方式会让字变的一片白
                //_paint.style = Paint.Style.FILL_AND_STROKE
                //_paint.strokeWidth = 2f

                _paint.letterSpacing = 0.1f
            }

            MotionEvent.ACTION_UP -> {
                _paint.typeface = Typeface.create(Typeface.SANS_SERIF, Typeface.NORMAL)
                _paint.letterSpacing = 0f

                invalidate()
            }
        }

        // Log.d(TAG, "onTouchEvent: $event")
        return super.onTouchEvent(event)
    }

    override fun performClick(): Boolean {
        // Log.d(TAG, "performClick: ")

        val cur = System.currentTimeMillis()

        if (cur < _interval) {
            Log.d(TAG, "performClick: 重复点击 ${_interval - cur}")
            return true
        }

        _interval = cur + _intervalConf

        // 必须执行这行,调用者setClickListener才能收到点击事件
        return super.performClick()

        // 这里无论返回false还是true,都无法再触发调用者的setClickListener事件
        // return true
    }

}
  • 写回答

4条回答 默认 最新

  • Halifax ‎ 2023-02-11 12:24
    关注

    望采纳。。

    自定义view组件,在预览模式需要禁止绘制等操作。

    可以使用View.isInEditMode(),来判断当前是不是处于编辑器的预览模式,是预览模式,不执行自定义view里面的代码。

    你在你的自定义view的代码里面,如:ondraw等方法里面这样使用:

    if(!View.isInEditMode()){
       // 不在预览模式下,已经运行到模拟器或者真机,才执行这里的代码,即可。
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论 编辑记录
查看更多回答(3条)

报告相同问题?

问题事件

  • 系统已结题 2月26日
  • 已采纳回答 2月18日
  • 创建了问题 2月11日

悬赏问题

  • ¥15 如何让企业微信机器人实现消息汇总整合
  • ¥50 关于#ui#的问题:做yolov8的ui界面出现的问题
  • ¥15 如何用Python爬取各高校教师公开的教育和工作经历
  • ¥15 TLE9879QXA40 电机驱动
  • ¥20 对于工程问题的非线性数学模型进行线性化
  • ¥15 Mirare PLUS 进行密钥认证?(详解)
  • ¥15 物体双站RCS和其组成阵列后的双站RCS关系验证
  • ¥20 想用ollama做一个自己的AI数据库
  • ¥15 关于qualoth编辑及缝合服装领子的问题解决方案探寻
  • ¥15 请问怎么才能复现这样的图呀