Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FlexBoxLayoutManager with RecyclerView causes multiple items to refresh on calling notifyItemChanged #631

Open
mdalihusain opened this issue Nov 27, 2023 · 0 comments

Comments

@mdalihusain
Copy link

mdalihusain commented Nov 27, 2023

  • [Y] I have searched existing issues and confirmed this is not a duplicate

Issues and steps to reproduce

  1. Enable data binding/view binding in project.
  2. Create a layout for RecyclerView Item, add a variable in it which contains a property 'selected', the background of this layout is dependent on whether the item is selected or not.
  3. Use FlexBoxLayout Manager for this recycler view.
  4. Create an Adapter for this recycler view, which changes the selected state of the list item upon clicking on it and then calls the notifyItemChanged method.
  5. The background of the item is changed but other items in the list seem to be refreshed or redrawn into the UI, the UI sort of flickers.

Screen Recording of the issue
https://github.com/google/flexbox-layout/assets/55429814/87c13dc1-37a3-4da9-8e5b-026750b7b0af

Expected behavior

Only the background of the item tapped should be changed and nothing else should be redrawn as I tried with LinearLayoutManager and I get this expected behaviour.

Version of the flexbox library

3.0.0

Link to code

FlexboxItemsAdapter.java

public class FlexboxItemsAdapter extends RecyclerView.Adapter<FlexboxItemsAdapter.ViewHolder> {

    private ArrayList<FlexboxItemModel> localDataSet;
    private boolean multipleSelectionAllowed;
    private int selectedItemPosition = 0;


    public FlexboxItemsAdapter(boolean multipleSelectionAllowed, ArrayList<FlexboxItemModel> dataSet) {
        localDataSet = dataSet;
        this.multipleSelectionAllowed = multipleSelectionAllowed;

    }

    // Create new views (invoked by the layout manager)
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
        // Create a new view, which defines the UI of the list item
        LayoutFlexboxItemBinding view = DataBindingUtil.inflate(
                LayoutInflater.from(viewGroup.getContext()),
                R.layout.layout_flexbox_item, viewGroup, false);
        return new ViewHolder(view);
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {

        public LayoutFlexboxItemBinding layoutFlexboxItemBinding;

        public ViewHolder(LayoutFlexboxItemBinding layoutFlexboxItemBinding) {
            super(layoutFlexboxItemBinding.getRoot());
            this.layoutFlexboxItemBinding = layoutFlexboxItemBinding;
        }

        public void bind(FlexboxItemModel model) {
            layoutFlexboxItemBinding.setItem(model);
        }

    }

    // Replace the contents of a view (invoked by the layout manager)
    @Override
    public void onBindViewHolder(ViewHolder viewHolder, @SuppressLint("RecyclerView") final int position) {
        // Get element from your dataset at this position and replace the
        // contents of the view with that element
        final FlexboxItemModel model = localDataSet.get(position);
        viewHolder.bind(model);
        if (!multipleSelectionAllowed && model.isSelected()) {
            selectedItemPosition = position;
        }
        viewHolder.layoutFlexboxItemBinding.lfiText.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                boolean state = model.isSelected();
                if(!multipleSelectionAllowed) {
                    localDataSet.get(selectedItemPosition).setSelected(false);
                    notifyItemChanged(selectedItemPosition);
                }
                model.setSelected(!state);
                notifyItemChanged(position);
            }
        });
    }


    @Override
    public int getItemCount() {
        return localDataSet.size();
    }

    @Override
    public long getItemId(int position) {
        return Long.parseLong(localDataSet.get(position).getId());
    }
    
}

FlexBoxItemModel.java

public class FlexboxItemModel {


    private String id;
    private String text;
    private boolean selected;

    public FlexboxItemModel(String id, String text, boolean selected) {
        this.id = id;
        this.text = text;
        this.selected = selected;
    }

layout_flexbox_item.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="https://schemas.android.com/apk/res/android"
    >
    <data>
        <variable
            name="item"
            type="FlexboxItemModel" />
    </data>
<TextView
    android:layout_marginRight="10dp"
    android:layout_marginBottom="10dp"
    android:id="@+id/lfi_text"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:paddingVertical="7dp"
    android:paddingHorizontal="13dp"
    android:text="@{item.text}"
    style="@style/reg_form_labels"
    android:textColor="@{item.selected?@color/white:@color/color_purple}"
    android:background="@{item.selected? @drawable/border_gradient_28dp_1dp_filled : @drawable/border_grey_28dp_1dp}"
    />
</layout>

Initialization of recycler view in fragment

RecyclerView recyclerView = binding.fseExamsRecyclerView;
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false); // no flickering issue if I use linearlayoutmanager
FlexboxLayoutManager layoutManager = new FlexboxLayoutManager(getContext());
layoutManager.setFlexDirection(FlexDirection.ROW);
layoutManager.setJustifyContent(JustifyContent.FLEX_START);
layoutManager.setFlexWrap(FlexWrap.WRAP);
recyclerView.setLayoutManager(layoutManager);
mViewModel.getExams().observe(getViewLifecycleOwner(), flexboxItemModels-> {
    FlexboxItemsAdapter adapter = new FlexboxItemsAdapter(true, flexboxItemModels);
    adapter.setHasStableIds(true);  // same issue whether I use this or not
    recyclerView.setAdapter(adapter);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant