Chip Group OnCheckedChangeListener() not triggered
Asked Answered
W

8

22

I'm trying to make a recyclerview filter based ChipGroup & Chip

enter image description here

I'm use fragment on my app, so, the fragment who contain the RecyclerView contain a frameLayout who inflate the ChipGroup filter fragment

I'm trying to trigger a listener when the user unselect all chip inside ChipGroup (I've already put listener on chip for trigger when chip are checked by user)

I've already put some listener on chipgroup but no one are trigered

FilterFragment.java

public class FilterFragment extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
public ChipGroup chipGroup;

// TODO: Rename and change types of parameters
public View.OnClickListener chipClickListener;

private OnFragmentInteractionListener mListener;

public FilterFragment() {
    // Required empty public constructor
}


public static FilterFragment newInstance(View.OnClickListener 
param1) {
    CoachFilterFragment fragment = new CoachFilterFragment();
    Bundle args = new Bundle();

    fragment.setArguments(args);
    return fragment;
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (getArguments() != null) {

    }
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup 
container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    View view = inflater.inflate(R.layout.fragment_filter, 
container, false);
    this.chipGroup = view.findViewById(R.id.chipGroup);
    for(Skill skill : ((MainActivity)getContext()).api.skills){

        Chip chip = new Chip(getContext());
        chip.setId(skill.getId());


        chip.setText(skill.getName());
        chip.setOnClickListener(chipClickListener);
        chip.setCheckable(true);
        chipGroup.addView(chip);

    }

    chipGroup.setOnCheckedChangeListener((chipGroup, id) -> {
      Log.d("test","ok");
    });


    return view;
}

public void onButtonPressed(Uri uri) {
    if (mListener != null) {
        mListener.onFragmentInteraction(uri);
    }
}

@Override
public void onAttach(Context context) {
    super.onAttach(context);

}

@Override
public void onDetach() {
    super.onDetach();
    mListener = null;
}



public interface OnFragmentInteractionListener {
    // TODO: Update argument type and name
    void onFragmentInteraction(Uri uri);
  }
}

FilterFragment.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:context=".Fragment.FilterFragment">

<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <com.google.android.material.chip.ChipGroup
        android:id="@+id/chipGroup"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginBottom="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

       </com.google.android.material.chip.ChipGroup>
   </androidx.constraintlayout.widget.ConstraintLayout>

</FrameLayout>

Someone have any idea why any listener are not triggered by my ChipGroup?Maybe I'm missing some parameter or something?

Wounded answered 26/11, 2018 at 8:46 Comment(10)
why are you setting listener twice to same chipgroup? try loggin Log.d("test","ok"); in your first listener.Osburn
@KaranMer Just for the test, I have try to add lot of different listener and I haven't remove it for show what I have tryWounded
remove the second one and log values in first listener, remember to clean your project after you remove second listener.Osburn
@KaranMer I've remove the listeners and keep only setOnCheckedChangeListener, clean and rebuild project but no change, the listener are not triggered when I select or unselect any child inside ChipsGroupWounded
can you update your question with changed code?Osburn
@KaranMer Of course, that's done. I have try with the two same listener (because they havent the same syntax) but no one are triggeredWounded
is there any specific reason you are setting click listener to added chips, try removing onclick for added chip and test.Osburn
Yes because I handle the child click on parent Fragment for apply filter. as Nilesh Rathod explain the listener who i'm trying to use are only triggered if my chipGroup are in only selection, but i'm not looking for that, I'm trying to handle when the chipGroup have all chip unselect (for filter reset)Wounded
Did you ever figure out a nice way to handle this Benjamin? It appears things are less rosy for ChipGroups when not requiring singleSelection="true".Chewning
@Chewning I've put on click listener on every Chip (listener are declared on parent fragment), and every time listener are trigger, I use a for loop on chips group child and instantiate it as Chip, like that you can check if they are checked or not. At every loop add the status of chip in array. after check all see if array contains only false (no one check) or true, and with the position you can know who's chips checked ( Message me back if you want code example)Wounded
E
38

Your code is fine the only issue is that setOnCheckedChangeListener() only work when your ChipGroup is for singleSelection

Read this documentation of ChipGroup

setOnCheckedChangeListener()

  • Register a callback to be invoked when the checked chip changes in this group.
  • This callback is only invoked in single selection mode.

ALSO READ

Handling Checked Chips

Call setOnCheckedChangeListener(OnCheckedChangeListener) to register a callback to be invoked when the checked chip changes in this group. This callback is only invoked in single selection mode.

if you want use setOnCheckedChangeListener() of ChipGroup than you need to make app:singleSelection="true"

UPDATE

based on your below comment i have added sample code to manage to handle when ChipGroup selection

SAMPLE CODE for maintain selection in ChipGroup

Layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <com.google.android.material.chip.ChipGroup
            android:id="@+id/chipGroup"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:layout_marginLeft="8dp"
            android:layout_marginTop="8dp"
            android:layout_marginEnd="8dp"
            android:layout_marginRight="8dp"
            android:layout_marginBottom="8dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            >

        </com.google.android.material.chip.ChipGroup>
    </androidx.constraintlayout.widget.ConstraintLayout>

    <Button
        android:layout_width="match_parent"
        android:text="Get Result"
        android:id="@+id/btnShowResult"
        android:layout_gravity="bottom"
        android:layout_height="wrap_content" />
</LinearLayout>

Activity code

public class Main3Activity extends AppCompatActivity {

    public ChipGroup chipGroup;
    public Button btnShowResult;
    public ArrayList<Boolean> booleanArrayList = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main3);

        chipGroup = findViewById(R.id.chipGroup);
        btnShowResult = findViewById(R.id.btnShowResult);


        btnShowResult.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                for (int i = 0; i < booleanArrayList.size(); i++) {
                    Log.e("RESULT", i + " :" + booleanArrayList.get(i));
                }
            }
        });

        for (int i = 0; i < 5; i++) {

            Chip chip = new Chip(this);
            chip.setId(i);
            chip.setTag(i);

            booleanArrayList.add(false);
            chip.setText("Chip No : " + i);
            chip.setCheckable(true);

            chip.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(CompoundButton compoundButton, boolean b) {

                    int tag = (int) compoundButton.getTag();
                    booleanArrayList.set(tag, b);

                }
            });
            chipGroup.addView(chip);

        }

        chipGroup.invalidate();


        chipGroup.setOnCheckedChangeListener(new ChipGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(ChipGroup chipGroup, int i) {

                Chip chip = chipGroup.findViewById(i);


                if (chip != null)
                    Toast.makeText(getApplicationContext(), "Chip is " + chip.getText().toString(), Toast.LENGTH_SHORT).show();

                Log.e("OnCheckedChangeListener", "Called");
            }
        });

    }

    ChipGroup.OnCheckedChangeListener onCheckedChangeListener = new ChipGroup.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(ChipGroup chipGroup, int i) {

        }
    };

}

For more information please check below articles

Extol answered 28/11, 2018 at 11:10 Comment(4)
There is no way to handle when ChipGroup have all child unselected?Wounded
@Wounded check updated answer i have added demo code to maintain ChipGroup selection let me know if any help requiredExtol
in first, thank you for this example, but yes and no, for more explain : The listener on the chip are in the parent fragment, so when I check any chip the parent fragment apply filter on RV depending which value on selected chips, I'm trying to found the way to have the same "logic" when all chip are unselected (for triggering the parent fragment and remove the filter). I think the best way it's to do like you do, add a button to apply filter and one to reset filter because thats look don't be possible with actual chipgroup listener.Wounded
Why did you add setOnCheckedChangeListener on each Chip and ChipGroup as well?Windproof
K
9

All chips need to have the android:checkable="true" property for the trigger to exist on them.

In adittion to setting the initial check of any chip (without giving a tap), the order of execution must be first the creation of the listener with chipGroup.setOnCheckedChangeListener() and then chip.isChecked = true.

So you could handle the checkable property from the xml and isChecked dynamically.

.xml

<com.google.android.material.chip.ChipGroup
    ..
    app:singleSelection="true">
    <com.google.android.material.chip.Chip
        ..
        android:checkable="true"/>

.kt

binding.chipGroup.setOnCheckedChangeListener { chipGroup, i -> 

}
binding.firstChip.isChecked = true   //default

GL

Krone answered 5/6, 2020 at 2:32 Comment(0)
W
4

Chip Click listener will only work if the single selection was set to true in chipGroup.

app:singleSelection="true"

If you're using the style like below, then make sure it was also given to every individual chip as well.

style="@style/Widget.MaterialComponents.Chip.Choice"

like this:

<com.google.android.material.chip.ChipGroup
                android:id="@+id/chip_group"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="10dp"
                android:layout_marginEnd="10dp"
                app:singleSelection="true"
                style="@style/Widget.MaterialComponents.Chip.Choice">

            <com.google.android.material.chip.Chip
                    android:id="@+id/chip_2"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    style="@style/Widget.MaterialComponents.Chip.Choice"
                    android:text="@string/announcements"
                    android:textAppearance="@style/ChipThemeBold"/>
            <com.google.android.material.chip.Chip
                    android:id="@+id/chip_3"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    style="@style/Widget.MaterialComponents.Chip.Choice"
                    android:text="@string/fyi"
                    android:textAppearance="@style/ChipThemeBold"/>
            <com.google.android.material.chip.Chip
                    android:id="@+id/chip_4"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    style="@style/Widget.MaterialComponents.Chip.Choice"
                    android:text="@string/heartbeat"
                    android:textAppearance="@style/ChipThemeBold"  />
            <com.google.android.material.chip.Chip
                    android:id="@+id/chip_5"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    style="@style/Widget.MaterialComponents.Chip.Choice"
                    android:text="@string/pitch"
                    android:textAppearance="@style/ChipThemeBold"  />
            <com.google.android.material.chip.Chip
                    android:id="@+id/chip_6"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    style="@style/Widget.MaterialComponents.Chip.Choice"
                    android:text="@string/question"
                    android:textAppearance="@style/ChipThemeBold" 
                    android:layout_marginEnd="15dp" />

        </com.google.android.material.chip.ChipGroup>
