Search code examples
androidlistviewandroid-fragmentsshow-hidelistadapter

Hide/Show elements in a ListView item after a click


I have a Fragment which contains a ListView. The ListView items contain TextView and Button elements. When I press a button in the listview I would like to update the row in which I clicked the button to hide the button and display a TextView (the text inside the TextView also needs to be updated once every second).

Is this possible and how?

MyFragment
public class MyFragment extends Fragment implements ClickedListener {
    private static final String TAG = MyFragment.class.getSimpleName();

    private MyListAdapter myListAdapter;

    public MyFragment() {
        // Required empty public constructor
        Log.e(TAG, "MyFragmment");
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        Log.e(TAG, "onCreateView");
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.fragment_mine, container, false);

        ListView myListView = view.findViewById(R.id.listView);

        myListAdapter = new MyListAdapter(getActivity(), MyFragment.this);
        myListView.setAdapter(myListAdapter);

        getList();

        return view;
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (isVisibleToUser && isResumed()) {
            getList();
        }
    }

    private void getList() { //This part works no need to discuss this.
        List<Items> items = myItemsContent.getItems();
                    myListAdapter.setItems(items);
    }

    @Override
    public void buttonClicked(Item item) {
        doSomeStuff();
        myListAdapter.displayTextView();
    }
}
MyListAdapter
public class MyListAdapter extends ArrayAdapter<Item> {
    private static final String TAG = MyListAdapter.class.getSimpleName();

    private Button myButton;
    private TextView status;

    private final Context context;

    public interface ClickedListener {
        void buttonClicked(Item item);
    }

    private final ClickedListener clickedListener;

    public MyListAdapter(@NonNull Context context, ClickedListener clickedListener) {
        super(context, R.layout.list_item);

        this.context = context;
        this.clickedListener = clickedListener;
    }

    public void setItems(List<Items> items) {
        super.addAll(items);
    }

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

        if (row == null) {
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            row = inflater.inflate(R.layout.list_item, parent, false);
        }

        TextView itemName = row.findViewById(R.id.list_item_name);
        myButton = row.findViewById(R.id.myButton);
        status = row.findViewById(R.id.status);

        Item item = getItem(position);
        if (item != null) {
            itemName.setText(item.getName());

            myButton.setOnClickListener(v -> clickedListener.buttonClicked(item));
        }

        return row;
    }

    public void displayTextView() {
        myButton.setVisibility(View.INVISIBLE);
        status.setVisibility(View.VISIBLE);
    }
}

Solution

  • I will do it more reliable way. I think you know the working of the Listview and adapter.

    So You have list of Items that you are passing to your adapter. I will change my Item class in following way. Please add these two fields in the Item class which I think is the model

    public boolean isButtonVisible = true;
    public boolean isTextViewVisible = false;
    

    Go a head create there header and setter.Or change any default value

    now in your getView method of Adapter do this in the end //Or just copy replace

        @NonNull
    @Override
    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
        View row = convertView;
    
        if (row == null) {
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            row = inflater.inflate(R.layout.list_item, parent, false);
        }
    
        TextView itemName = row.findViewById(R.id.list_item_name);
        myButton = row.findViewById(R.id.myButton);
        status = row.findViewById(R.id.status);
    
        Item item = getItem(position);
        if (item != null) {
            itemName.setText(item.getName());
    
            myButton.setOnClickListener(v -> clickedListener.buttonClicked(item));
    
           if(item.isButtonVisible){
            myButton.setVisiblity(View.VISIBLE);
           }else{
           myButton.setVisibilty(View.GONE)        
           }
    
           if(item.isTextViewVisible){
            myTextView.setVisiblity(View.VISIBLE);
           }else{
           myTextView.setVisibilty(View.GONE)        
           }
    
        }
    
        return row;
        }
    

    Finally do this in your fragment inside following method

     @Override
       public void buttonClicked(Item item) {
        doSomeStuff();
        item.setButtonVisibility (Whatever you want to do true or false)
        ite.setTextViewVisible  (Whatever you want to do true or false)
        myListAdapter.notifyDataSetChanged(); 
        }
    

    Important: You need to call myListAdapter.notifyDataSetChanged() in the end. you do not need to call myListAdapter.displayTextView(); as this will not work