在Android EditText中设置两个复合drawable

时间:2018-05-04 13:49:20

标签: android android-layout kotlin android-textinputlayout

我有以下TextInputEditTexts嵌套在自定义TextInputLayouts内部,我希望同时显示“x”图标和密码切换。但是,眼睛切换会覆盖“x”图标。

我有一个名为TextInputLayout的自定义LoginInputLayout,我试图在密码editText的右侧添加两个drawables,但我只保留眼睛图标。

如何在右侧添加两个drawables而不是覆盖另一个?如下图所示。

这是我想要的设计

enter image description here

在父LayoutInputTextView的Android实现中,看起来第一个孩子实际上是FrameLayout,而该FL的孩子是TextInputEditText

当密码切换(导致眼睛出现)设置为显示时,看起来android实现为切换的视图膨胀,并将其设置在FrameLayout内,如下所示。

if (shouldShowPasswordIcon()) {
            if (mPasswordToggleView == null) {
                mPasswordToggleView = (CheckableImageButton) LayoutInflater.from(getContext())
                        .inflate(R.layout.design_text_input_password_icon, mInputFrame, false);
                mPasswordToggleView.setImageDrawable(mPasswordToggleDrawable);
                mPasswordToggleView.setContentDescription(mPasswordToggleContentDesc);
                mInputFrame.addView(mPasswordToggleView);

                mPasswordToggleView.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        passwordVisibilityToggleRequested(false);
                    }
                });
            }

唯一的问题是,mFrameLayout成员变量是私有的,我无法在其中添加更多子项或控制它们的放置位置。这就是为什么我觉得我只能尝试复合绘画方式。

 <com.ge.cbyge.view.LoginInputTextLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_vertical"
        app:error="@{viewModel.emailError}">

        <android.support.design.widget.TextInputEditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="@string/login_fragment_email_text"
            android:focusable="true"
            android:focusableInTouchMode="true"
            android:inputType="textEmailAddress"
            android:maxLines="1"
            android:text="@={viewModel.email}"/>

    </com.ge.cbyge.view.LoginInputTextLayout>

    <com.ge.cbyge.view.LoginInputTextLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="@dimen/placeholder_dimen"
        android:maxLines="1"
        app:error="@{viewModel.passwordError}"
        app:passwordToggleEnabled="true">

        <android.support.design.widget.TextInputEditText
            android:id="@+id/password_edit_text"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="@string/login_fragment_password_text"
            android:focusable="true"
            android:focusableInTouchMode="true"
            android:text="@={viewModel.password}"/>

</com.ge.cbyge.view.LoginInputTextLayout>

这是我TextInputLayout

的自定义实现
class LoginInputTextLayout : TextInputLayout, TextWatcher {

    lateinit var clearTextIcon: Drawable

    constructor(context: Context) : super(context)

    constructor(context: Context, attrs: AttributeSet) : super(context, attrs)

    constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle)

    override fun addView(child: View?, index: Int, params: ViewGroup.LayoutParams) {
        super.addView(child, index, params)

        if(child is EditText) {
            Timber.d("$TAG child was an editText")
            if (editText != null) {
                Timber.d("$TAG initializing the clearText")
                init(context)
            }
        }
    }

    private fun init(context: Context) {
        val drawable = ContextCompat.getDrawable(context, R.drawable.abc_ic_clear_material)
        DrawableCompat.setTint(drawable, editText!!.currentHintTextColor)
        clearTextIcon = drawable
        clearTextIcon.setBounds(0, 0, clearTextIcon.intrinsicHeight, clearTextIcon.intrinsicHeight)
        setClearIconVisible(false)
        editText!!.transformationMethod = PasswordTransformationMethod.getInstance()
        editText!!.setOnTouchListener(onTouchListener)
        editText!!.setOnFocusChangeListener(focusChangeListener)
        editText!!.addTextChangedListener(this)
    }

    private val onTouchListener: View.OnTouchListener = OnTouchListener { v, event ->
        val x = event.x.toInt()
        if (clearTextIcon.isVisible && x > width - paddingRight - clearTextIcon.intrinsicWidth) {
            if (event.action == MotionEvent.ACTION_UP) {
                editText?.setText("")
            }
            return@OnTouchListener true
        }

        return@OnTouchListener false
    }

    private val focusChangeListener: View.OnFocusChangeListener = OnFocusChangeListener { v, hasFocus ->
        if (hasFocus) {
            setClearIconVisible(editText!!.text.isNotEmpty())
        } else {
            setClearIconVisible(false)
        }
    }

    private fun setClearIconVisible(visible: Boolean) {
        clearTextIcon.setVisible(visible, false)
        val compoundDrawables = TextViewCompat.getCompoundDrawablesRelative(editText!!)
        TextViewCompat.setCompoundDrawablesRelative(
                editText!!,
                compoundDrawables[0],
                compoundDrawables[1],
                if (visible) clearTextIcon else null,
                compoundDrawables[3])
    }

    override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
        if (editText!!.isFocused) {
            setClearIconVisible(s.isNotEmpty())
        }
    }

    override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}

    override fun afterTextChanged(s: Editable) {}
}

1 个答案:

答案 0 :(得分:0)

我能够让它发挥作用,偏离复合一次性权利。我能够在FrameLayout方法中抓住addView(),检测它是否有两个孩子(意思是editText和眼睛徽标),如果有,请将“x”标记设置在左侧眼睛。

class LoginInputTextLayout : TextInputLayout, TextWatcher {

    private lateinit var clearTextIcon: ImageView
    private lateinit var frameLayout: FrameLayout

    constructor(context: Context) : super(context)

    constructor(context: Context, attrs: AttributeSet) : super(context, attrs)

    constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle)

    override fun addView(child: View?, index: Int, params: ViewGroup.LayoutParams) {
        super.addView(child, index, params)

        if (child is FrameLayout) {
            frameLayout = child
        }

        if(child is EditText) {
            if (editText != null) {
                init()
            }
        }
    }

    private fun init() {
        initClearTextIcon(isPasswordVisibilityToggleEnabled)
        editText!!.setOnFocusChangeListener(focusChangeListener)
        editText!!.addTextChangedListener(this)
    }

    private fun initClearTextIcon(passwordToggleEnabled: Boolean) {
        val drawable = ContextCompat.getDrawable(context, R.drawable.abc_ic_clear_material)
        DrawableCompat.setTint(drawable, editText!!.currentHintTextColor)

        clearTextIcon = LayoutInflater.from(context).inflate(R.layout.design_text_input_password_icon, frameLayout, false) as ImageView
        clearTextIcon.maxHeight = editText!!.height
        clearTextIcon.setImageDrawable(drawable)
        clearTextIcon.setOnClickListener {
            editText?.setText("")
        }

        if (passwordToggleEnabled) {
            val shiftedClearTextIcon = clearTextIcon
            shiftedClearTextIcon.setPadding(0,0, passwordVisibilityToggleDrawable!!.intrinsicWidth * 2, 0)
            frameLayout.addView(clearTextIcon)
            editText!!.transformationMethod = PasswordTransformationMethod.getInstance()
        } else {
            frameLayout.addView(clearTextIcon)
        }
        setClearIconVisible(false)
    }

    private val focusChangeListener: View.OnFocusChangeListener = OnFocusChangeListener { v, hasFocus ->
        if (hasFocus) {
            setClearIconVisible(editText!!.text.isNotEmpty())
        } else {
            setClearIconVisible(false)
        }
    }

    private fun setClearIconVisible(visible: Boolean) {
        if (visible) clearTextIcon.visibility = View.VISIBLE else clearTextIcon.visibility = View.GONE
    }

    override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
        if (editText!!.isFocused) {
            setClearIconVisible(s.isNotEmpty())
        }
    }

    override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}

    override fun afterTextChanged(s: Editable) {}
}