Home > OS >  When clicking on Button on ListView item, the state of the last item changes
When clicking on Button on ListView item, the state of the last item changes

Time:06-07

Hey so the goal is that when the button cancel of a list item is clicked, the state of the item must be shown as "Canceled" and the button goes black. However, when pressing on the button the button does go black but the list item doesn't change state. Instead, the last button of the view list changes state. Can you help me out?

Adapter class:

package com.example.myappfinal.Adapter;

import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.graphics.drawable.DrawableCompat;

import com.example.myappfinal.Logic.Appointment;
import com.example.myappfinal.R;

import java.util.ArrayList;


public class AppointmentListAdapter extends ArrayAdapter<Appointment> {

    private String state,date,time;
    private TextView stateT,dateT,timeT;
    private Context mContext;
    int mRecource;


    public AppointmentListAdapter(@NonNull Context context, int resource, @NonNull ArrayList<Appointment> objects) {
        super(context, resource, objects);
        mContext=context;
        mRecource=resource;
    }

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


        state=getItem(position).getState();
        String service=getItem(position).getService().getName();
        date = getItem(position).getDate();
        time = getItem(position).getStartTime();

        LayoutInflater inflater = LayoutInflater.from(mContext);
        convertView = inflater.inflate(mRecource,parent,false);

        stateT = (TextView) convertView.findViewById(R.id.state);
        TextView serviceT = (TextView) convertView.findViewById(R.id.service);
        TextView dateT = (TextView) convertView.findViewById(R.id.date);
        TextView timeT = (TextView) convertView.findViewById(R.id.time);


        stateT.setText(state);
        serviceT.setText(service);
        dateT.setText(date);
        timeT.setText(time);

        Button button =(Button)convertView.findViewById(R.id.button);
        if(state.equals("Canceled")){
            Drawable buttonDrawable = button.getBackground();
            buttonDrawable = DrawableCompat.wrap(buttonDrawable);
            DrawableCompat.setTint(buttonDrawable, Color.BLACK);
            button.setBackground(buttonDrawable);
        }

            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    //do something
                    if(state.equals("Active")) {
                        getItem(position).cancel();
                        state = getItem(position).getState();
                        stateT.setText(state);

                        Drawable buttonDrawable = button.getBackground();
                        buttonDrawable = DrawableCompat.wrap(buttonDrawable);
                        DrawableCompat.setTint(buttonDrawable, Color.BLACK);
                        button.setBackground(buttonDrawable);
                    }

                }

            });

        return convertView;

    }

CodePudding user response:

The problem is that stateT is a class member in the adapter that you override for each row's getView call, so after the list is populated it always refers to the last row. You should not save the views (e.g. stateT) as class members. Every call to getView will override the prior values held there.

For your case you should probably do something like this (hard to say for sure without the full code)

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

    // Don't re-inflate unless necessary
    if( convertView == null ) {
        LayoutInflater inflater = LayoutInflater.from(mContext);
        convertView = inflater.inflate(mRecource,parent,false);
    }

    // Get the state of the current row
    Appointment appt = getItem(position);
    String state = appt.getState();
    String service = appt.getService().getName();
    String date = appt.getDate();
    String time = appt.getStartTime();
        
    // These should NOT be class members
    TextView stateT = convertView.findViewById(R.id.state);
    TextView serviceT = convertView.findViewById(R.id.service);
    TextView dateT = convertView.findViewById(R.id.date);
    TextView timeT = convertView.findViewById(R.id.time);

    // Set the row's values
    stateT.setText(state);
    serviceT.setText(service);
    dateT.setText(date);
    timeT.setText(time);

    Button button = convertView.findViewById(R.id.button);
    
    if(state.equals("Canceled")){
        Drawable buttonDrawable = button.getBackground();
        buttonDrawable = DrawableCompat.wrap(buttonDrawable);
        DrawableCompat.setTint(buttonDrawable, Color.BLACK);
        button.setBackground(buttonDrawable);
 
        // may also want to disable the button
        button.setEnabled(false);
    }
    else {
        button.setEnabled(true);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // get the current row state - since it may have been
                // updated since the listener was created
                String rowState = appt.getState();
                
                if(rowState.equals("Active")) {
                    appt.cancel();
                    String newState = appt.getState();

                    // stateT here refers to just this row's TextView now
                    stateT.setText(newState);

                    Drawable buttonDrawable = button.getBackground();
                    buttonDrawable = DrawableCompat.wrap(buttonDrawable);
                    DrawableCompat.setTint(buttonDrawable, Color.BLACK);
                    button.setBackground(buttonDrawable);

                    // may also want to disable the button
                    button.setEnabled(false);
                }
            }
        });
    }

    return convertView;
}

  • Related