84 votes

Mettre un texte constant dans un EditText qui ne devrait pas être modifiable - Android

Je veux avoir un texte constant à l'intérieur de editText comme :

http://<here_user_can_write>

L'utilisateur ne doit pas pouvoir supprimer des caractères de " http:// "J'ai fait des recherches à ce sujet et j'ai trouvé ceci :

editText.setFilters(new InputFilter[] {
    new InputFilter() {
        public CharSequence filter(CharSequence src, int start,
            int end, Spanned dst, int dstart, int dend) {
            return src.length() < 1 ? dst.subSequence(dstart, dend) : "";
        }
    }
}); 

mais je ne sais pas s'il restreint l'utilisateur à ne pas supprimer de caractères de du début à la fin limite. Je n'ai pas non plus compris l'utilisation de la classe Spanned.

Un bon choix serait de mettre en place une TextView à l'intérieur EditText mais je ne pense pas que ce soit possible dans Android puisque les deux sont des Vues, est-ce possible ?

6voto

slezadav Points 3466

Vous aviez presque raison, essayez

private final String PREFIX="http://";

editText.setFilters(new InputFilter[]{new InputFilter() {
            @Override
            public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int
                    dend) {
                return dstart<PREFIX.length()?dest.subSequence(dstart,dend):null;
            }
        }});

5voto

Jack the Ripper Points 1501

CODE POUR AJOUTER UN PRÉFIXE PERSONNALISÉ À VOTRE TEXTE D'ÉDITION (PRÉFIXE NON MODIFIABLE)

Code de Medium par Ali Muzaffar

public class PrefixEditText extends AppCompatEditText {
    float originalLeftPadding = -1;

    public PrefixEditText(Context context) {
        super(context);
    }

    public PrefixEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public PrefixEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        calculatePrefix();
    }

    private void calculatePrefix() {
        if (originalLeftPadding == -1) {
            String prefix = (String) getTag();
            float[] widths = new float[prefix.length()];
            getPaint().getTextWidths(prefix, widths);
            float textWidth = 0;
            for (float w : widths) {
                textWidth += w;
            }
            originalLeftPadding = getCompoundPaddingLeft();
            setPadding((int) (textWidth + originalLeftPadding),
                getPaddingRight(), getPaddingTop(),
                getPaddingBottom());
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        String prefix = (String) getTag();
        canvas.drawText(prefix, originalLeftPadding, getLineBounds(0, null), getPaint());
    }
}

Et XML

<com.yourClassPath.PrefixEditText
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="bottom"
    android:textSize="14sp"
    android:tag="€ " />

4voto

Cyber Gh Points 92

Une fonction d'extension Kotlin facile à utiliser à cette fin

fun EditText.stickPrefix(prefix: String) {
    this.addTextChangedListener(afterTextChanged = {
        if (!it.toString().startsWith(prefix) && it?.isNotEmpty() == true) {
            this.setText(prefix + this.text)
            this.setSelection(this.length())

        }
    })
}
//someEditText.stickPrefix("+")

3voto

Cristina De Rito Points 842

Je sais que je fais revivre un ancien article, mais je veux partager avec la communauté que j'ai lutté avec ce sujet ces jours-ci et que j'ai trouvé que le fait de placer un TextView sur le EditText est non seulement parfaitement réalisable (pour répondre à la deuxième partie de la question), bien plus dans ce cas où le texte constant est nécessaire dans la position de départ, mais aussi préférable. De plus, le curseur ne se déplacera même pas devant le texte "mutable", ce qui est un effet élégant. Je préfère cette solution parce qu'elle n'ajoute pas de charge de travail et de complexité à mon application avec des listeners et autres.

Voici un exemple de code de ma solution :

<RelativeLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_marginStart="3dp"
        android:text="http://" />

    <EditText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:inputType="textUri"
        android:paddingStart="choose an appropriate padding" />
</RelativeLayout>

En enfermant les vues dans un RelativeLayout ils se chevaucheront. L'astuce consiste à jouer avec la fonction android:paddingStart de la propriété EditText pour que le texte commence juste après l'icône TextView , tandis que android:layout_centerVertical="true" y android:layout_marginStart="3dp" les propriétés de la TextView s'assurer que son texte est correctement aligné sur le texte saisi et sur le début de la ligne sous-jacente de l'article EditText (c'est du moins ce qui se produit lorsque l'on utilise un modèle à thème matériel).

3voto

Antonis Radz Points 544

J'ai créé une fonction d'extension Kotlin pour ajouter un préfixe à EditText

fun EditText.addPrefix(prefix: String) {
        var text = ""
        var isPrefixModified = false
        val formattedPrefix = "$prefix "
        var lastCharSequence: CharSequence? = null

        val setEditText: () -> Unit = {
            setText(text)
            Selection.setSelection(editableText, text.length)
        }

        this.addTextChangedListener(object : TextWatcher {
            override fun afterTextChanged(editable: Editable?) {
                val newText = editable.toString()

                when {
                    isPrefixModified -> {
                        isPrefixModified = false
                        setEditText()
                    }
                    isTryingToDeletePrefix(newText) -> {
                        setEditText()
                    }
                    isNewInput(newText) -> {
                        text = "$formattedPrefix$newText"
                        setEditText()
                    }
                    else -> {
                        text = newText
                    }
                }
            }

            override fun beforeTextChanged(charSequence: CharSequence?, start: Int,
                                           count: Int, after: Int) {
                charSequence?.let {
                    if (it != lastCharSequence && it.isNotEmpty() && start <= prefix.length) {
                        isPrefixModified = true
                    }
                    lastCharSequence = charSequence
                }
            }

            override fun onTextChanged(charSequence: CharSequence?, start: Int,
                                       before: Int, count: Int) {
                // Ignore
            }

            private fun isTryingToDeletePrefix(newText: String) =
                    text.isNotEmpty() && newText.length < text.length && isNewInput(newText)

            private fun isNewInput(newText: String) = !newText.contains(formattedPrefix)
        })
    }

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X