Raj Turakhia
Raj Turakhia

Reputation: 245

Lag issue while changing focus from one editext to another and to another while quick typing

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>

enter image description here

Upvotes: 3

Views: 294

Answers (3)

Sambhav Khandelwal
Sambhav Khandelwal

Reputation: 3765

Instead of creating so many editTexts, you can use this library

Upvotes: -1

OhhhThatVarun
OhhhThatVarun

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

Ivo
Ivo

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

Related Questions