Search code examples
androidlistviewxamarin.android

EditText Inside List. EditText.TextChanged gives wrong values on scroll


I have this row layout on each list:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <TextView
        android:id="@+id/RawNumberTextView"
        android:layout_marginLeft="@dimen/ButtonMargin"
        android:layout_marginRight="@dimen/ButtonMargin"
        android:text="@string/ColumnsStatistics_RawCount"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    <EditText
        android:id="@+id/RawBetEditText"
        android:clickable="true"
        android:focusable="true" 
        android:focusableInTouchMode="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:inputType="number"/>
            <com.google.android.material.button.MaterialButton
            style="@style/AppTheme.ButtonStyle"
        android:id="@+id/MinusOneButton"
        android:layout_marginLeft="@dimen/ButtonMargin"
        android:layout_marginRight="@dimen/ButtonMargin"
            android:elevation="@dimen/ButtonElevation"
            android:text="-1"        
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
              />
            <com.google.android.material.button.MaterialButton
            style="@style/AppTheme.ButtonStyle"
        android:id="@+id/PlusOneButton"
        android:layout_marginRight="@dimen/ButtonMargin"
            android:elevation="@dimen/ButtonElevation"
            android:text="+1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
             />
</LinearLayout>

and this Layout that contains the ListView:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/ListViewTitleTextView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    <ListView
        android:id="@+id/BetPerDrawListView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>

I'm using this Adapter:

using Android.App;
using Android.Views;
using Android.Widget;
using System.Collections.Generic;
using System.Globalization;

namespace KinoStats
{
    public class MoneyPerDrawAdapter : BaseAdapter<string>
    {
        private Activity Activity;
        private List<string> Data;

        public MoneyPerDrawAdapter(Activity Activity, List<string> Data) : base()
        {
            this.Activity = Activity;
            this.Data = Data;
        }
        public override string this[int position]
        {
            get { return Data[position]; }
        }

        public override int Count
        {
            get { return Data.Count; }
        }

        public override long GetItemId(int position)
        {
            return 0;
        }

        public override View GetView(int position, View convertView, ViewGroup parent)
        {
            View view = convertView;
            EditText betPerDrawEditText = null;
            Button MinusOneButton;
            Button PlusOneButton;

            if (view == null)
            {
                view = Activity.LayoutInflater.Inflate(Resource.Layout.SingleRawMoneyPerRaw, null);

                betPerDrawEditText = view.FindViewById<EditText>(Resource.Id.RawBetEditText);
                MinusOneButton = view.FindViewById<Button>(Resource.Id.MinusOneButton);
                PlusOneButton = view.FindViewById<Button>(Resource.Id.PlusOneButton);
                MinusOneButton.SetFocusable(ViewFocusability.NotFocusable);
                MinusOneButton.FocusableInTouchMode = false;
                PlusOneButton.SetFocusable(ViewFocusability.NotFocusable);
                PlusOneButton.FocusableInTouchMode = false;

                int pos = (int)MinusOneButton.Tag;

                MinusOneButton.Click += (sender, e) =>
                {
                    pos = (int)MinusOneButton.Tag;
                    int number = 0;

                    bool success = int.TryParse(Data[pos], out number);
                    if (success)
                    {
                        if (number > 0)
                            number--;
                        Data[pos] = number.ToString(CultureInfo.InvariantCulture);
                        betPerDrawEditText.Text = number.ToString(CultureInfo.InvariantCulture);
                    }
                    else
                    {
                        Data[pos] = number.ToString(CultureInfo.InvariantCulture);
                        betPerDrawEditText.Text = number.ToString(CultureInfo.InvariantCulture);
                    }
                };

                PlusOneButton.Click += (sender, e) =>
                {
                    pos = (int)PlusOneButton.Tag;
                    int number = 1;

                    bool success = int.TryParse(Data[pos], out number);
                    if (success)
                    {
                        number++;
                        betPerDrawEditText.Text = number.ToString(CultureInfo.InvariantCulture);
                        Data[pos] = number.ToString(CultureInfo.InvariantCulture);
                    }
                    else
                    {
                        betPerDrawEditText.Text = number.ToString(CultureInfo.InvariantCulture);
                        Data[pos] = number.ToString(CultureInfo.InvariantCulture);
                    }
                };

                betPerDrawEditText.TextChanged += (object sender, Android.Text.TextChangedEventArgs e) =>
                {
                    //int number = 0;

                    //bool success = int.TryParse(e.Text.ToString(), out number);
                    //if (success)
                    //    Data[pos] = e.Text.ToString();
                };
            }
            MinusOneButton = view.FindViewById<Button>(Resource.Id.MinusOneButton);
            PlusOneButton = view.FindViewById<Button>(Resource.Id.PlusOneButton);
            MinusOneButton.Tag = position;
            PlusOneButton.Tag = position;
            var rawCountTextView = view.FindViewById<TextView>(Resource.Id.RawNumberTextView);
            betPerDrawEditText = view.FindViewById<EditText>(Resource.Id.RawBetEditText);

            rawCountTextView.Text = position + Activity.GetString(Resource.String.ColumnsStatistics_RawCount);
            //betPerDrawEditText.TextChanged += (object sender, Android.Text.TextChangedEventArgs e) =>
            //{
            //    int number = 0;

            //    bool success = int.TryParse(Data[position], out number);
            //    if (success)
            //        Data[position] = e.Text.ToString();
            //};
            betPerDrawEditText.Text = Data[position];

            return view;
        }
    }
}

