11

yesterday I noticed the possibility to integrate Fragments in older API Levels through the Compatibility package, but thats not really essential for the question. :)

I have a Button with an OnClickListener

Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        doSomething();
        button.setPressed(true);
    }
});

Because of the actual clicking, it is shown as pressed and after releasing the click, the button state is not pressed and stays that way.

Is there a simple way that keeps the button state pressed after releasing? First thing I can think of would be some sort of timer, but that seems unreasonable.

strem
  • 400
  • 1
  • 4
  • 15
  • 1
    use `setSelected(boolean state)` – Muhammad Babar Jan 02 '14 at 12:40
  • 1
    Hi strem - could you please list exactly how you fixed it? Do you mean you want the button to display pressed for a set time until the event is complete? Or reset the pressed button? Anyway, please show your solution because the solution you selected below was wrong .. – tm_forthefuture Feb 13 '14 at 12:48

7 Answers7

25

Just to note this is because Android is changing the setPressed both before and after your onClickEvent, so changing it yourself has no effect. Another way to get around this is to use the onTouchEvent.

button.setOnTouchListener(new OnTouchListener() {

    @Override
    public boolean onTouch(View v, MotionEvent event) {

        // show interest in events resulting from ACTION_DOWN
        if (event.getAction() == MotionEvent.ACTION_DOWN) return true;

        // don't handle event unless its ACTION_UP so "doSomething()" only runs once.
        if (event.getAction() != MotionEvent.ACTION_UP) return false;

        doSomething();
        button.setPressed(true);                    
        return true;
   }
});
sfmirtalebi
  • 370
  • 7
  • 16
Martin Sykes
  • 2,591
  • 1
  • 21
  • 19
  • 2
    Martin, I like your answer very much. However, when I click in the notification area or in the options menu, the pressed state goes away. Do you have any idea of what is going on? – Couitchy Jul 24 '13 at 09:12
14

Use ToggleButton instead of Button.

<ToggleButton
    android:id="@+id/button2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_weight="1"
    android:background="@drawable/topping_selector"
    android:checked="false"
    android:textOff="Topping2"
    android:textOn="Topping2" />

topping_selector.xml:

<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_checked="true" 
        android:drawable="@drawable/btn_topping_on" />

    <item android:state_checked="false" 
        android:drawable="@drawable/btn_topping_off" />

</selector>
Marcos Dimitrio
  • 6,651
  • 5
  • 38
  • 62
krishna mohan
  • 141
  • 1
  • 2
6

You can keep the button states in xml file under drawable folder, then used as background for button. For example:

 android:background="@drawable/buttonstate"

buttonstate.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true" android:drawable="@drawable/back_focused" />
    <item android:drawable="@drawable/back" /> <!-- default -->
</selector>
sfmirtalebi
  • 370
  • 7
  • 16
Kakey
  • 3,936
  • 5
  • 29
  • 45
  • 13
    not quite what i hoped for, but thanks nevertheless! got it working now with button.setSelected(true) and definining a drawable for that state – strem May 12 '11 at 09:09
  • 3
    not what the user asked, doesnt solve the problem. This answer really should not be approved. – ChuckKelly Sep 12 '13 at 05:19
  • I agree with Chuck - strem - please post an example of how you did this with setSelected(true) if you managed to achieve it that way. Does the button return to the normal state after the action is complete? – tm_forthefuture Feb 12 '14 at 13:41
  • @strem checkout my solution below – M. Usman Khan Mar 18 '14 at 10:23
4

Better solution:

In xml file:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
    <item android:state_activated="true">
        <bitmap android:src="@drawable/image_selected"/>
    </item>
    <item>
        <bitmap android:src="@drawable/image_not_selected"/>
    </item>
</selector>

And in java:

@Override
public void onClick(View v) {
   v.setActivated(!v.isActivated());
}
sfmirtalebi
  • 370
  • 7
  • 16
M. Usman Khan
  • 3,689
  • 1
  • 59
  • 69
  • 1
    Haha. Too many lines for simple task: ```v.setActivated(!v.isActivated())``` But thanks anyway – ruX Jul 29 '14 at 15:25
  • if this is the logic then you dont need a selector to.. simply toogle things on your own . bad solution' – Khay Apr 10 '15 at 10:52
3

You can use android.os.Handler class. Ugly, but works also:

final Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        doSomething();
        new Handler().post(new Runnable() {
            @Override
            public void run() {
                button.setPressed(true);
            }
        });
    }
});
valerybodak
  • 4,195
  • 2
  • 42
  • 53
0

Another solution is to extend Button and override setPressed(boolean pressed) method so you can handle platform calls from the onClickEvent using a flag, for example changing the boolean pressed parameter depending on your needs.

public class MyButton extends Button {
   boolean isSelected = false;  //this is your flag
   @Override
   public void setPressed(boolean pressed) {
       if(isSelected) {
           //here you change the parameter so it stays pressed
           super.setPressed(true);
           return;
       }
       super.setPressed(pressed);
   }

   public void setIsSelected(boolean selected) {
       this.isSelected = selected;
   }

   public MyButton(Context context) {
       super(context);
   }
}
sfmirtalebi
  • 370
  • 7
  • 16
0

This is the solution I used, It also works on android 7.0 at the moment.

YourActivity.java

public void onStandbyStart(String message) {
    startStandbyBtn.setActivated(true);
}

public void onBackOnline(String message) {
    startStandbyBtn.setActivated(false);
}

YourActivityLayout

<Button
        ...
        style="@style/generic_btn_style"
        ... />

values/styles.xml

    <style name="generic_btn_style" parent="@android:style/Widget.Button">
        <item name="android:gravity">center_vertical|center_horizontal</item>
        <item name="android:background">@drawable/generic_btn</item>
        <item name="android:textColor">@color/selector_white_black</item>
        <item name="android:focusable">true</item>
        <item name="android:clickable">true</item>
</style>

drawable/generic_btn.xml This selector chooses the button background. I use the pressed as the activated.

<?xml version="1.0" encoding="utf-8"?>

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/generic_btn_disabled" android:state_enabled="false" />
    <item android:drawable="@drawable/generic_btn_pressed" android:state_enabled="true" android:state_pressed="true" />
    <item android:drawable="@drawable/generic_btn_pressed" android:state_activated="true" />
    <item android:drawable="@drawable/generic_btn_focused" android:state_enabled="true" android:state_focused="true" />
    <item android:drawable="@drawable/generic_btn_enabled" android:state_enabled="true" />
</selector>

color/selector_black_white Here I set the text color. In my case, I need to pick the textcolor black when pressed.

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="#fff" android:state_pressed="true" /> <!-- pressed -->
    <item android:color="#fff" android:state_activated="true" /> <!-- pressed -->
    <item android:color="#000" /> <!-- default -->
</selector>
Federico Picci
  • 1,105
  • 10
  • 17