Установите два составных рисования в Android EditText - PullRequest
0 голосов
/ 04 мая 2018

У меня есть ниже TextInputEditTexts, вложенный в custom TextInputLayouts, и я хочу, чтобы значок "x" и переключатель пароля были видны одновременно. Однако переключатель глаза перекрывает значок «x».

У меня есть пользовательский TextInputLayout с именем LoginInputLayout, в котором я пытаюсь добавить два рисованных элемента в правой части пароля editText, но я продолжаю получать только значок глаза.

Как я могу добавить два рисованных объекта с правой стороны, и чтобы один не перекрывал другой? Как на картинке ниже.

Это дизайн, к которому я пытаюсь добраться

enter image description here

В реализации Android для родителя LayoutInputTextView похоже, что первый дочерний элемент на самом деле 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 голосов
/ 04 мая 2018

Я смог заставить это работать, отклоняясь от составного одноразового права. Мне удалось поймать 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) {}
}
...