Je veux avoir un texte constant dans editText comme:
http://<here_user_can_write>
L'utilisateur ne devrait pas pouvoir supprimer les caractères de "http://
", j'ai cherché à ce sujet et 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 si cela empêche l'utilisateur de supprimer tous les caractères de start to end limit. Je ne pouvais pas non plus comprendre l'utilisation de la classe Spanned.
Une solution serait un bon choix si nous pouvons insérer une TextView
dans EditText
mais je ne pense pas que ce soit possible sous Android, car les deux sont des vues, est-ce possible?
Avez-vous essayé cette méthode?
final EditText edt = (EditText) findViewById(R.id.editText1);
edt.setText("http://");
Selection.setSelection(edt.getText(), edt.getText().length());
edt.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// TODO Auto-generated method stub
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO Auto-generated method stub
}
@Override
public void afterTextChanged(Editable s) {
if(!s.toString().startsWith("http://")){
edt.setText("http://");
Selection.setSelection(edt.getText(), edt.getText().length());
}
}
});
Voilà comment vous pouvez le faire avec un InputFilter
:
final String prefix = "http://"
editText.setText(prefix);
editText.setFilters(new InputFilter[] {
new InputFilter() {
@Override
public CharSequence filter(final CharSequence source, final int start,
final int end, final Spanned dest, final int dstart, final int dend) {
final int newStart = Math.max(prefix.length(), dstart);
final int newEnd = Math.max(prefix.length(), dend);
if (newStart != dstart || newEnd != dend) {
final SpannableStringBuilder builder = new SpannableStringBuilder(dest);
builder.replace(newStart, newEnd, source);
if (source instanceof Spanned) {
TextUtils.copySpansFrom(
(Spanned) source, 0, source.length(), null, builder, newStart);
}
Selection.setSelection(builder, newStart + source.length());
return builder;
} else {
return null;
}
}
}
});
Si vous souhaitez également que le préfixe ne puisse pas être sélectionné, vous pouvez ajouter le code suivant.
final SpanWatcher watcher = new SpanWatcher() {
@Override
public void onSpanAdded(final Spannable text, final Object what,
final int start, final int end) {
// Nothing here.
}
@Override
public void onSpanRemoved(final Spannable text, final Object what,
final int start, final int end) {
// Nothing here.
}
@Override
public void onSpanChanged(final Spannable text, final Object what,
final int ostart, final int oend, final int nstart, final int nend) {
if (what == Selection.SELECTION_START) {
if (nstart < prefix.length()) {
final int end = Math.max(prefix.length(), Selection.getSelectionEnd(text));
Selection.setSelection(text, prefix.length(), end);
}
} else if (what == Selection.SELECTION_END) {
final int start = Math.max(prefix.length(), Selection.getSelectionEnd(text));
final int end = Math.max(start, nstart);
if (end != nstart) {
Selection.setSelection(text, start, end);
}
}
}
};
editText.getText().setSpan(watcher, 0, 0, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
Il y avait un léger problème avec la réponse de @Rajitha Siriwardena . Elle suppose que toute la chaîne, à l'exception du suffixe, a été supprimée avant que le suffixe ait un sens si vous avez la chaîne.
http://stackoverflow.com/
et essayez de supprimer toute partie de http://
, vous supprimerez stackoverflow.com/
pour obtenir uniquement http://
.
J'ai également ajouté une vérification au cas où l'utilisateur essaie de saisir avant le préfixe.
@Override
public void afterTextChanged(Editable s) {
String prefix = "http://";
if (!s.toString().startsWith(prefix)) {
String cleanString;
String deletedPrefix = prefix.substring(0, prefix.length() - 1);
if (s.toString().startsWith(deletedPrefix)) {
cleanString = s.toString().replaceAll(deletedPrefix, "");
} else {
cleanString = s.toString().replaceAll(prefix, "");
}
editText.setText(prefix + cleanString);
editText.setSelection(prefix.length());
}
}
Remarque: cela ne gère pas le cas où l'utilisateur tente de modifier le préfixe lui-même uniquement avant et après.
Vous avez eu 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;
}
}});
CODE POUR AJOUTER UN PRÉFIXE PERSONNALISÉ À VOTRE EDITTEXT (PRÉFIXE NON ÉDITABLE)
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="€ " />
Tiré du blog de ALi Muzaffar, voir le message original pour plus de détails.
Utilisez la vue personnalisée EditText
pour tracer le texte du préfixe et ajouter un remplissage en fonction de la taille du texte
public class PrefixEditText extends EditText {
private String mPrefix = "$"; // add your prefix here for example $
private Rect mPrefixRect = new Rect(); // actual prefix size
public PrefixEditText(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
getPaint().getTextBounds(mPrefix, 0, mPrefix.length(), mPrefixRect);
mPrefixRect.right += getPaint().measureText(" "); // add some offset
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawText(mPrefix, super.getCompoundPaddingLeft(), getBaseline(), getPaint());
}
@Override
public int getCompoundPaddingLeft() {
return super.getCompoundPaddingLeft() + mPrefixRect.width();
}
}
Je sais que je ressuscite un ancien message, mais je souhaite partager avec la communauté les difficultés que j'ai rencontrées avec ce sujet ces derniers jours et j’ai trouvé que le fait de placer une TextView
sur une EditText
est non seulement parfaitement faisable (pour répondre à la deuxième partie de la question), beaucoup plus dans ce cas où le texte constant est nécessaire dans la position de départ, mais préférable, aussi. De plus, le curseur ne bouge même pas avant le texte "mutable", ce qui est un effet élégant ... Je préfère cette solution car elle n’ajoute pas de charge de travail ni de complexité à mon application avec les auditeurs.
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 encadrant les vues dans une RelativeLayout
, elles seront superposées . L'astuce consiste à jouer avec la propriété Android:paddingStart
de la EditText
, pour que le texte commence juste après la TextView
, tandis que les propriétés Android:layout_centerVertical="true"
et Android:layout_marginStart="3dp"
de la TextView
s'assurent que son texte est correctement aligné avec le texte saisi et avec le début de la ligne sous-jacente de la variable EditText
(ou du moins, cela se produit lors de l’utilisation de la matière à thème).
Celui-ci consiste essentiellement à ajouter le préfixe "+91" au champ de saisie de votre numéro de téléphone.
1.Ajouter ce code à oncreate () of activity
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sign_up);
// Write other things......//
etPhoneNumber.setFilters(new InputFilter[]{getPhoneFilter(),newInputFilter.LengthFilter(13)});
etPhoneNumber.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
if (etPhoneNumber.getText().toString().isEmpty()) {
etPhoneNumber.setText("+91");
Selection.setSelection(etPhoneNumber.getText(), etPhoneNumber.getText().length()); }
} else {
if (etPhoneNumber.getText().toString().equalsIgnoreCase("+91")) {
etPhoneNumber.setFilters(new InputFilter[]{});
etPhoneNumber.setText("");
etPhoneNumber.setFilters(new InputFilter[]{getPhoneFilter(),new InputFilter.LengthFilter(13)});
}
}
}
});
}
2.Déclarez une méthode appelée getPhoneFilter ()
private InputFilter getPhoneFilter() {
Selection.setSelection(etPhoneNumber.getText(), etPhoneNumber.getText().length());
etPhoneNumber.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
@Override
public void afterTextChanged(Editable s) {
if(!s.toString().startsWith("+91")){
if (etPhoneNumber.getFilters() != null && etPhoneNumber.getFilters().length > 0) {
etPhoneNumber.setText("+91");
Selection.setSelection(etPhoneNumber.getText(), etPhoneNumber.getText().length());
}
}
}
});
// Input filter to restrict user to enter only digits..
InputFilter filter = new InputFilter() {
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend) {
for (int i = start; i < end; i++) {
if (!String.valueOf(getString(R.string.digits_number)).contains(String.valueOf(source.charAt(i)))) {
return "";
}
}
return null;
}
};
return filter;
}
3.dclarez "digits_number" dans votre fichier de valeurs
<string name="digits_number">1234567890+</string>
EditText msg=new EditText(getContext());
msg.setSingleLine(true);
msg.setSingleLine();
msg.setId(View.generateViewId());
msg.measure(0,0);
TextView count=new TextView(getContext());
count.setTextColor(Color.parseColor("#666666"));
count.setText("20");
count.setPadding(0,0,(int)Abstract.getDIP(getContext(),10),0);
count.measure(0,0);
float tenPIX =TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,10,getContext().getResources().getDisplayMetrics());
msg.setPadding((int)tenPIX,(int)tenPIX,(int)(int)tenPIX+count.getMeasuredWidth(),(int)tenPIX);
RelativeLayout ll1=new RelativeLayout(getContext());
ll1.addView(msg,new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
LayoutParams countlp=new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
countlp.addRule(RelativeLayout.ALIGN_END,msg.getId());
countlp.addRule(RelativeLayout.ALIGN_BASELINE,msg.getId());
ll1.addView(count,countlp);
Basé sur @ demaksee comment. J'étends EditText et remplace la fonction onSelectionChanged. Donc, même l'utilisateur ne peut pas éditer le préfixe. Très simple et utile. Kotlin:
private var prefix : String? = ""
override fun onSelectionChanged(selStart: Int, selEnd: Int) {
if (prefix != null && prefix!!.isNotBlank()) {
var finalStart = selStart
var finalEnd = selEnd
val prefixLength = prefix!!.length
if (prefixLength > selStart) {
finalStart = prefixLength
}
if (prefixLength > selEnd) {
finalEnd = prefixLength
}
if (finalStart == selStart && finalEnd == selEnd) {
super.onSelectionChanged(finalStart, finalEnd)
} else {
val startWithPrefix = text?.startsWith(prefix ?: "") ?: prefix.isNullOrBlank()
if (!startWithPrefix) {
setText(prefix)
}
setSelection(finalStart, finalEnd)
}
}
}
public fun setPrefix(prefix: String) {
editText.setText(prefix)
editText.setSelection(prefix.length)
this.prefix = prefix
}
Voici une solution moins efficace qui devrait gérer tous les cas de figure lorsque des caractères OR sont supprimés/insérés dans OR autour du préfixe.
prefix = "http://"
extra = "ahhttp://"
differencePrefix(prefix, extra) = "aht"
Code:
public static String differencePrefix(String prefix, String extra) {
if (extra.length() < prefix.length()) return "";
StringBuilder sb = new StringBuilder();
StringBuilder eb = new StringBuilder();
int p = 0;
for (int i = 0; i < extra.length(); i++) {
if (i >= prefix.length()) {
while(p < extra.length()) {
eb.append(extra.charAt(p));
p++;
}
break;
}
if (p >= extra.length()) break;
char pchar = extra.charAt(p);
char ichar = prefix.charAt(i);
while(pchar != ichar) {
//check if char was deleted
int c = i + 1;
if (c < prefix.length()) {
char cchar = prefix.charAt(c);
if (cchar == pchar) {
break;
}
}
sb.append(pchar);
p++;
if (p >= extra.length()) break;
pchar = extra.charAt(p);
}
p++;
}
return eb.toString() + sb.toString();
}
Vous pouvez l'utiliser comme ça
editText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
String input = s.toString();
if (!input.startsWith(prefix)) {
String extra = differencePrefix(prefix, input);
String newInput = prefix + extra;
editText.setText(newInput);
editText.setSelection(newInput.length());
}
}
});
Le code ci-dessous fonctionne pour moi. Il gère les cas où l'utilisateur édite le préfixe, le supprime, insère du texte à partir du tampon, modifie le texte sélectionné. Si l'utilisateur change de préfixe, le focus se déplace vers la fin du préfixe.
final String prefix = "http://";
final String[] aLastText = {prefix};
et.setText(prefix);
et.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
public void afterTextChanged(Editable sNew) {
if (!sNew.toString().startsWith(prefix)) {
String sLast = aLastText[0];
boolean isRemoving = sNew.length() < sLast.length();
int start;
int end = sNew.length() - 1;
for (start = 0; start < sLast.length() && start < sNew.length(); start++) {
if (sLast.charAt(start) != sNew.charAt(start))
break;
}
int k = sLast.length() - 1;
for (; end >= start && k >= 0; end--, k--) {
if (sLast.charAt(k) != sNew.charAt(end))
break;
}
String sEdited = sNew.toString().substring(start, ++end);
k += isRemoving ? 1 : 0;
k = k < prefix.length() ? prefix.length() : k;
String sSuffix = sLast.substring(k, sLast.length());
et.setText(prefix + sEdited + sSuffix);
et.setSelection(et.getText().length() - sSuffix.length());
}
aLastText[0] = et.getText().toString();
}
});
Exemples:
ht5tp: // localhost, 5http: // localhost, http:/5/localhost -> http: // 5localhost
http: localhost -> http: // localhost
Je viens de trouver la solution pour rendre le préfixe non modifiable et comment enregistrer du texte si vous essayez de supprimer le préfixe. C'est très proche de @Rajitha Siriwardena répondre. Tout ce que vous avez manqué, c'est de sauvegarder le texte avant d'appliquer les modifications. Il sera restauré dans afterTextChanged (...).
Code:
final String prefix = "http://";
editText.setText(prefix);
Selection.setSelection(editText.getText(), editText.getText().length());
editText.addTextChangedListener(new TextWatcher() {
String text;
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
text = charSequence.toString();
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void afterTextChanged(Editable editable) {
if (!editable.toString().startsWith(prefix)) {
editText.setText(text);
Selection.setSelection(editText.getText(), editText.getText().length());
}
}
});