The ListView is displayed inside an AlertDialog through this function:

private void AddMoney()
        {
            var layout = LayoutInflater.Inflate(Resource.Layout.ListViewMoneyPerDraw, null);
            var listviewTitle = layout.FindViewById<TextView>(Resource.Id.ListViewTitleTextView);
            var list = layout.FindViewById<ListView>(Resource.Id.BetPerDrawListView);
            var moneyPerDrawDialogBuilder = new AlertDialog.Builder(Activity);

            var listOptions = new List<string>();
            listOptions.Add("1");
            listOptions.Add("2");
            listOptions.Add("3");
            listOptions.Add("4");
            listOptions.Add("1");
            listOptions.Add("2");
            listOptions.Add("3");
            listOptions.Add("4");
            listOptions.Add("1");
            listOptions.Add("2");
            listOptions.Add("3");
            listOptions.Add("4");
            listOptions.Add("1");
            listOptions.Add("2");
            listOptions.Add("3");
            listOptions.Add("4");
            list.Adapter = new MoneyPerDrawAdapter(Activity, listOptions);
            list.ItemsCanFocus = true;

            moneyPerDrawDialogBuilder.SetTitle(GetString(Resource.String.NumbersSearch_NumberSelectionAlertDialogTitle));
            moneyPerDrawDialogBuilder.SetIcon(Resource.Mipmap.ic_launcher);
            moneyPerDrawDialogBuilder.SetView(layout);
            moneyPerDrawDialogBuilder.SetCancelable(false);
            moneyPerDrawDialogBuilder.SetPositiveButton(GetString(Android.Resource.String.Ok), (s, ex) => {  }); 
            moneyPerDrawDialogBuilder.SetNegativeButton(GetString(Android.Resource.String.Cancel), (s, ex) => { }); 
            var moneyPerDrawDAlertDialog = moneyPerDrawDialogBuilder.Show();
            moneyPerDrawDAlertDialog.Window.ClearFlags(WindowManagerFlags.NotFocusable | WindowManagerFlags.AltFocusableIm);
        }

In each row there is an EditText that displays a number, i want this number to be able to increase/decrease it from the buttons and also manually from the EditText with the keyboard. so if edittext shows 3 and i make it from keyboard 30 then i want if i press the + button to go 31

The problem is that if I uncomment the lines of betPerDrawEditText.TextChanged The EditText's are getting wrong values from scrolling alone. How i can properly save the text entered there?

EDIT: with this code works but I'm not sure if it is the best solution

if (view != null)
{
    betPerDrawEditText.TextChanged += (object sender, Android.Text.TextChangedEventArgs e) =>
            {
                int number = 0;
                if ((int)betPerDrawEditText.Tag == position)
                {
                    bool success = int.TryParse(e.Text.ToString(), out number);
                    if (success)
                        Data[position] = number.ToString();
                }
            };
}

Solution

  • You could set the value of Data[pos] of the EditText again when you Plus or Minus.

    Add the code below into the Plus or Minus button event.

     Data[pos] = betPerDrawEditText.Text;
    

    The whole code:

                MinusOneButton.Click += (sender, e) =>
                {
                    pos = (int)MinusOneButton.Tag;
                    Data[pos] = betPerDrawEditText.Text;
                    int number = 0;
    
                    bool success = int.TryParse(Data[pos], out number);
                    if (success)
                    {
                        if (number > 0)
                            number--;
                        Data[pos] = number.ToString(CultureInfo.InvariantCulture);
                        betPerDrawEditText.Text = number.ToString(CultureInfo.InvariantCulture);
                    }
                    else
                    {
                        Data[pos] = number.ToString(CultureInfo.InvariantCulture);
                        betPerDrawEditText.Text = number.ToString(CultureInfo.InvariantCulture);
                    }
                };
    
                PlusOneButton.Click += (sender, e) =>
                {
                    pos = (int)PlusOneButton.Tag;
                    int number = 1;
                    Data[pos] = betPerDrawEditText.Text;
                    bool success = int.TryParse(Data[pos], out number);
                    if (success)
                    {
                        number++;
                        betPerDrawEditText.Text = number.ToString(CultureInfo.InvariantCulture);
                        Data[pos] = number.ToString(CultureInfo.InvariantCulture);
                    }
                    else
                    {
                        betPerDrawEditText.Text = number.ToString(CultureInfo.InvariantCulture);
                        Data[pos] = number.ToString(CultureInfo.InvariantCulture);
                    }
                };
    

    Screenshot:

    enter image description here