Whipstitch answered 3/4, 2019 at 10:28 Comment(0)
E
3

It works like this way.

<com.google.android.material.chip.ChipGroup
    ...
    ...
    style="@style/Widget.MaterialComponents.Chip.Choice"
    app:singleSelection="true">

    <!-- Declare your chips or add them programmatically -->

</com.google.android.material.chip.ChipGroup>
    
    // Inflate instead of NEW instance
    val chip = layoutInflater.inflate(R.layout.chip, chipGroup, false) as Chip
    chip.text = "Text"
    chipGroup.addView(chip)
    
    // setOnCheckedChangeListener
    chipGroup.setOnCheckedChangeListener { group, checkedId ->
        // The same checked chip
        if (checkedId == -1) {
            return@setOnCheckedChangeListener
        }
    
        // TODO
    }
Expeditious answered 11/6, 2019 at 6:30 Comment(0)
S
1

You can add setOnCheckedChangeListener for all of chipgroup children. (In Kotlin)

for (index in 0 until chipGroup!!.childCount) {
        val chip: Chip = chipGroup!!.getChildAt(index) as Chip

        // Set the chip checked change listener
        chip.setOnCheckedChangeListener{view, isChecked ->
            if (isChecked){
                list.add(view.text.toString())
            }else{
                list.remove(view.text.toString())
            }

            if (list.isNotEmpty()){
                // Show the selection
                Log.d(LOGTAG,"Selected $list")
            }
        }
    }
Shillyshally answered 3/5, 2021 at 12:46 Comment(0)
D
0

i have same issue, but it's not relate to ChipGroup because i put the ChipGroup in wrong place like this:

<androidx.constraintlayout.widget.ConstraintLayout>

   <com.google.android.material.chip.ChipGroup />

   <other full screen view />
<androidx.constraintlayout.widget.ConstraintLayout/>

it makes my ChipGroup unfocusable, so just move the ChipGroup to the bottom of parent view

<androidx.constraintlayout.widget.ConstraintLayout>
   <other full screen view />

   <-- change here -->
   <com.google.android.material.chip.ChipGroup />
<androidx.constraintlayout.widget.ConstraintLayout/>

and it works, hope it helps

Displeasure answered 29/6, 2019 at 7:10 Comment(0)
B
0

I will suggest don't make use of recyclerview with chips if you want horizontal scrolling because you got HorizontalScrollView and it works quite well with chipgroup:

Based on Nilesh Rathod's Answer. To add chips dynamically you need following code:

Activity File Code:

String[] fileNameChip = getIntent().getStringArrayExtra(Constants.CHIPS_NAME_ARRAY);

        for (final String chipName : fileNameChip) {
             LayoutInflater layoutInflater = getLayoutInflater();
             Chip chip = (Chip) 
             layoutInflater.inflate(R.layout.cat_chip_group_item_choice, chipGroup, false);
             chip.setText(chipName);
             chip.setId(i); //HERE SET ID THAT WILL BE CHECKED_ID ON setOnCheckedChangeListener

             chip.setOnClickListener(new View.OnClickListener() {
                  @Override
                  public void onClick(View v) {
                     Log.d(TAG, "onClick: " + chipName );
                     }
                  });
                  chipGroup.addView(chip);
              }  
              chipGroup.setOnCheckedChangeListener(new ChipGroup.OnCheckedChangeListener() {
                   @Override
                   public void onCheckedChanged(ChipGroup group, int checkedId) {
                          Log.d(TAG, "onCheckedChanged: " + checkedId);
                       }
                    });

Activity XML FILE:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<HorizontalScrollView
    android:layout_width="match_parent"
    android:scrollbars="none"
    android:layout_height="wrap_content">

    <com.google.android.material.chip.ChipGroup
        android:id="@+id/chip_group_code_files"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:singleLine="true"
        app:singleSelection="true" />
</HorizontalScrollView>

cat_chip_group_item_choice.xml:(Specify chip type:Choice,filter,Action,Normal)

<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.chip.Chip
    xmlns:android="http://schemas.android.com/apk/res/android"
    style="@style/Widget.MaterialComponents.Chip.Choice"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>
Bedraggled answered 20/7, 2019 at 3:10 Comment(0)
C
0

Found this as the easiest method to do so with multiple selection chip group:

    chipGroup.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
            @Override
            public void onLayoutChange(View view, int i, int i1, int i2, int i3, int i4, int i5, int i6, int i7) {
                List<Integer> ids = chipGroup.getCheckedChipIds();
                if (ids.contains(R.id.chip1)) {
                // do your stuff 
             }
           }
        });
Caramelize answered 7/10, 2021 at 12:39 Comment(1)
this is not triggered if all selections are cancelled.Encampment

© 2022 - 2024 — McMap. All rights reserved.