Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EditText with not-editable/not-cancellable suffix [duplicate]

i created a layout for one of my activities in which users can insert a value in some EditText widget. I need that some of these EditText must have a suffix (like cm, mm and so on) that has to be not editable. After the user has inserted the value i will parse the content of these EditText avoiding the suffix so i will handle the only input without the suffix. How to do that?

I have already searched and searched here on SO but nothing helped me. I found answers like this one https://stackoverflow.com/a/20794581/2516399 that don't help me.

I hope i was clear in my question... sorry for my english

like image 874
smartmouse Avatar asked Feb 24 '15 18:02

smartmouse


5 Answers

I have made extension function for EditText:

fun EditText.addSuffix(suffix: String) {
    val editText = this
    val formattedSuffix = " $suffix"
    var text = ""
    var isSuffixModified = false

    val setCursorPosition: () -> Unit =
        { Selection.setSelection(editableText, editableText.length - formattedSuffix.length) }

    val setEditText: () -> Unit = {
        editText.setText(text)
        setCursorPosition()
    }

    this.addTextChangedListener(object : TextWatcher {
        override fun afterTextChanged(editable: Editable?) {
            val newText = editable.toString()

            if (isSuffixModified) {
                // user tried to modify suffix
                isSuffixModified = false
                setEditText()
            } else if (text.isNotEmpty() && newText.length < text.length && !newText.contains(formattedSuffix)) {
                // user tried to delete suffix
                setEditText()
            } else if (!newText.contains(formattedSuffix)) {
                // new input, add suffix
                text = "$newText$formattedSuffix"
                setEditText()
            } else {
                text = newText
            }
        }

        override fun beforeTextChanged(charSequence: CharSequence?, start: Int, count: Int, after: Int) {
            charSequence?.let {
                val textLengthWithoutSuffix = it.length - formattedSuffix.length
                if (it.isNotEmpty() && start > textLengthWithoutSuffix) {
                    isSuffixModified = true
                }
            }
        }

        override fun onTextChanged(charSequence: CharSequence?, start: Int, before: Int, count: Int) {
        }
    })
}

You can then use it as:

yourEditTextView.addSuffix("suffix")
like image 59
netpork Avatar answered Nov 10 '22 19:11

netpork


This is my solution: An EditText class that draws the suffix behind the text. There are two custom attributes for defining the text of the suffix and the suffix padding (to the left corner of the EditText).

public class EditTextWithSuffix extends EditText {
    TextPaint textPaint = new TextPaint();
    private String suffix = "";
    private float suffixPadding;

    public EditTextWithSuffix(Context context) {
        super(context);
    }

    public EditTextWithSuffix(Context context, AttributeSet attrs) {
        super(context, attrs);
        getAttributes(context, attrs, 0);
    }

    public EditTextWithSuffix(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        getAttributes(context, attrs, defStyleAttr);
    }

    @Override
    public void onDraw(Canvas c){
        super.onDraw(c);
        int suffixXPosition = (int) textPaint.measureText(getText().toString()) + getPaddingLeft();
        c.drawText(suffix, Math.max(suffixXPosition, suffixPadding), getBaseline(), textPaint);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        textPaint.setColor(getCurrentTextColor());
        textPaint.setTextSize(getTextSize());
        textPaint.setTextAlign(Paint.Align.LEFT);
    }

    private void getAttributes(Context context, AttributeSet attrs, int defStyleAttr) {
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.EditTextWithSuffix, defStyleAttr, 0);
        if(a != null) {
            suffix = a.getString(R.styleable.EditTextWithSuffix_suffix);
            if(suffix == null) {
                suffix = "";
            }
            suffixPadding = a.getDimension(R.styleable.EditTextWithSuffix_suffixPadding, 0);
        }
        a.recycle();
    }
}

here is the attributes definition:

<resources>
    <declare-styleable name="EditTextWithSuffix">
        <attr name="suffix" format="string|reference" />
        <attr name="suffixPadding" format="dimension" />
    </declare-styleable>
</resources>
like image 36
artkoenig Avatar answered Nov 10 '22 20:11

artkoenig


private static final String mSuffix = "SUFX";

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        final EditText et = new EditText(this);
        et.setText(mSuffix);

        et.setOnFocusChangeListener(new OnFocusChangeListener() {   
            @Override
            public void onFocusChange(View v, boolean hasFocus) {

                //NO FOCUS
                if(!hasFocus){
                    //HAS USER CLEARED THE SUFFIX
                    if(!et.getText().toString().contains(mSuffix)){
                        //ADDING SUFFIX AGAIN
                        String newText = et.getText().toString();
                        et.setText(mSuffix+newText);
                    }
                }
            }
        });


    }

In my opinion, use Regular Exp. to check the suffix. it will be more secure and simple.

SOLUTION:2

Here is another solution,something tricky ;)

   <RelativeLayout
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content">
    <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/test_value"
            android:layout_alignParentLeft="true"
            android:id="@+id/editText2"
            android:layout_gravity="center"
            />
    <TextView
            android:id="@+id/text_hint"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            android:text="@string/hint_test"
            android:textSize="18sp"
            android:layout_marginRight="10dp"
            android:textColor="#808080"
            />
</RelativeLayout>

RESULT/OUTPUT

OUTPUT:

REF:StackOverFlow

like image 25
theapache64 Avatar answered Nov 10 '22 21:11

theapache64


Try this

final EditText eTxt = (EditText) findViewById(R.id.edit_text);

eTxt.setText("cm");
Selection.setSelection(eTxt.getText(), eTxt.getText().length());

eTxt.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("cm")){
            eTxt.setText("cm");
            Selection.setSelection(eTxt.getText(), eTxt.getText().length());
        }

    }
});
like image 5
Apurva Avatar answered Nov 10 '22 19:11

Apurva


Try Out the following code for numeric edittext with alphabetic suffix:-

expiry.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 c, int start, int count,
                                  int after) {
        // TODO Auto-generated method stub

    }

    @Override
    public void afterTextChanged(Editable e) {
        String s = e.toString();
        if (s.length() > 0) {
            if (!s.endsWith("days")) {
                if (!s.equals(s + "days")) {
                    s = s.replaceAll("[^\\d.]", "");
                    expiry.setText(s + "days");
                } else {
                    expiry.setSelection(s.length() - "days".length());
                }
            } else {
                expiry.setSelection(s.length() - "days".length());
                if (s.equals("days")) {
                    expiry.setText("");
                }
            }
        }
    }
});
like image 2
Nikhil Ambuwani Avatar answered Nov 10 '22 21:11

Nikhil Ambuwani