it-swarm.com.de

Fügen Sie in EditText konstanten Text ein, der nicht bearbeitbar sein sollte - Android

Ich möchte einen konstanten Text in editText haben:

http://<here_user_can_write>

Der Benutzer sollte keine Zeichen aus "http://" löschen können. Ich habe danach gesucht und Folgendes gefunden:

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) : "";
        }
    }
}); 

ich weiß jedoch nicht, ob es den Benutzer einschränkt, keine Zeichen von Anfang bis Ende Limit zu löschen. Ich konnte auch die Verwendung der Spanned-Klasse nicht verstehen.

Eine Möglichkeit wäre eine gute Wahl, wenn wir eine TextView in EditText einfügen können, aber ich glaube nicht, dass dies in Android möglich ist, da beide Ansichten sind.

55
Shrikant

Hast du diese Methode ausprobiert? 

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());

            }

        }
    });
114

So können Sie es tatsächlich mit einer InputFilter machen:

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;
        }
      }
    }
});

Wenn Sie möchten, dass das Präfix nicht auswählbar ist, können Sie den folgenden Code hinzufügen.

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);
12
Michael

Bei @Rajitha Siriwardenas Antwort gab es ein kleines Problem. Sie geht davon aus, dass die gesamte Zeichenfolge außer dem Suffix gelöscht wurde, bevor das Suffix bedeutet, dass Sie die Zeichenfolge haben

http://stackoverflow.com/

und versuchen, einen beliebigen Teil von http:// zu löschen, den Sie stackoverflow.com/ löschen, was nur http:// ergibt.

Ich habe auch eine Prüfung hinzugefügt, falls der Benutzer versucht, vor dem Präfix einzugeben.

 @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());
    }
}

Hinweis: Dies behandelt nicht den Fall, in dem der Benutzer versucht, das Präfix selbst nur davor und danach zu bearbeiten.

Sie hatten es fast richtig, versuchen Sie es

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;
            }
        }});
4
slezadav

CODE ZUM HINZUFÜGEN VON CUSTOM PREFIX ZU IHREM EDITTEXT (PREFIX NICHT BEARBEITBAR)

Code from Medium von 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());
    }
}

Und XML

<com.yourClassPath.PrefixEditText
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content"
    Android:gravity="bottom"
    Android:textSize="14sp"
    Android:tag="€ " />
4
Jack the Ripper

Aus dem Blog von ALi Muzaffar entnommen, siehe den ursprünglichen Beitrag für weitere Details.

Verwenden Sie custom EditText View, um den Präfixtext zu zeichnen und die Auffüllung entsprechend der Präfixtextgröße hinzuzufügen:

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();
}
}
3
Vishal Jadav

Ich weiß, dass ich einen alten Beitrag wiederbelebe, aber ich möchte mit der Community teilen, dass ich mich mit diesem Thema derzeit schwer getan habe. Ich fand, dass das Platzieren einer TextView über die EditText nicht nur absolut machbar ist (um auf den zweiten Teil des Newsletters zu antworten Frage), viel mehr in diesem Fall, wenn der konstante Text in der Ausgangsposition benötigt wird, aber auch bevorzugt. Darüber hinaus bewegt sich der Cursor nicht einmal vor dem "veränderlichen" Text, was ein eleganter Effekt ist. Ich bevorzuge diese Lösung, weil sie meiner App mit Zuhörern und was auch immer noch zu viel Arbeitsaufwand und Komplexität hinzufügt.

Hier ist ein Beispielcode meiner Lösung:

<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>

Wenn Sie die Ansichten in eine RelativeLayout einschließen, werden sie überlappt. Der Trick besteht darin, mit der Android:paddingStart-Eigenschaft der EditText zu spielen, damit der Text direkt nach der TextView beginnt, während Android:layout_centerVertical="true" und Android:layout_marginStart="3dp"-Eigenschaften der TextView dies sicherstellen Sein Text ist korrekt an dem eingegebenen Text und am Anfang der darunterliegenden Zeile der Variable EditText ausgerichtet (oder dies geschieht zumindest, wenn ein Material verwendet wird).

1

Dies ist im Grunde das Präfix "+91" zu Ihrem Bearbeitungstextfeld der Telefonnummer hinzuzufügen.

1. Fügen Sie diesen Code oncreate () der Aktivität hinzu

@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.Declare eine Methode namens 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.declare "digits_number" in Ihrer Wertedatei

    <string name="digits_number">1234567890+</string>
1
Ankit Beura
    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);
0
Mr.Nestorjava

Basierend auf @ demaksee Kommentar. Ich erweitere EditText und überschreibe die Funktion onSelectionChanged. Der Benutzer kann das Präfix also nicht bearbeiten. Sehr einfach und nützlich. 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
}

Hier ist eine weniger effiziente Lösung, die alle Fälle behandeln sollte, in denen Zeichen OR um das Präfix herum in OR gelöscht/eingefügt werden.

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();
}

Sie können es so verwenden

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());
        }
    }
});
0
Veedka

Der folgende Code funktioniert für mich. Es behandelt Fälle, in denen der Benutzer das Präfix bearbeitet, löscht, Text aus dem Puffer einfügt und den ausgewählten Text ändert. Wenn der Benutzer das Präfix ändert, wird der Fokus zum Ende des Präfixes verschoben.

    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();
        }
    });

Beispiele:

ht5tp: // localhost, 5http: // localhost, http:/5/localhost -> http: // 5localhost

http: localhost -> http: // localhost

0
Pavel Kataykin

Ich habe gerade die Lösung gefunden, wie man das Präfix nicht editierbar macht und wie man Text speichert, wenn man versucht, das Präfix zu entfernen. Das ist der Antwort von @Rajitha Siriwardena sehr nahe. Alles, was Sie versäumt haben, ist das Speichern von Text, bevor Änderungen vorgenommen werden. Es wird in afterTextChanged (...) wiederhergestellt.

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());
        }
    }
});
0