androidandroid-buttonandroid-statusbaronsaveinstancestate

How to prevent a 'pressed Button' from getting unpressed when I pull down the status bar or minimize the app using Java in android studio?


I am working on a project where a button should stay pressed when the user touches or taps on it. I have done it successfully using:

button.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        button.setPressed(true);
        return true;
    }
});

Now, my problem is: when I pull down the status bar or minimize the app using home/back button (from navigation bar), the button becomes unpressed.

I have tried to solve this using:

onSaveInstanceState(Bundle savedInstanceState)

to save the pressed state of the button, but it didn't work.

Now, how can I solve this problem?


Solution

  • I have found two solutions to this (I personally like the second one).

    Solution 1

    Firstly, I have used onResume() and a flag variable to save the button's state when user minimizes the app.

    Secondly, I have used onWindowFocusChanged() and that same flag variable to save the button's state when user pulls down the status bar.

    Demo code:

    public class MainActivity extends AppCompatActivity {
    
        Button button;
    
        int flag=0;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            button = (Button) findViewById(R.id.button);
    
            button.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View view, MotionEvent motionEvent) {
    
                    button.setPressed(true);
                    flag=1;
    
                    return true;
                }
            });
        }
    
        @Override
        public void onResume() {
            super.onResume();
    
            if(flag==1){
                button.setPressed(true);
            }else{
                button.setPressed(false);
            }
    
        }
    
        @Override
        public void onWindowFocusChanged(boolean hasFocus) {
            // handle when the user pull down the notification bar where
            // (hasFocus will ='false') & if the user pushed the
            // notification bar back to the top, then (hasFocus will ='true')
    
            super.onWindowFocusChanged(hasFocus);
    
            if (!hasFocus) {
                Log.i("Tag", "Notification bar is pulled down");
    
            }
            else {
                Log.i("Tag", "Notification bar is pushed up");
                if(flag==1){
                    button.setPressed(true);
                }else{
                    button.setPressed(false);
                }
            }
    
        }
    }
    

    Solution 2:

    Firstly, I have created a file in drawable named button_bg.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
    
        <item android:state_selected="false" android:state_focused="false"
            android:state_pressed="false"
            android:drawable="@drawable/button_disabled">
        </item>
    
    
        <item android:state_selected="true"
            android:drawable="@drawable/button_default">
        </item>
    
    
        <item android:state_focused="true"
            android:drawable="@drawable/button_default">
        </item>
    
    
        <item android:state_pressed="true"
            android:drawable="@drawable/button_default">
        </item>
    
    </selector>
    

    Create two files in drawable (button_disabled.xml & button_default.xml) which are used in button_bg.xml.

    button_disabled.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle">
    
        <solid android:color="#b6b7b5" />
    
        <padding
            android:bottom="7dp"
            android:left="7dp"
            android:right="7dp"
            android:top="7dp" />
    
        <stroke
            android:width="2dp"
            android:color="#050303" />
    
        <corners android:radius="15dp" />
    
    </shape>
    

    button_default.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle">
    
        <solid
            android:color="#6FA803"/>
    
    
        <padding
            android:bottom="7dp"
            android:left="7dp"
            android:right="7dp"
            android:top="7dp" />
    
        <stroke
            android:width="2dp"
            android:color="#050303" />
    
        <corners android:radius="15dp" />
    
    </shape>
    

    Then, I have added this button_bg.xml file as a background of my button:

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/button_bg"
        android:text="Button" />
    

    Lastly, I have used setOnClickListener() and View.setSelected() to select the button view and stay pressed:

    button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
    
            v.setSelected(true);
    
        }
    });
    

    The reason I like the second solution is: I don't need to handle the button's state manually. So, when I will be working on with several buttons, the second solution will be more handy.