2013-01-07 12 views
44

我想有内部EDITTEXT常量文本,如:把常量文本内的EditText这应该是不可编辑的 - Android电子

http://<here_user_can_write> 

用户应该不能够从“http://”删除任何字符,我搜索有关这一点,并发现这一点:

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中可能,因为两者都是视图,单向会是一个不错的选择,有可能吗?

+0

检查这个答案http://stackoverflow.com/a/19789317/983741 –

回答

85

你试过这种方法吗?

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

      } 

     } 
    }); 
+22

它的安全使用'startsWith'而不是'contains',以避免用户移动光标位置,在常量之前输入任何内容。 –

+0

但删除它时,如果不从删除按钮移动手,文本将被删除,我可以解决吗? – user1767260

+0

感谢machan,这是有用的... –

9

@Rajitha Siriwardena的回答有一个小问题。 它假定了后缀,这意味着除了前后缀整个字符串已被删除,如果你有串

http://stackoverflow.com/ 

,并尝试删除http://任何部分将删除stackoverflow.com/导致只有http://

我还添加了一个检查用户尝试输入前的前缀。

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

注意:这不处理用户试图仅在前后编辑前缀本身的情况。

0

这是一个效率较低的解决方案,它应该处理在字符或单词被删除/插入前缀周围的所有情况。

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

你有它差不多吧,尽量

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

这就是你能真正做到这一点与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); 
+0

非常有用和正在工作 – ashishdhiman2007

0

我知道我恢复旧的文章,但我想,我已经跟这个话题这些天奋斗社会各界分享,我发现,放置TextViewEditText不仅是完全可行的(以回答问题的第二部分),在这种情况下,当起始位置需要常量文本时更多,但也更可取。而且光标甚至不会在“可变”文本之前移动,这是一种优雅的效果。 我更喜欢这个解决方案,因为它不会增加我的应用程序的工作量和复杂度,无论是听众还是任何人。

这里是我的解决方案的示例代码:

<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的意见。 这里的诀窍是玩EditTextandroid:paddingStart属性,使文本刚好在TextView之后开始,android:layout_centerVertical="true"android:layout_marginStart="3dp"的属性确保其文本与输入的文本正确对齐,并且与开始的底线EditText(或至少这发生在使用材质主题时)。

2

使用这个定制的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(); 
} 
} 
+0

谢谢,这非常有帮助 –

2

CODE

代码从中通过阿里穆扎法尔

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添加自定义前缀为您EDITTEXT(PREFIX不可编辑)

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

请确保您在xml文件中使用正确的类路径。 com.alimuzaffar.customwidgets.PrefixEditText - 如果你使用它,你的应用程序将粉碎。 –

+0

是的,我没错,我会编辑帖子。我的错 –

0

我刚刚发现解决方案如何使前缀不可编辑,以及如何尝试删除前缀时如何保存文本。这非常接近@Rajitha Siriwardena的答案。您错过的所有内容都是在应用更改之前保存文本。它将在afterTextChanged(...)中恢复。

代码:

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()); 
     } 
    } 
}); 
相关问题