Reputation: 245
I am trying to create PIN View by using 8 edittext. I have used a recursive function to addTextChangedListener for each and every edittext.
So my expectation here is when user type single digit in one edittext the focus should move to next edittext and so on. So the issue that I am facing is when user type digits too fast edittexts are not catching all digits.
For Example: I type 89898989 quickly It only fills up with 888888
Consider my following code
class FirstFragment : Fragment() {
private var _binding: FragmentFirstBinding? = null
private val binding get() = _binding!!
var count = 0
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentFirstBinding.inflate(inflater, container, false)
val views = arrayListOf(
_binding!!.textView,
_binding!!.textView2,
_binding!!.textView3,
_binding!!.textView4,
_binding!!.textView5,
_binding!!.textView6,
_binding!!.textView7,
_binding!!.textView8
)
views.first().requestFocus()
someRecursiveFunction(views)
return binding.root
}
private fun someRecursiveFunction(view: ArrayList<EditText>) {
view[count].addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable) {
if (view[count].text.toString().length == 1) {
if (count == view.size - 1) {
Toast.makeText(context, "Reached last digit", Toast.LENGTH_SHORT).show()
return
} else {
view[count].removeCallbacks {}
count++
view[count].requestFocus()
someRecursiveFunction(view)
}
}
}
override fun beforeTextChanged(
s: CharSequence, start: Int,
count: Int, after: Int
) {}
override fun onTextChanged(
s: CharSequence, start: Int,
before: Int, count: Int
) {}
})
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
Layout code:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".FirstFragment">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<EditText
android:id="@+id/textView"
android:background="@android:color/white"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:focusable="true"
android:maxLines="1"
android:maxLength="1"
android:gravity="center"
android:inputType="number"
android:textColor="@color/black"
android:layout_width="40dp"
android:layout_height="40dp" />
<EditText
android:id="@+id/textView2"
android:background="@android:color/white"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:focusable="true"
android:maxLines="1"
android:maxLength="1"
android:gravity="center"
android:inputType="number"
android:textColor="@color/black"
android:layout_width="40dp"
android:layout_height="40dp" />
<EditText
android:id="@+id/textView3"
android:background="@android:color/white"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:focusable="true"
android:maxLines="1"
android:inputType="number"
android:maxLength="1"
android:gravity="center"
android:textColor="@color/black"
android:layout_width="40dp"
android:layout_height="40dp" />
<EditText
android:id="@+id/textView4"
android:background="@android:color/white"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:focusable="true"
android:maxLines="1"
android:inputType="number"
android:maxLength="1"
android:gravity="center"
android:textColor="@color/black"
android:layout_width="40dp"
android:layout_height="40dp" />
<EditText
android:id="@+id/textView5"
android:background="@android:color/white"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:focusable="true"
android:maxLines="1"
android:inputType="number"
android:maxLength="1"
android:gravity="center"
android:textColor="@color/black"
android:layout_width="40dp"
android:layout_height="40dp" />
<EditText
android:id="@+id/textView6"
android:background="@android:color/white"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:focusable="true"
android:maxLines="1"
android:inputType="number"
android:maxLength="1"
android:gravity="center"
android:textColor="@color/black"
android:layout_width="40dp"
android:layout_height="40dp" />
<EditText
android:id="@+id/textView7"
android:background="@android:color/white"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:focusable="true"
android:maxLines="1"
android:inputType="number"
android:maxLength="1"
android:gravity="center"
android:textColor="@color/black"
android:layout_width="40dp"
android:layout_height="40dp" />
<EditText
android:id="@+id/textView8"
android:background="@android:color/white"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:focusable="true"
android:maxLines="1"
android:inputType="number"
android:maxLength="1"
android:gravity="center"
android:textColor="@color/black"
android:layout_width="40dp"
android:layout_height="40dp" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Upvotes: 3
Views: 294
Reputation: 3765
Instead of creating so many editTexts, you can use this library
Upvotes: -1
Reputation: 4330
I think you can do something like this to improve performance. Also, I think you should avoid recursion whenever you can.
You don't need to keep a list of all the views when you already have them inside your LinearLayout
try to use the properties LinearLayout
already have like children
XML
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".FirstFragment">
<LinearLayout
android:id="@+id/editTextContainer" <--- added this line
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<EditText
android:id="@+id/editText"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:background="@android:color/white"
android:focusable="true"
android:gravity="center"
android:inputType="number"
android:maxLength="1"
android:maxLines="1"
android:textColor="@color/black" />
<EditText
android:id="@+id/editText2"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:background="@android:color/white"
android:focusable="true"
android:gravity="center"
android:inputType="number"
android:maxLength="1"
android:maxLines="1"
android:textColor="@color/black" />
<EditText
android:id="@+id/editText3"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:background="@android:color/white"
android:focusable="true"
android:gravity="center"
android:inputType="number"
android:maxLength="1"
android:maxLines="1"
android:textColor="@color/black" />
<EditText
android:id="@+id/editText4"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:background="@android:color/white"
android:focusable="true"
android:gravity="center"
android:inputType="number"
android:maxLength="1"
android:maxLines="1"
android:textColor="@color/black" />
<EditText
android:id="@+id/editText5"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:background="@android:color/white"
android:focusable="true"
android:gravity="center"
android:inputType="number"
android:maxLength="1"
android:maxLines="1"
android:textColor="@color/black" />
<EditText
android:id="@+id/editText6"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:background="@android:color/white"
android:focusable="true"
android:gravity="center"
android:inputType="number"
android:maxLength="1"
android:maxLines="1"
android:textColor="@color/black" />
<EditText
android:id="@+id/editText7"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:background="@android:color/white"
android:focusable="true"
android:gravity="center"
android:inputType="number"
android:maxLength="1"
android:maxLines="1"
android:textColor="@color/black" />
<EditText
android:id="@+id/editText8"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:background="@android:color/white"
android:focusable="true"
android:gravity="center"
android:inputType="number"
android:maxLength="1"
android:maxLines="1"
android:textColor="@color/black" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Fragment
You don't need count
or views
to keep track of your views
class FirstFragment : Fragment() {
private var _binding: FragmentFirstBinding? = null
private val binding get() = _binding!!
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
_binding = FragmentFirstBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
binding.editTextContainer.children.first().requestFocus()
setAfterTextChangedListener(binding.editTextContainer)
}
private fun setAfterTextChangedListener(editTextContainer: ViewGroup) {
val editTexts = editTextContainer.children.toList()
editTexts.forEachIndexed { index, view ->
if (view is EditText) {
view.doAfterTextChanged {
if (it?.isNotEmpty() == true && index + 1 != editTexts.size) {
editTexts[index + 1].requestFocus()
}
}
}
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
Upvotes: 2
Reputation: 23357
You do view[count].removeCallbacks {}
. This does absolutely nothing in your code. I suppose you think it removes the TextChangedListener, but it doesn't.
There's also no need to wait with adding the listener to the next views. Just add them all, then you also don't need to make the function recursive. So I propose to just do something like this:
private fun someRecursiveFunction(view: ArrayList<EditText>) {
view.forEach {
it.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable) {
if (view[count].text.toString().length == 1) {
if (count == view.size - 1) {
Toast.makeText(context, "Reached last digit", Toast.LENGTH_SHORT).show()
return
} else {
count++
view[count].requestFocus()
}
}
}
override fun beforeTextChanged(
s: CharSequence, start: Int,
count: Int, after: Int
) {}
override fun onTextChanged(
s: CharSequence, start: Int,
before: Int, count: Int
) {}
})
}
}
it should functionally work the same as your code, except that it already adds all listeners at once. Although I don't know if it helps with your problem, I do think it would be an improvement on your code.
Upvotes: 0