80

editText内に次のような一定のテキストを入れたい:

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ではできないと思いますが、可能ですか?

4

16 に答える 16

165

この方法は試しましたか?

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

            }

        }
    });
于 2013-01-07T12:04:53.007 に答える
16

それはあなたが実際にそれを行う方法です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);
于 2016-04-03T17:58:49.397 に答える
10

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

注: これは、ユーザーが前後にのみプレフィックス自体を編集しようとするケースを処理しません。

于 2015-01-22T23:17:08.847 に答える
6

あなたはそれをほぼ正しかった、試してみてください

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;
            }
        }});
于 2015-10-14T11:17:26.297 に答える
5

EDITTEXT にカスタム プレフィックスを追加するコード (プレフィックスは編集不可)

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.yourClassPath.PrefixEditText
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="bottom"
    android:textSize="14sp"
    android:tag="€ " />
于 2017-08-31T10:05:14.203 に答える
3

TextView古い投稿を復活させていることは知っていますが、最近このトピックに苦労していることをコミュニティと共有したいと思いますEditText。 、この場合、開始位置に一定のテキストが必要な場合はさらに多くなりますが、それも望ましいです。さらに、カーソルは「変更可能な」テキストの前ではまったく移動しません。これはエレガントな効果です。リスナーなどを使用したアプリにワークロードや複雑さが追加されないため、このソリューションを好みます。

私のソリューションのサンプルコードは次のとおりです。

<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がオーバーラップします。ここでの秘訣は、 のandroid:paddingStartプロパティをいじって、、 whileEditTextの直後にテキストを開始させ、そのテキストが入力されたテキストと下にある行の開始(または少なくともこれは、マテリアルをテーマにしたものを使用している場合に発生します)。TextViewandroid:layout_centerVertical="true"android:layout_marginStart="3dp"TextViewEditText

于 2016-10-05T16:57:18.200 に答える
3

プレフィックスを追加するKotlin拡張機能を作りました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)
        })
    }
于 2020-07-07T07:16:53.883 に答える
1

これは、プレフィックスの前後で文字または単語が削除/挿入された場合のすべてのケースを処理する効率の悪いソリューションです。

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());
        }
    }
});
于 2015-09-14T22:38:09.870 に答える
1
    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);
于 2018-04-07T07:21:54.300 に答える
1

以下のコードは私にとってはうまくいきます。ユーザーが接頭辞を編集、削除、バッファからテキストを挿入、選択したテキストを変更する場合を処理します。ユーザーがプレフィックスを変更すると、フォーカスはプレフィックスの末尾に移動します。

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

例:

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

http:localhost -> http://localhost

于 2019-01-17T14:10:49.090 に答える