代码在最后, 如下图所示, 不用自定义组件 预览是好的, 用了自定义组件, 整个预览都不显示了, 但是在真机上运行是好的~
找了写教程看了, 但是没有看出个所以然来~~ 求帮忙看看到底什么问题导致的不显示~
组件代码(正常情况复制出去就能用):
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
}
}