在EditText中放置不可编辑的常量文本 – Android
我想在editText里面有如下的常量文本:
http://<here_user_can_write>
用户不应该能够从“ http://
”中删除任何字符,我search了这个,发现这个:
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) : ""; } } });
但是我不知道是否限制用户不要从开始到结束限制删除任何字符。 我也无法理解使用Spanned类。
一种方法是如果我们可以把TextView
放在EditText
但是我不认为在Android中是可能的,因为两者都是Views,是不是有可能?
你试过这个方法吗?
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()); } } });
@Rajitha Siriwardena的回答有一个小问题。 它假定除了后缀之外的整个string已经被删除,而后缀是如果你有string的意思
http://stackoverflow.com/
并尝试删除http://
任何部分,您将删除stackoverflow.com/
只导致http://
。
我还添加了一个检查,以防止用户在前缀之前尝试input。
@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()); } }
注意:这不处理用户试图仅在前后编辑前缀本身的情况。
这就是你可以用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; } } } });
如果您还希望前缀不可选,则可以添加以下代码。
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);
你说得对,试试
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; } }});
使用这个自定义的EditText:
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(); } }
为您的编辑添加自定义前缀的代码(不可编辑的前缀)
来自Ali Muzaffar的Medium的代码
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()); } }
和XML
<com.alimuzaffar.customwidgets.PrefixEditText android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="bottom" android:textSize="14sp" android:tag="€ " />
这是一个效率较低的解决scheme,应该处理在字符或单词被删除/插入前缀周围的所有情况。
prefix = "http://" extra = "ahhttp://" differencePrefix(prefix, extra) = "aht"
码:
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(); }
你可以像这样使用它
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()); } } });
我知道我正在重振一个旧post,但是我想和社区分享一下我最近在这个话题上挣扎的TextView
,我发现把TextView
放在EditText
上不仅是完美可行的(对第二部分问题),在这种情况下,在起始位置需要常量文本的情况下更多,但也是可取的。 而且光标甚至不会在“可变”文本之前移动,这是一个优雅的效果。 我更喜欢这个解决scheme,因为它不会增加我的应用与听众的工作量和复杂性。
以下是我的解决scheme的示例代码:
<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>
通过在RelativeLayout
包含视图,它们将被重叠。 这里的诀窍是使用EditText
的android:paddingStart
属性来使文本刚好在TextView
后面启动,而TextView
android:layout_centerVertical="true"
和android:layout_marginStart="3dp"
属性确保它文本与input的文本以及EditText
底层行的开始正确alignment(或者至less在使用Material主题时发生这种情况)。