首页 > 解决方案 > 自定义 AppCompatEditText 组件未初始化

问题描述

我是 Kotlin 的新手,我正在尝试按照教程中的方式实现自定义 pin 输入文本编辑字段。我用 Kotlin 重写了PinEntryEditText,它没有抛出任何错误。我还添加到我的 XML 布局文件中,并在我的 MainActivity 页面中使用它。它运行并且没有抛出错误。但是,它没有按预期显示。我开始尝试调试它并在每个类构造函数上设置 3 个断点。调试器不会停在其中任何一个上,这让我觉得它甚至永远不会从那里开始。

现在,这是我的课:

class PinEntryEditText : AppCompatEditText {
    private var mSpace = 24f //24 dp by default, space between the lines
    private var mCharSize: Float = 0.toFloat()
    private var mNumChars = 4f
    private var mLineSpacing = 8f //8dp by default, height of the text from our lines
    private var mMaxLength = 4f
    val XML_NAMESPACE_ANDROID = "http://schemas.android.com/apk/res/android"

    var mClickListener: View.OnClickListener? = null

    private var mLineStroke = 1f //1dp by default
    private var mLineStrokeSelected = 2f //2dp by default
    private var mLinesPaint: Paint? = null


    var mStates = arrayOf(intArrayOf(android.R.attr.state_selected), // selected
            intArrayOf(android.R.attr.state_focused), // focused
            intArrayOf(-android.R.attr.state_focused))// unfocused

    var mColors = intArrayOf(Color.GREEN, Color.BLACK, Color.GRAY)

    var mColorStates = ColorStateList(mStates, mColors)


    constructor(context: Context) : super(context) {
        this.setWillNotDraw(false)
    }

    constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
        this.setWillNotDraw(false)
        init(context, attrs)
    }

    constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
        this.setWillNotDraw(false)
        init(context, attrs)
    }

    private fun init(context: Context, attrs: AttributeSet) {
        val multi = context.resources.displayMetrics.density
        mLineStroke = (multi * mLineStroke)
        mLineStrokeSelected = (multi * mLineStrokeSelected)
        mLinesPaint = Paint(paint)
        mLinesPaint?.strokeWidth = mLineStroke.toFloat()
        if (!isInEditMode) {
            val outValue = TypedValue()
            context.theme.resolveAttribute(colorControlActivated,
                    outValue, true)
            val colorActivated = outValue.data
            mColors[0] = colorActivated

            context.theme.resolveAttribute(colorPrimaryDark,
                    outValue, true)
            val colorDark = outValue.data
            mColors[1] = colorDark

            context.theme.resolveAttribute(colorControlHighlight,
                    outValue, true)
            val colorHighlight = outValue.data
            mColors[2] = colorHighlight
        }
        setBackgroundResource(0)
        mSpace = (multi * mSpace) //convert to pixels for our density
        mLineSpacing = (multi * mLineSpacing) //convert to pixels for our density
        mMaxLength = attrs.getAttributeIntValue(XML_NAMESPACE_ANDROID, "maxLength", 4).toFloat()
        mNumChars = mMaxLength

        //Disable copy paste
        super.setCustomSelectionActionModeCallback(object : ActionMode.Callback {
            override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
                return false
            }

            override fun onDestroyActionMode(mode: ActionMode) {}

            override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
                return false
            }

            override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
                return false
            }
        })
        // When tapped, move cursor to end of text.
        super.setOnClickListener { v ->
            setSelection(text!!.length)
            if (mClickListener != null) {
                mClickListener?.onClick(v)
            }
        }

    }

    override fun setOnClickListener(l: View.OnClickListener?) {
        mClickListener = l
    }

    override fun setCustomSelectionActionModeCallback(actionModeCallback: ActionMode.Callback) {
        throw RuntimeException("setCustomSelectionActionModeCallback() not supported.")
    }

    override fun onDraw(canvas: Canvas) {
        //super.onDraw(canvas)
        val availableWidth = width - paddingRight - paddingLeft
        if (mSpace < 0) {
            mCharSize = availableWidth / (mNumChars * 2 - 1)
        } else {
            mCharSize = (availableWidth - mSpace * (mNumChars - 1)) / mNumChars
        }

        var startX = paddingLeft.toFloat()
        val bottom = height - paddingBottom

        //Text width
        val text = text
        val textLength = text!!.length
        val textWidths = FloatArray(textLength)
        paint.getTextWidths(getText(), 0, textLength, textWidths)


        for (i in 0..mNumChars.toInt()) {
            updateColorForLines(i == textLength)
            canvas.drawLine(startX.toFloat(), bottom.toFloat(), startX.toFloat() + mCharSize, bottom.toFloat(), paint)
            if (text.length > i) {
                val middle = startX + mCharSize / 2
                canvas.drawText(text, i,i + 1, middle - textWidths[0] / 2, (bottom - mLineSpacing).toFloat(), paint)
            }

            if (mSpace < 0) {
                startX += mCharSize * 2
            } else {
                startX += mCharSize + mSpace
            }
        }
    }

    private fun getColorForState(vararg states: Int): Int {
        return mColorStates.getColorForState(states, Color.GRAY)
    }

    private fun updateColorForLines(next: Boolean) {
        if (isFocused) {
            mLinesPaint?.strokeWidth = mLineStrokeSelected.toFloat()
            mLinesPaint?.color = getColorForState(android.R.attr.state_focused)
            if (next) {
                mLinesPaint?.color = getColorForState(android.R.attr.state_selected)
            }
        } else {
            mLinesPaint?.strokeWidth = mLineStroke.toFloat()
            mLinesPaint?.color = getColorForState(-android.R.attr.state_focused)
        }
    }
}

这是我的组件 XML:

<com.myapp.app.myapp.PinEntryEditText
    android:id="@+id/pin_entry_edit"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:cursorVisible="false"
    android:digits="1234567890"
    android:inputType="number"
    android:maxLength="4"
    android:textIsSelectable="false"
    android:textSize="20sp" />

我必须以编程方式分配课程吗?不幸的是,我真的不知道如何解决这个问题,因为调试器甚至不会进入课堂。任何形式的输入都可能是错误的,我们将不胜感激。

标签: javaandroidandroid-layoutkotlin

解决方案


根据View.setWillNotDraw,您应该setWillNotDraw(true)从构造函数中删除:

如果此视图自己不进行任何绘图,请设置此标志以允许进一步优化。默认情况下,该标志未在 View 上设置,但可以在某些 View 子类上设置,例如 ViewGroup。通常,如果您覆盖 onDraw(android.graphics.Canvas) 您应该清除此标志


推荐阅读