Make few prefilled characters uneditable in EditText using Android - android

I am working on EditText where I am displaying pre filled country code in start lets say "+971", what I want is that if user trying to click and edit in EditText, he should not edit or delete "+971" and can only be able to put number after that like "+971 123445579" and if trying to delete number then "+971" should not get delete.
My code is given below, please guide me how can I achieve this. Thanks
private fun setupTextChangeListener() {
edit_text.textWatcherListener = object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
setDatePickerIconOnDemand()
}
override fun afterTextChanged(s: Editable?) {
}
}
}
// In this method I am putting Start Drawable in EditText:
private fun setDatePickerIconOnDemand() {
edit_text.setDrawableStart(context.drawable(R.drawable.ic_earh_arrow_down_default))
edit_text.setDrawable()
}

You can add following lines of code in on onTextChanged callback
if (edit_text.length() < 5 || !edit_text.text!!.startsWith("+971 ")) {
edit_text.setText("+971 ")
edit_text.setSelection(edit_text.length())
}
What it will do is: It will check onTextChanged 'if your current text in edit text is only your country code, Set the country code in your editText and move cursor at the end.

Related

How to forbid "00" or "0123-like" start of input in Android EditText, in Kotlin?

I have an EditText object with the numberDecimal input type. The input manipulation (e.g., calculation) is working ok, but inputs starting with "00" and "0123-like" (zero followed by a number, not the dot) are currently permitted.
How can I forbid inputs starting with "00" or "0123-like" (zero followed by a number, not the dot), in Kotlin?
Aftering googling and reading many similar questions and answers, I've tried TextWatcher and InputFilter, but can't really figure out a solution.
You can use a TextWatcher and regular expression if the modified string is in the format 0, followed by a number, you can remove the last inserted digit and return to a string containing only the initial 0.
editText.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) {
val newText = s.toString().trim()
// Check if the text is 0 followed by another digit, in that case remove the last inserted value
if (newText.length > 1 && newText.matches("^0[\\d]+".toRegex())) {
// Unwanted expression: remove last inserted char and reset the cursor position to show after the first character
editText.setText("0")
editText.setSelection(1)
}
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
})
EDIT
If you need to apply the same TextWatcher to multiple EditText you could define your CustomTextWatcher class:
class CustomTextWatcher(
private val editText: EditText
) : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
override fun afterTextChanged(s: Editable?) {
val newText = s.toString().trim()
// Check if the text is 0 followed by another digit, in that case remove the last inserted value
if (newText.length > 1 && newText.matches("^0[\\d]+".toRegex())) {
// Unwanted expression: remove last inserted char and reset the cursor position to show after the first character
editText.setText("0")
editText.setSelection(1)
}
}
}
And then add it to your EditTexts with:
editText1.addTextChangedListener(CustomTextWatcher(editText1));
editText2.addTextChangedListener(CustomTextWatcher(editText2));
...

How can I prevent a user from deleting pre-existing text in an EditText widget?

I have an EditText with some pre-existing text that MUST NOT be deleted. The user should only be allowed to append text in the view.
The solution I have right now can be seen below, where I check if the new length of the EditText is shorter than the original text. If it is, the user has attempted to delete a character so I just repopulate the view with the original text and move the cursor. The problem with this solution is that the user could just enter text that is longer than the original length, then change the position of the cursor to somewhere within the original text, and finally delete characters.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val originalText = "Hello"
binding.et.setText(originalText)
binding.et.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
s?.let {
if (s.length < originalText.length) {
binding.et.setText(originalText)
binding.et.setSelection(originalText.count())
}
}
}
override fun afterTextChanged(s: Editable?) {}
})
}
What should I do? I'm open to all ideas.
Thanks!
Edit:
I've also tried combining an EditText and a TextView (as some have suggested) but the layout is difficult to achieve because both the original text and the new text can span multiple lines. My solution above contains one word in the original text but it could be many. So I need to cater for this scenario:
...where the white box represents the TextView and the red box represents the EditText.
I don't think Bö macht Blau's answer will work either because the prefix is in its own "column".
I think I will have to use Zain's solution with (startsWith()) or create a custom view (though I've never done one of these before).
Please consider #Gabe Sechan advice in OP comments that the EditText alone is not the optimum solution for that.
In case you still need to use EditText then you can change the condition to check that the returned CharSequence of the EditText watcher starts with the original text using startsWith() method
et.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
s?.let {
if (!s.startsWith(originalText)) {
if (s.length <= originalText.length) {
et.setText(originalText)
et.setSelection(originalText.count())
} else {
et.setText(originalText + s.subSequence(originalText.length, s.length))
et.setSelection(s.count())
}
}
}
}
override fun afterTextChanged(s: Editable?) {}
})
You can use a text field, that's a combination of a TextInputEditText and a TextInputLayout. Then you can set a prefix like so:
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:prefixText="#string/prefix_text">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</com.google.android.material.textfield.TextInputLayout>
The prefix will be visible as soon as the TextInputEditText gains focus. Since it is not part of the EditText content, it can't be modified by the users.
Useful links:
documentation for TextInputLayout
overview of style options
This check should work:
if (s.substring(0, 4) == originalText) {
// update text
}
But consider looking into InputFilter, as a comment suggested.

