Is there an option to make the MaterialButtonToggleGroup have a required selected button when using app:singleSelection="true"?
When clicking to a different button works fine (all other buttons are deselected), but when you click the same (already selected) button it deselects it itself and I want to remain selected.
My example:
<com.google.android.material.button.MaterialButtonToggleGroup
android:layout_width="wrap"
android:layout_height="wrap_content"
app:singleSelection="true">
<com.google.android.material.button.MaterialButton
android:id="#+id/filterA"
style="#style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="A"/>
<com.google.android.material.button.MaterialButton
android:id="#+id/filterB"
style="#style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="B"/>
<com.google.android.material.button.MaterialButton
android:id="#+id/filterC"
style="#style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="C"/>
</com.google.android.material.button.MaterialButtonToggleGroup>
You can define it in the layout using the app:selectionRequired attribute:
<com.google.android.material.button.MaterialButtonToggleGroup
app:selectionRequired="true"
app:checkedButton="#id/..."
app:singleSelection="true">
You can also use the method setSelectionRequired:
buttonGroup.setSelectionRequired(true);
Note: This requires a minimum of version 1.2.0-alpha03
I got this working with the following:
toggle_group.addOnButtonCheckedListener { group, checkedId, isChecked ->
if (group.checkedButtonId == -1) group.check(checkedId)
}
If you have singleSelection enabled, the conditional will only evaluate to true when the user has clicked on the button which is already checked, making it so no button is checked. When this happens, we just need to check the button they unchecked.
I also came across this issue and I found this is working with the app:singleSelection="true"
String selectedValue = "Male";
genderBtnToggle.addOnButtonCheckedListener(new MaterialButtonToggleGroup.OnButtonCheckedListener() {
#Override
public void onButtonChecked(MaterialButtonToggleGroup group, int checkedId, boolean isChecked) {
MaterialButton btn = genderBtnToggle.findViewById(checkedId);
if (!isChecked && btn.getText().toString().equals(selectedValue)) {
genderBtnToggle.check(checkedId);
}
if (isChecked) {
selectedValue = btn.getText().toString();
}
}
});
I also came across this issue and will be waiting for a permanent fix from google. In the meantime, I did the following to make sure that at least one button is checked.
final MaterialButtonToggleGroup tGroup = view.findViewById(R.id.toggleGroup);
final MaterialButton breast = tGroup.findViewById(R.id.breast);
final MaterialButton bottle = tGroup.findViewById(R.id.bottle);
final MaterialButton solids = tGroup.findViewById(R.id.solids);
View.OnClickListener onClickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
tGroup.check(v.getId());
}
};
breast.setOnClickListener(onClickListener);
bottle.setOnClickListener(onClickListener);
solids.setOnClickListener(onClickListener);
Hope this helps.
Related
I want to check if my Checkboxes are checked to change some values.
I got the answer for radioButton which is inserted to a RadioGroup and we can simply use :
radioGroup.setOnCheckedChangeListener(new new OnCheckedChangeListener(){
#Override
public void onCheckedChanged(RadioGroup group, int checkedId)
{ . . . }
}
i'm looking for something like this ,However this approach is differ from Checkboxes because there is no widget like CheckboxGroup to use setOnCheckedChangeListener On it .
For example i have checkbox1 and checkbox2. how can i get as long as these two checkboxes are checked to changing some value like :
if(checkbox1==isChecked && checkbox2==isChecked)
//Do sth ...
else
//Do sth Different
EDIT : Maybe i could not explain my problem perfectly , this is just like question below but for Checkboxes
How to check state Changing of Radio Button android?
As commented you can use checkboxRef.isChecked()
if(checkbox1.isChecked() && checkbox2.isChecked()){
}
else{
}
but I want to use them in a different function , may globally access
to this checkboxes
You can use sharedPreference and with a utility class to store the state of your checkbox.
SharedPreferences helper class
This is way to check which checkbox is checked..
if(checkbox1.isChecked())
{
//means checkbox1 is checked...
}else
{
//means checkbox2 is checked...
}
If you want to set an event listener to detect when a change is made you can use:
checkbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {
//Code here
} } );
On the other hand if you want to check if it is checked you can use:
if(checkbox.isChecked()){
//Code here
}
Finally i got the answer , first of all I need to set onclick attribute as the same for all of the checkboxes , and check my Needed for approach desire output in the onClick Function,
Xml:
<CheckBox
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="func"
android:text="1"
android:id="#+id/c1"/>
<CheckBox
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="2"
android:onClick="func"
android:id="#+id/c2"/>
<CheckBox
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="3"
android:onClick="func"
android:id="#+id/c3"/>
JavaCode:
public void func(View view) {
CheckBox checkBox1 = (CheckBox)findViewById(R.id.c1);
CheckBox checkBox2 = (CheckBox)findViewById(R.id.c2);
CheckBox checkBox3 = (CheckBox)findViewById(R.id.c3);
if(checkBox1.isChecked() && checkBox2.isChecked() && (!checkBox3.isChecked()))
{
Next = true;
}
else
{
Next = false;
}
}
checkBox1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(checkBox1.isChecked() && checkBox2.isChecked()){
}
}
});
I am now trying to use android data-binding in my project, and encounter this kind of issue, for example: I have 3 checkbox as a checkbox group, if first checkbox is checked, then a variable type is 1. the second makes type to 2, the 3rd makes type to 3. so I implement the code in this way.
// layout.xml
<android.support.v7.widget.AppCompatCheckBox
android:layout_width="50dp"
android:layout_height="50dp"
android:checked="#{userInfoViewModel.type == 1}"
android:onCheckedChanged="#{(compoundButton, checked) -> userInfoViewModel.onTypeChecked(checked, 1)}"
/>
<android.support.v7.widget.AppCompatCheckBox
android:layout_width="50dp"
android:layout_height="55dp"
android:checked="#{userInfoViewModel.type == 2}"
android:onCheckedChanged="#{(compoundButton, checked) -> userInfoViewModel.onTypeChecked(checked, 2)}"
/>
<android.support.v7.widget.AppCompatCheckBox
android:layout_width="50dp"
android:layout_height="55dp"
android:checked="#{userInfoViewModel.type == 3}"
android:onCheckedChanged="#{(compoundButton, checked) -> userInfoViewModel.onTypeChecked(checked, 3)}"
/>
// viewModel
public void onTypeChecked(boolean checked, int i) {
if (checked) {
// if it is a check. set the type
type.set(i);
} else {
// if it is a uncheck. set type to unknown
type.set(0);
}
}
Now the problem is that, if I have checked 1st checkbox, then I check the 2nd. type should be set to 2, and the UI should update correctly. But the reality is that uncheck event also occur on the 1st checkbox, after type is set to 2, then type.set(0) is triggered, so no checkbox is checked.
In fact, this issue is same to onCheckedChanged called automatically. What I need is a solution for data-binding.
In non-data-binding project, I think the best solution is using setCheckedSilent(answer by #Emanuel Andrada).
public void setCheckedSilent(boolean checked) {
super.setOnCheckedChangeListener(null);
super.setChecked(checked);
super.setOnCheckedChangeListener(listener);
}
But in data-binding, I can not do this. So is there any expert can help me out?
According to #Arpan Sharma's answer, listen to onClick instead of onCheckedChanged. This solution works currently, But I am worried about the value of checked, is it always right?
public void onTypeChecked(View view, int i) {
Boolean checked = ((CheckBox) view).isChecked();
if (checked) {
type.set(i);
} else {
type.set(0);
}
}
Expose an ObservableBoolean from the ViewModel, then use two-way databinding over that boolean.
Then you can use the ObservableBoolean's values to decide what you want to do, rather than encode it in the XML.
android:checked="#={vm.checkedValue}"
This is very simple with data binding
In xml checkbox component
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onCheckedChanged="#{(compoundButton, checked) ->
changeKeyboardVM.onCheckedChange(compoundButton, checked)}" />
In ViewModel or Activity
public void onCheckedChange(CompoundButton button, boolean check) {
Log.d("Z1D1", "onCheckedChange: " + check);
}
now Boolean check true on checked
and false on unchecked
I faced the same problem and i used onCLick listener instead onCHeck
listener .That way the listener wont change the check state when it is set programatically.
In your problem you should try setting different check change listeners to your check boxes.
I came across this question for first time and I think it's better to be implemented using binding adapter.
Here is the code for binding adapter
interface OnUserCheckedChangeListener {
fun onUserCheckChange(view:CompoundButton, isChecked:Boolean)
}
#BindingAdapter("onUserCheckedChange")
fun setUserCheckedChangeListener(view:CompoundButton, listener: OnUserCheckedChangeListener?){
if(listener == null){
view.setOnClickListener(null)
}else{
view.setOnClickListener {
listener.onUserCheckChange(view, view.isChecked)
}
}
}
And we can use it on any compound button
<CheckBox
android:id="#+id/finish_check"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
android:checked="#{your_condition}"
onUserCheckedChange="#{(view, checked) -> vm.onItemChecked(todo, checked)}"
/>
Using onClick instead of onCheckedChanged to prevent 2-ways binding.
From item_order_view.xml:
<data>
<variable
name="viewModel"
type="com.package.name.OrderItemViewModel" />
</data>
<CheckBox
android:id="#+id/cb_selected"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="8dp"
android:buttonTint="#color/white"
android:checked="#{viewModel.isSelect}"
android:onClick="#{() -> viewModel.onClickedCheckBox()}"
android:textColor="#color/white" />
From OrderItemViewModel.java
public class OrderItemViewModel {
public final ObservableField<Boolean> isSelect;
public final OrderItemViewModelListener mListener;
private final Order mOrder;
public OrderItemViewModel(Order order, OrderItemViewModelListener listener) {
this.mListener = listener;
this.mOrder = order;
isSelect = new ObservableField<>(mOrder != null ? mOrder.isSelect() : false);
}
/**
* Using onClick instead of onCheckedChanged
* to prevent 2-ways binding issue.
*/
public void onClickedCheckBox() {
mListener.onCheckChanged();
}
public interface OrderItemViewModelListener {
void onCheckChanged();
}
}
See https://stackoverflow.com/a/52606437/2914140:
Write inside OnCheckedChangeListener:
if (button.isPressed()) {
// A user pressed Switch.
}
Maybe some answers from How to use data binding for Switch onCheckedChageListener event? may help, for instance, defining android:onCheckedChanged listener, but I didnt test.
I am completely new to android development, my problem is that i had two editText boxes in my layout and self created number button 0-9,enterButton and Clr button. now my problem is to get two inputs from user via these number button in two diffrent editText boxes. Help me out!!!
Here is the code`#Override
public void onClick(View view) {
// button clicked
if (view.getId() == R.id.buttonEnter) {
// enter button
}
} else if (view.getId() == R.id.buttonClr) {
// clear button
} else {
// number button
response.setVisibility(View.INVISIBLE);
// here i want to take two inputs by clicking two buttons and display them
int entered1 = Integer.parseInt(view.getTag().toString());
editTxt1.setText(String.valueOf(entered1));
int entered2 = Integer.parseInt(view.getTag().toString());
editTxt2.setText(String.valueOf(entered2));
}
}`
<Button
android:id="#+id/button1"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="1dp"
android:layout_weight="1"
android:gravity="center"
android:padding="5dp"
android:tag="1"
android:text="1"
android:textSize="30sp"
android:textStyle="bold" />`
Ok i get what you are trying to do, but why are you retrieving theTag, which appears to be a String from the view, then parse it to int, just to make it a string again?
besides that, id like to see the Button initialization, so i can understand what exactly the tag is.
In my Android application, I want to create a fragment that works like a keypad. I have one function which handle onClick for all 9 keys. I want to know is there anyway to write just one function to handle onLongClick for all these 9 keys too.
here is layout xml :
<Button
android:id="#id/testButton"
android:layout_width="70dp"
android:layout_height="55dp"
android:layout_margin="2dp"
android:background="#drawable/keypad_round_button"
android:text="1"
android:textColor="#color/black_1"
android:onClick="keypadSetNote"
android:longClickable="true"/>
<Button
android:id="#id/testButton"
android:layout_width="70dp"
android:layout_height="55dp"
android:layout_margin="2dp"
android:background="#drawable/keypad_round_button"
android:text="2"
android:longClickable="true"
android:textColor="#color/black_1"
android:onClick="keypadSetNote"
/>
Here is OnlongClick listener :
Button button = (Button) findViewById(R.id.testButton);
button.setOnLongClickListener(new View.OnLongClickListener() {
public boolean onLongClick(View v) {
Button clickedButton = (Button) v;
String buttonText = clickedButton.getText().toString();
Log.v(TAG, "button long pressed --> " + buttonText);
return true;
}
});
I gave all keys same ID to handle all onLongClick actions in one function, but it just work for the first key. Is there anyway to define something like group button in Android ??? Or I have to write OnLongClick listener for all of them separately ???
Just create a named function instead of an anonymous one:
View.OnLongClickListener listener = new View.OnLongClickListener() {
public boolean onLongClick(View v) {
Button clickedButton = (Button) v;
String buttonText = clickedButton.getText().toString();
Log.v(TAG, "button long pressed --> " + buttonText);
return true;
}
};
button1.setOnLongClickListener(listener);
button2.setOnLongClickListener(listener);
button3.setOnLongClickListener(listener);
And, altough you don't asked it, we must warn you: As #AndyRes says, your buttons must have differents ids. Having the same ID doesn't mean that getting the button by id will return all buttons, only will return the first button with that ID, that's because it only works with the first button.
Buttons should have different ids:
<Button
android:id="#id/testButton1"
//... />
<Button
android:id="#id/testButton2"
//... />
<Button
android:id="#id/testButton3"
//... />
Now, to set the listener for all, a solution would be to get the id of all buttons in an array, and then use a "for" loop to set the listener for each.
Like this:
// Store the id of buttons in an array
int[] ids={R.id.testButton1, R.id.testButton2,R.id.testButton3};
// loop through the array, find the button with respective id and set the listener
for(int i=0; i<ids.length; i++){
Button button = (Button) findViewById(ids[i]);
button.setOnLongClickListener(longClickListener);
}
View.OnLongClickListener longClickListener = new View.OnLongClickListener() {
public boolean onLongClick(View v) {
// .....
return true;
}
};
if your buttons are in the LinearLayout, in the RelativeLayour or in the other. And you have very many buttons.
View.OnLongClickListener listener = new View.OnLongClickListener() {
public boolean onLongClick(View v) {
Log.d("ID", ""+v.getId());
switch (v.getId())
{
case R.id.button1:
//do something for button1
break;
case R.id.button2:
//do something for button2
break;
...
}
return true;
}
};
LinearLayout layout=(LinearLayout)findViewById(R.id.IdOfLinearLayout);
for(int i=0;i<layout.getChildCount();i++){
layout.getChildAt(i).setOnLongClickListener(listener);
}
xml file for example...
<LinearLayout
android:id=#+id/IdOfLinearLayout"....>
<Button
android:id="#+id/button1"
android:layout_width=...
android:layout_height=...
.../>
<Button
android:id="#+id/button2"
... />
....
<Button
android:id="#+id/buttonN"
.../>
</LinearLayout>
In the app I've been working on, I would like to have a multiple-state (in my case, three) toggle button, instead of the two that ToggleButton provides. I've tried to start my own that extends Button, following the CompoundButton source, but quite honestly reading over its source got a bit overwhelming.
Is there a way to do a three-state toggle button using just a selector xml or something, or perhaps another method I haven't thought of? I'm rather at a loss of how to do this.
I implemented a multi-state toggle button, the source code is here
This is how it looks:
And it's quite easy to use it:
<org.honorato.multistatetogglebutton.MultiStateToggleButton
android:id="#+id/mstb_multi_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dip"
mstb:values="#array/planets_array" />
In your activity:
MultiStateToggleButton button2 = (MultiStateToggleButton) this.findViewById(R.id.mstb_multi_id);
button2.setOnValueChangedListener(new ToggleButton.OnValueChangedListener() {
#Override
public void onValueChanged(int value) {
Log.d(TAG, "Value: " + value);
}
});
You can create a custom ImageButton to achieve this, you need 3 different images in this case.
You can also add more states if you want.
public class FlashButton extends ImageButton {
public enum FlashEnum {
AUTOMATIC, ON, OFF
}
public interface FlashListener {
void onAutomatic();
void onOn();
void onOff();
}
private FlashEnum mState;
private FlashListener mFlashListener;
public FlashButton(Context context, AttributeSet attrs) {
super(context, attrs);
//Sets initial state
setState(FlashEnum.AUTOMATIC);
}
#Override
public boolean performClick() {
super.performClick();
int next = ((mState.ordinal() + 1) % FlashEnum.values().length);
setState(FlashEnum.values()[next]);
performFlashClick();
return true;
}
private void performFlashClick() {
if(mFlashListener == null)return;
switch (mState) {
case AUTOMATIC:
mFlashListener.onAutomatic();
break;
case ON:
mFlashListener.onOn();
break;
case OFF:
mFlashListener.onOff();
break;
}
}
private void createDrawableState() {
switch (mState) {
case AUTOMATIC:
setImageResource(R.drawable.ic_flash_auto);
break;
case ON:
setImageResource(R.drawable.ic_flash_on);
break;
case OFF:
setImageResource(R.drawable.ic_flash_off);
break;
}
}
public FlashEnum getState() {
return mState;
}
public void setState(FlashEnum state) {
if(state == null)return;
this.mState = state;
createDrawableState();
}
public FlashListener getFlashListener() {
return mFlashListener;
}
public void setFlashListener(FlashListener flashListener) {
this.mFlashListener = flashListener;
}
}
You can certainly define a selector to use as a background that has three entries. The question is what button attributes you can use for the selector. You can have two boolean attributes, say A and B, and define the selector in terms of A, B, and default. (A && B will satisfy A, so more properly they could be thought of as A, !A && B, and !A && !B.) You can overload existing attributes (selected, focused, etc.) or, more elegantly, define your own custom attributes using the recipe described in this thread.
Why not use RadioGroup and style radios inside?
<RadioGroup
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<RadioButton
android:layout_width="match_parent"
android:layout_weight="1"
android:layout_height="wrap_content"
android:background="#drawable/your_drawable_selector"
android:button="#android:color/transparent"
android:gravity="center_horizontal" //center text
android:text="text"
/>
...
Chip is a very good native option.
<com.google.android.material.chip.ChipGroup
android:id="#+id/chip_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:singleSelection="true">
<com.google.android.material.chip.Chip
android:id="#+id/first_chip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Todo"
android:textAppearance="?android:attr/textAppearance"
android:textColor="#color/black"
android:checkable="true"
style="#style/Widget.MaterialComponents.Chip.Choice"
app:chipBackgroundColor="#color/colorAccent"/>
<!-- Second Chip -->
<!-- Third Chip -->
</com.google.android.material.chip.ChipGroup>
binding.chipGroup.setOnCheckedChangeListener { chipGroup, i ->
when (i) {
binding.firstChip -> {
binding.firstChip.setChipBackgroundColorResource(R.color.colorAccent)
}
else -> {}
}
}
binding.firstChip.isChecked = true //default
GL
Source