I know that I can trigger the OnClickListener.onClick of a Button manually in code by calling performClick, but that doesn't seem to make it visually appear as it's been clicked. I'm looking for a way to manually make a button appear as if it's been clicked. Do I need to manually change the background drawable and invalidate (and then change it back again on a Handler.postDelayed call), or is there a more framework-y way of doing this?
EDIT
I know how to make the button have different drawables to appear pressed when the user initiates the press. The question is this:
Is there a simple way to make a button appear pressed programmatically when not physically pressed by the user?
SOLUTION
I just subclassed Button and made the button aware of it's normal background as a StateListDrawable and the Drawable that is used as the pressed state. I expose a method that manually sets the background to the "pressed" drawable, and I use Handler.postAtTime to have it return to it's normal background so it can be used as a regular button again when I'm done.
Although this question is very old, I figured I'll still answer it. You don't need to subclass the View. First call performClick(), visual cue won't last long, but then you can set the button's pressed state via view.setPressed(true); and then reset it a couple of milliseconds later like this.
handler.postDelayed(new Runnable() {
#Override
public void run() {
view.setPressed(false);
}
}, 100);
Ya, you have to create 2 drawables. One for pressed state and other for normal state.
Then you will have to create an xml like:
<?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/focused_drawable" />
<item
android:state_pressed="false"
android:drawable="#drawable/unfocused_drawable" />
</selector>
Place this xml inside your drawable folder. You can also add focused state as
android:state_focused="true"
Then inside your layout which is used by your activity, give inside your button tag:
android:background="#drawable/your xml file name"
Related
I recently refactored my App to use the jetpack navigation. On my MainActivity, I had a ViewPager containing 3 fragments with 1 recyclerview each. I therefore moved the ViewPager from the Activity to a new Fragment. Everything works when it comes to the functionality itself, but a new issue arose which really bugs me: When I select an item on the recyclerview with a long press, the ripple effect gets stuck and stays there, as if I'm still pressing the item, which I don't. Here is a picture of a selected item. As it can be seen, the ripple effect stays active on the TextView.
When I unselect the Item, the ripple effect also stays active:
The selection itself is handled with the android SelectionTracker. The TextView has the background set to background="?android:attr/selectableItemBackground". The whole ViewItem has the background set to android:background="#drawable/bg_multi_selection, whereas the bg_multi_selection file looks as follows:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#color/secondaryLightColor" android:state_activated="true" />
<item android:drawable="#android:color/transparent" />
</selector>
What could be the issue of that? This is especially weird, as the problem did not exist, when the ViewPager with its fragments was contained inside the Activity, and not a Fragment. Any suggestions on how to fix this?
I found a solution which works for me. So for anyone interested, I did the following:
In the recyclerviewadapter in the onBindViewHolder() method I check if the element is selected and additionally set the background color and background resource of the TextView programmatically.
if (elementIsSelected) {
viewHolder.viewBinding.itemTextView.setBackgroundColor(context.resources.getColor(R.color.transparent, context.theme))
} else {
val outValue = TypedValue()
context.theme.resolveAttribute(android.R.attr.selectableItemBackground, outValue, true)
viewHolder.viewBinding.itemTextView.setBackgroundResource(outValue.resourceId)
}
whereas I definied the color to be transparent, i.e. #00000000
It's odd that this problem occurs only on some devices, so I'm not sure if the "real" problem lies somewhere else, but at least that's how I fixed it. Hope that might be helpful for someone else.
I'm an Android beginner and I am currently trying to make my first calculator app.
My biggest inspiration is the Windows 10 built-in calc. I want some buttons to be disabled during some actions to get rid of bugs but I don't like the look of disabled-buttons.
I'd rather have them enabled but make them so they don't perform any action. I tried to use .setClickable(false) but then there is no sound of click as well as no animation of clicking (shadow).
Can they be fully clickable but have no action?
Use a variable to decide that. Put it somewhere in your class:
private boolean clicked = false;
Then(at the on click listener of the button):
if (clicked) {
//your action happens here(it wouldn't happen, until you change clicked to true)
}
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#color/disabled_color" android:state_enabled="false" />
<item android:drawable="#color/enabled_color" android:state_enabled="true"/>
</selector>
You can use the above xml (let's say we name it button_selector.xml)
Apply it as background for your Button (in your activity layout)
In your code, based on your actions, use
setEnabled(false);
and that's it. You can change it back programmatically when you want the button to be active again. Also, you can add
setFocusable(false);
setFocusableInTouchMode(false);
setClickable(false);
Try this:
Button btn = (Button) findViewById(R.id.button1);
btn.setEnabled(false);
What it does is disable the button and make it not clickable.
Not surprising I found myself looking at a tablet-optimized design one day that showed a pane with search results on the left side and a pane to display corresponding details on the right. The results on the left pane had a selected state to indicate which details were currently shown. What seemed to be a walk in the park ended up being a tiresome journey of trial and error. But finally I managed to get it working and I removed all irrelevant test-code only to discover it had stopped working straight away. I reintroduced the "irrelevant" part and surprisingly it worked as planned.
Client happy, designer happy, but not me, because I still don't understand why it works as it does.
I have a fragment that has a ListView with choiceMode set to ListView.CHOICE_MODE_SINGLE.
The adapter inflates custom views for each result and sets a drawable as background (happens in code)
The drawable is a selector wrapped in a RippleDrawable and has checked and activated states with a drawable for the selected state that needs to be preserved.
The custom view overrides setSelected(boolean selected) and dependent on the boolean adds or removes a view that has the selected state.
Now my problem is 3 & 4. Having the checked and activated states (step 3) ensures that setSelected(true) gets called when the view is tapped, but not immediately gets called again with setSelected(false) once the touchDown ends and thus the view I set in step 4 stays.
I had however expected I didn't need this custom view from step 4 as I thought it would use the drawable for the activated state from step 3. Removing the custom (thus unrelated to Android states system) view from step 4 has the effect that the state drawable from step 3 does show up, but only during onPress (touchDown/Hold) and... on the previous selected item!
Item Background
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#color/light_gray">
<item android:drawable="#drawable/search_result_selector" />
</ripple>
Selector Drawable (search_result_selector)
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#color/white_selected" android:state_selected="true"/>
<item android:drawable="#color/white_selected" android:state_pressed="true"/>
<item android:drawable="#drawable/search_result_highlighted_state" android:state_activated="true"/>
<item android:drawable="#drawable/search_result_highlighted_state" android:state_checked="true"/>
<item android:drawable="#color/white"/>
</selector>
setSelected(selected) on custom view used for items in ListView
#Override
public void setSelected(boolean selected) {
super.setSelected(selected);
if (selected && selectedView == null) {
selectedView = new View(getContext());
selectedView.setBackground(Utils.getDrawable(getContext(), R.drawable.action_bar_background));
RelativeLayout.LayoutParams lp = new LayoutParams(Utils.pxFromDp(getContext(), 3), getHeight());
lp.addRule(ALIGN_PARENT_RIGHT);
addView(selectedView, lp);
} else if (!selected && selectedView != null) {
removeView(selectedView);
selectedView = null;
}
}
selectedView is a field I defined in my custom view class. I understand why it works, but I wonder why I need it as I expected the state drawable to be used correctly and preserve selection. The strange thing is when I remove that part, the ListView decides to do use the drawable, but on the previous selected view and only during touchDown. Now why would the presence of a custom implementation, not tied to any Android API influence the working of Android's view states? Apparently it is tied somehow, somewhere, but I fail to see where. Any pointers to the why behind this all would put my mind at ease. Thank you in advance!
EDIT
Apparently one of my conclusions was wrong. setSelected(false) was called, even with the states in the selector. Which makes sense perhaps if activated is the state that matters. I moved the code to an overriden method on setActivated, which does in fact show my custom view. That said the weirdness remains... the state drawable don't work as expected.
I would like to define a button in Android, through XML, which, below the standard Button graphics (change color when clicked, slightly rounded edges,...), shows an image of my choice. I would like the final product to be somewhat like this:
I have tried change the src and background of an ImageButton, but it does not provide the intended effect. Could you please point me some way of achieving this?
Maybe that's not exactly what you mean by standard, but when you set a background, you end up having to recreate the behavior when the button is clicked. The best way to do it in Android is by using a selector as your button's background. Create a XML drawable with the selector in it.
Example:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="#drawable/button_bg_pressed" />
<item android:drawable="#drawable/button_bg_default" />
</selector>
That way, when your button is clicked, it will change the background to other image that does what you want.
EDIT:
There are other modifiers such as focused, if you need.
If you want Lollipop's ripple effects, I think you can create a Layout and put your button inside it. Change the Layout background and set the button background to transparent. If that doesn't work, try adding android:background="?android:attr/selectableItemBackground" to your button.
As Paulo said, you can achieve the click effect with a selector.
See this answer (https://stackoverflow.com/a/30192562) it gives the code for a very nice and customizable ripple effect.
Hi im applying custom images to button on different states, for which i create an xml file in appliication drawable folder in which i define states of button and images like this
Btn_enter_cutom.xml
<item android:drawable="#drawable/btn_enter" />
<item
android:state_pressed="true"
android:drawable="#drawable/btn_enter_pressed" />
and assign this xml file to background attribute of the button.
button's default image is btn_enter.png but when this button presses i want to apply btn_enter_presses.png,but when i pressed the button nothing will happens,is there any problem with the xml file please help me in this regards.thanks
A state list will always display the first matching line. Reverse your two items, since the first one acts as a default and prevents any further testing.