0

I am trying to repeat an action while a button is pressed.

I have already searched for some solutions and all are useless. My assumption is that this may happen because my buttons are inside a ListView item.

What I want to approach the following application:

enter image description here

Where I can increment (+1) or decrement(-1) the value of each EditText (Count) by single time pressing, or holding pressed the button for a while.

My adapter code:

public class ItemAdapter extends ArrayAdapter<SizeCount> {

    private Collection<SizeCount> list;
    private static final String LOG_TAG = "MemoListAdapter";
    EditText tbCount;
    TextView tvSize;
    Button btAdd, btSubstract;    

    public ItemAdapter (Context context,List<SizeCount> list){
        super(context,0,list);
        this.list = list;
    }

    public Collection<SizeCount> getList() {
        return list;
    }


    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        try {
            View v = convertView;
            if(v == null){
                v = LayoutInflater.from(getContext()).inflate(
                        R.layout.entry_size_count,parent,false
                );
            }

            final SizeCount item = getItem(position);

            tvSize = (TextView) v.findViewById(R.id.tvSize);
            tvSize.setFocusable(false);
            tbCount= (EditText) v.findViewById(R.id.tbCount);

            tvSize .setText(item.getArticles().getSize());
            tbCount.setText(item.getCount()+"");

            btAdd= v.findViewById(R.id.btAdd);

            btAdd.setOnTouchListener(new View.OnTouchListener() {

                private Handler mHandler;

                @Override public boolean onTouch(View v, MotionEvent event) {
                    switch(event.getAction()) {
                        case MotionEvent.ACTION_DOWN:
                            if (mHandler != null) return true;
                            mHandler = new Handler();
                            mHandler.postDelayed(mAction, 500);
                            break;
                        case MotionEvent.ACTION_UP:
                            if (mHandler == null) return true;
                            mHandler.removeCallbacks(mAction);
                            mHandler = null;
                            break;
                    }
                    return false;
                }

                Runnable mAction = new Runnable() {
                    @Override public void run() {
                        float currentCount = item.getCount();
                        float nextCount = currentCount + 1;
                        item.setCount(nextCount);
                        item.setModified(true);
                        notifyDataSetChanged();
                        mHandler.postDelayed(this, 500);
                    }
                };

            });

            return v;
        } catch (Exception ex) {
            Log.e(LOG_TAG, "error", ex);
            return null;
        }
    }
}

And the behaviour I get:

  • When I click the (+) button a single time: Nothing changes.
  • When I hold pressed the (+) button: It starts increasing and never stops. Even when I release it.
Oscar Martinez
  • 621
  • 1
  • 8
  • 18

1 Answers1

1

When you press the button and use the notifyDataSetChanged() method it will cause the MotionEvent.ACTION_UP fail.

Please use the viewHolder.tbCount.setText() method to replace notifyDataSetChanged() and don't forget to update SizeCount(item) object value.

public class ItemAdapter extends ArrayAdapter<SizeCount> {
    private static final String LOG_TAG = "MemoListAdapter";

    private Collection<SizeCount> list;

    public ItemAdapter(Context context, List<SizeCount> list) {
        super(context, 0, list);
        this.list = list;
    }

    public Collection<SizeCount> getList() {
        return list;
    }

    @SuppressLint("ClickableViewAccessibility")
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        final SizeCount item = getItem(position);
        if (item == null) return convertView;

        final ViewHolder viewHolder;
        if (convertView == null) {
            convertView = LayoutInflater.from(getContext()).inflate(R.layout.entry_size_count, parent, false);
            viewHolder = new ViewHolder();
            viewHolder.tbCount = (EditText) convertView.findViewById(R.id.tbCount);
            viewHolder.tvSize = (TextView) convertView.findViewById(R.id.tvSize);
            viewHolder.btAdd = convertView.findViewById(R.id.btAdd);
            viewHolder.btAdd.setOnTouchListener(new View.OnTouchListener() {
                private Handler mHandler = new Handler();

                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    switch (event.getAction()) {
                        case MotionEvent.ACTION_DOWN:
                            mHandler.postDelayed(mAction, 500);
                            break;
                        case MotionEvent.ACTION_UP:
                            mHandler.removeCallbacks(mAction);
                            break;
                    }
                    return false;
                }

                Runnable mAction = new Runnable() {
                    @Override
                    public void run() {
                        float currentCount = item.getCount();
                        float nextCount = currentCount + 1;
                        item.setModified(true);

                        // update SizeCount value
                        item.setCount(nextCount);

                        // set value to tbCount
                        viewHolder.tbCount.setText(String.valueOf(item.getCount()));

                        // this will cause the MotionEvent.ACTION_UP fail
                        // notifyDataSetChanged();

                        mHandler.postDelayed(this, 500);
                    }
                };

            });

            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }

        viewHolder.tvSize.setFocusable(false);
        viewHolder.tvSize.setText(item.getArticles().getSize());
        viewHolder.tbCount.setText(item.getCount() + "");
        return convertView;
    }

    private class ViewHolder {
        TextView tvSize;

        TextView tbCount;

        Button btAdd;
    }
}

I think it is not good to call notifyDataSetChanged() method for this case. It is wrong to refresh the whole View just to change value on single item.

Changemyminds
  • 1,147
  • 9
  • 25
  • No changes, the incrementing becomes unstoppable – Oscar Martinez Jan 11 '19 at 10:06
  • @OscarMartinez I fixed the incrementing becomes unstoppable problem. You can try it. It work for me. – Changemyminds Jan 11 '19 at 14:47
  • Thanks. Is there a way to change the background color of the Count `EditText` whenever it has changed its value? I have tried but many Views change its background color because of recycling – Oscar Martinez Jan 12 '19 at 14:48
  • You can use viewHolder.tbCount.addTextChangedListener() method and implement TextWatcher interface. [An Example](https://stackoverflow.com/questions/30371988/how-to-change-background-of-textview-from-edittext-text-change) – Changemyminds Jan 13 '19 at 04:28
  • Thanks but they all change the background color from begining even when I have not pressed any button. Is there an alternative to `ListView`? it always behaves very odd – Oscar Martinez Jan 13 '19 at 11:19
  • Use this code or you can use Recyclerview to replace ListView. @Override public void onTextChanged(CharSequence s, int start, int before, int count) { if (s.toString().equals("0.0")) { // set default color viewHolder.tbCount.setBackgroundColor(Color.RED); } else { // changed color viewHolder.tbCount.setBackgroundColor(Color.BLUE); } } – Changemyminds Jan 13 '19 at 13:16