Ryan
Ryan

Reputation: 614

How to limit number of lines in Dynamic Android EditText within AlertDialog

I am dynamically creating an EditText within an AlertDialog and want to limit the number of lines shown. Currently, the EditText keeps expanding vertically with each carriage return. This results in the dialog buttons not being visible after a certain point. I have isolated the code down to the following :

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Button b = (Button) findViewById(R.id.button);
    b.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
            AlertDialog.Builder builder = new AlertDialog.Builder(v.getContext());
            EditText input = new EditText(v.getContext());
            input.setLines(4);
            //input.setMaxLines(4);
            input.setSingleLine(false);
            input.setGravity(Gravity.TOP);
            //input.setVerticalScrollBarEnabled(true);
            builder.setView(input);
            builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {     }
            });
            builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {    }
            });
            AlertDialog d = builder.create();
            d.show();
        }
    });

}

}

I'd be happy to either a) Limit the number of lines of text OR b) Have a scrollbar appear beyond X lines.

I've tried setting a number of properties on the EditText including 'setMaxLines','setHeight' and 'setVerticalScrollBarEnabled' and neither of these work.

I realise there is some existing suggestions for similar issues, but none where the EditText is created dynamically and within an AlertDialog. Any help or suggestions would be appreciated.

Upvotes: 2

Views: 2063

Answers (3)

Ryan
Ryan

Reputation: 614

As with Darshan's answer, I ended up extending the EditText, implementing the TextWatcher interface and looking to see when the number of lines exceeded the limit set. When it does, the saved cursor position/text is restored. See code below:

public class MaxEditText extends EditText implements TextWatcher {

private String saved;
private int positionSaved;
private int maxLines;

public MaxEditText(Context context, int maxLines) {
    super(context);
    this.maxLines = maxLines;
    this.setLines(maxLines);
    this.setSingleLine(false);
    this.setGravity(Gravity.TOP);
    this.addTextChangedListener(this);
}

@Override
public void onTextChanged(CharSequence cs, int arg1, int arg2, int arg3) {

}

@Override
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
    saved = arg0.toString();
    positionSaved = ((EditText) this).getSelectionStart();
}

@Override
public void afterTextChanged(Editable arg0) {
    if (this.getLineCount() > maxLines)
    {
        this.setText(saved);
        ((EditText) this).setSelection(positionSaved-1);
    }
}

}

It seems to me like a bit of a hack to have to 'undo' what is entered as opposed to preventing the text being entered in the first place, so if anyone has an alternative, please post it.

Upvotes: 0

Darshan Mistry
Darshan Mistry

Reputation: 3372

you can limit lines count in your LimitedEditText component

you can limit characters count in your LimitedEditText component

if you exceed the limit of characters or lines somewhere in the middle of text, cursor won't bring you to the end - it will stay where have you been.

Im turning off listener, because every call of setText() method would recursively call these 3 callback methods in case when user exceeded characters or lines limit.

import android.content.Context;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.EditText;
import android.widget.Toast;

/**
* EditText subclass created to enforce limit of the lines number in editable
* text field
*/
public class LimitedEditText extends EditText {

/**
 * Max lines to be present in editable text field
 */
private int maxLines = 1;

/**
 * Max characters to be present in editable text field
 */
private int maxCharacters = 50;

/**
 * application context;
 */
private Context context;

public int getMaxCharacters() {
    return maxCharacters;
}

public void setMaxCharacters(int maxCharacters) {
    this.maxCharacters = maxCharacters;
}

@Override
public int getMaxLines() {
    return maxLines;
}

@Override
public void setMaxLines(int maxLines) {
    this.maxLines = maxLines;
}

public LimitedEditText(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    this.context = context;
}

public LimitedEditText(Context context, AttributeSet attrs) {
    super(context, attrs);
    this.context = context;
}

public LimitedEditText(Context context) {
    super(context);
    this.context = context;
}

@Override
protected void onFinishInflate() {
    super.onFinishInflate();

    TextWatcher watcher = new TextWatcher() {

        private String text;
        private int beforeCursorPosition = 0;

        @Override
        public void onTextChanged(CharSequence s, int start, int before,
                int count) {                
            //TODO sth
        }

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count,
                int after) {
            text = s.toString();
            beforeCursorPosition = start;
        }

        @Override
        public void afterTextChanged(Editable s) {

            /* turning off listener */
            removeTextChangedListener(this);

            /* handling lines limit exceed */
            if (LimitedEditText.this.getLineCount() > maxLines) {
                LimitedEditText.this.setText(text);
                LimitedEditText.this.setSelection(beforeCursorPosition);
            }

            /* handling character limit exceed */
            if (s.toString().length() > maxCharacters) {
                LimitedEditText.this.setText(text);
                LimitedEditText.this.setSelection(beforeCursorPosition);
                Toast.makeText(context, "text too long", Toast.LENGTH_SHORT)
                        .show();
            }

            /* turning on listener */
            addTextChangedListener(this);

        }
    };

    this.addTextChangedListener(watcher);
}

}

Upvotes: 2

capt.swag
capt.swag

Reputation: 10651

If you want to set a fixed number of lines you should do

setLines(int numOfLines);

If you want to set a limit to the number of lines which will be added on typing

setMaxLines(int limit);

And for additional information, you could set the limit to minimum number of lines using

setMinLines(int limit);

Upvotes: 2

Related Questions