Multi-State Toggle Button
Asked Answered
J

5

22

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.

Janel answered 28/1, 2011 at 1:18 Comment(0)
A
10

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.

Apprehension answered 28/1, 2011 at 1:30 Comment(4)
Looking at the thread you linked: I understand step 1, but 2 I have some questions about. In creating a new view, would it be better to extend View, Button, or something else? And are there other methods I should be overloading besides the constructors and onCreateDrawableState()? My apologies if these are basic, this is my first real app.Janel
Nevermind, got it working! Thank you for the push in the right direction, I appreciate it.Janel
@moonfire is your code proprietary? I'm trying to create a tri-state toggle button too, and would like to see some other solutions to wrap my head around how to do it.Geier
@JohnMetta Sorry for the late answer, I should check here more often. If you still need help, I just made a post about it at link. Or if you just want to download example source code: link. Hope that helps!Janel
H
20

I implemented a multi-state toggle button, the source code is here

This is how it looks:

enter image description here

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);
    }
});
Hyrax answered 29/1, 2014 at 14:44 Comment(4)
how did you customized it like in the picture? In your docs you didn't mention any custimizations.Peterus
That's an old version, try searching for older commits. But basically you'll have to modify the background drawables.Hyrax
@Hyrax thank you for this great code! I was wondering if it's possible to make a transition between toggles, instead of jumping straight from one button to the other, is there a way to transition between them?Islas
@Hyrax If I pass value Yes from Activity A to B where the toggle button is, how can I set the state of the toggle button with value Yes as checked ?Deviltry
T
14

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;
    }

}
Twelve answered 17/10, 2014 at 18:20 Comment(1)
You are making people lazy ;)Lowdown
A
10

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.

Apprehension answered 28/1, 2011 at 1:30 Comment(4)
Looking at the thread you linked: I understand step 1, but 2 I have some questions about. In creating a new view, would it be better to extend View, Button, or something else? And are there other methods I should be overloading besides the constructors and onCreateDrawableState()? My apologies if these are basic, this is my first real app.Janel
Nevermind, got it working! Thank you for the push in the right direction, I appreciate it.Janel
@moonfire is your code proprietary? I'm trying to create a tri-state toggle button too, and would like to see some other solutions to wrap my head around how to do it.Geier
@JohnMetta Sorry for the late answer, I should check here more often. If you still need help, I just made a post about it at link. Or if you just want to download example source code: link. Hope that helps!Janel
S
7

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"
         />
...
Subterrane answered 9/3, 2016 at 15:59 Comment(0)
C
2

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

Caracas answered 1/6, 2020 at 20:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.