How to get full text from the editText by using addTextChangedListener in kotlin

I would like to add full text from the editText into an array. But while running this code the array
values will be like first word , second word etc. How to get the full sentence and i want to add it
into an array(Already did it using interface)
Note : The code is placed on the recyclerview adapter ,
Where texBox is the EditText and examinationListener is the interface used
Here i shared the code. Please check it.
textBox.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable) {
textFromBox = s.toString()
examinationListener.addAnswer(textFromBox)
}
override fun beforeTextChanged(s: CharSequence, start: Int,
count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence, start: Int,
before: Int, count: Int) {
}
})
override fun afterTextChanged(s: Editable) {
textFromBox = textBox.text.toString()
examinationListener.addAnswer(textFromBox)
}
I created an array up to the list size. Each items of RecyclerView have an EditText.
val array = arrayOfNulls<String>(listSize)
We need to know the position of EditText to add to the array. Change interface like this:
interface ExaminationListener {
fun addAnswer(text: String, position: Int)
}
function addAnswer:
override fun addAnswer(text: String, position: Int) {
array[position] = text // we add every changes to the array.
}
This use is more useful. We don't need other methods:
textBox.doAfterTextChanged {
examinationListener.addAnswer(it.toString(), position) // you can use adapterPosition if that is in Viewholder
}
We create a sentence from array elements. You can see your full sentence:
val sentence = array.filterNotNull().joinToString (separator = " ") { it -> it }
Log.d("Sentence" , sentence)
Very Simple just add a TextWatcher to your EditText like:
val answerWatcher = object : TextWatcher {
override fun beforeTextChanged(value: CharSequence, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(value: CharSequence, start: Int, before: Int, count: Int) {
when {
// Here value is your full text from your EditText
value.toString().equals("I am a sentence", ignoreCase = true) -> {
}
else -> {
// Just a test condition
}
}
}
override fun afterTextChanged(s: Editable) {
}
}
// Add this TextWatcher to your EditText
edittext.addTextChangedListener(answerWatcher)

Updating EditTexts on the fly

Trying to learn kotlin and I'm working on a simple conversion app where I have two edittexts. I would like for the calculation to happen automatically when I change the text. So if edittext2 is supposed to be 10 times larger than edittext1, I'd like edittext1 change to 10 if I enter 100 in edittext2 and if I change edittext2 to 50, edittext1 changes to 5, etc..
Currently I have a convert and clear button, but I would like to minimize the design and make it less cumbersome.
Try this out
edittext2.addTextChangedListener(object : TextWatcher {
override fun onTextChanged(s: CharSequence, start: Int, before: Int,
count: Int) {
if (s != "") {
val outPut=Integer.parseInt("get the value of editText1")+ Integer.parseInt("get the value of editText2")
txtOutPut.text="$outPut"
}
}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int,
after: Int) {
}
override fun afterTextChanged(s: Editable) {
}
})

How can I replace one note with a different note as the user is typing (replace “space” with “-”

I am using a tag system similar to SO, and instead of forcing the user to find the dash in their keyboard I want space to automatically be translated to a dash.
I am trying to implement it with this textWatcher, but the app doesn't let me type the space bar (it kinda flashes but nothing happens.
imageTagsInput.addTextChangedListener(object : TextWatcher {
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
imageTagsInput.removeTextChangedListener(this)
imageTagsInput.setText(imageTagsInput.text.toString().replace(" ","-"))
imageTagsInput.addTextChangedListener(this)
imageTagsInput.setSelection(imageTagsInput.length())
}
override fun afterTextChanged(s: Editable?) {
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
})
And this is the xml of the EditText:
android:digits="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-  "
Add something like this in afterTextChanged
String result = s.toString().replaceAll(" ", "-");
if (!s.toString().equals(result)) {
ed.setText(result);
ed.setSelection(result.length());
// alert the user
}
For more info see this answer

Categories

Resources