As you can see the background is distorted behind the popup. It only happens on lollipop! Please don't be confused by all the x_ in my style files. I've just de-branded the code.
In theme file:
<style name="core" parent="Theme.AppCompat.Light">
<!-- Popup menu -->
<item name="android:popupMenuStyle">#style/x_popup_menu_theme</item>
<item name="android:textAppearanceSmallPopupMenu">#style/x_popup_menu_small_text</item>
<item name="android:textAppearanceLargePopupMenu">#style/x_popup_menu_large_text</item>
</style>
in v21/themes_styles.xml
<style name="x_popup_menu_theme" parent="Widget.AppCompat.PopupMenu">
<item name="android:popupBackground">#color/x_navy_dark</item>
</style>
<style name="x_popup_menu_large_text" parent="TextAppearance.AppCompat.Widget.PopupMenu.Large">
<item name="android:textColor">#color/std_white</item>
</style>
<style name="x_popup_menu_small_text" parent="TextAppearance.AppCompat.Widget.PopupMenu.Small">
<item name="android:textColor">#color/std_white</item>
</style>
If I change/remove the style to this it works as shown in the next pic.
<style name="x_popup_menu_theme" parent="Widget.AppCompat.PopupMenu">
</style>
<style name="x_popup_menu_large_text" parent="TextAppearance.AppCompat.Widget.PopupMenu.Large">
</style>
<style name="x_popup_menu_small_text" parent="TextAppearance.AppCompat.Widget.PopupMenu.Small">
</style>
There was a bug in Android 5.0.x (which was fixed in 5.1) where setting an opaque (ex. #color) background in an elevated window resulted in visual artifacts.
As a workaround on 5.0.x devices, you can set the background to a non-opaque drawable such as a rounded rectangle.
res/drawable/my_popup_bg.xml:
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="2dp" />
<solid android:color="#color/x_navy_dark" />
</shape>
res/values/styles.xml:
...
<style name="x_popup_menu_theme" parent="Widget.AppCompat.PopupMenu">
<item name="android:popupBackground">#drawable/my_popup_bg</item>
</style>
[EDITED - Removed original answer that suggested turning off hardware acceleration]
It appears this is a bug in android 5.0 with the frame buffer. It has been fixed in android 5.1. Bug listing
Here's a message from Chet Haase on how to work around the issue:
The trigger is that you're setting the background of the popup window to a color, which resolves to a colored rectangle. You should either be using a rounded rect (like the default style uses) or, better yet, use the dark theme instead of a custom color.
The bug [in android] (which is [fixed in 5.1]) was that we were not accounting for the padding for shadows and were not setting the correct translucency flags in the window in this situation.
For now I just created my own popup menu using a linearlayout and handling the clicks and back button manually. Not too elegant, but it matched what the art team wanted closer than the popup menu anyway.
<LinearLayout
android:id="#id/fake_popup"
android:layout_below="#id/pending"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="wrap_content" android:orientation="vertical">
<TextView
style="#style/button.dropdown"
android:id="#id/send_reminder"
android:background="#color/navy_dark"
android:textColor="#color/std_white"
android:text="#string/send_reminder"/>
<TextView
style="#style/button.dropdown"
android:id="#id/withdraw_invite"
android:background="#color/navy_dark"
android:textColor="#color/std_white"
android:text="#string/withdraw_invite"/>
</LinearLayout>
Handle the click to show/hide the menu (note the annotations are ButterKnife):
#OnClick (R.id.pending) public void showPendingActionsMenu () {
// pendingActionsPopupMenu.show ();
if (pendingPopup.isShown ()) {
hidePendingPopup ();
} else {
showPendingPopup ();
}
}
And handle the clicks of the individual choices:
#OnClick (R.id.send_reminder)
public void sendReminder () { //your code here }
Don't forget to override onBackPressed!
#Override public void onBackPressed () {
if (pendingPopup.isShown ()) {
hidePendingPopup ();
} else {
super.onBackPressed ();
}
}
Related
I've seen some SO questions and they gave some possible methods to achieve what I want. For example:
Use colorControlHighlight attribute in styles.xml.
Here is my styles-v21.xml:
<style name="SelectableItemBackground">
<item name="android:colorControlHighlight">#5677FC</item>
<item name="android:background">?attr/selectableItemBackground</item>
</style>
And my widget:
<TextView
android:id="#+id/tv_take_photo_as_bt"
android:layout_width="280dp"
android:layout_height="48dp"
android:text="#string/act_take_photo"
style="#style/SelectableItemBackground"/>
And it doesn't work. I also tried to add parent="Theme.AppCompat to "SelectableItemBackground" style, or change to colorControlHighlight(no android: prefix)", or change to ?android:attr/selectableItemBackground, neither is useful.
Use backgroundTint attribute in layout.
So I add android:backgroundTint="#5677FC" to my TextView. Still useless. Then I tried to change android:backgroundTintMode to src_in and src_atop, and they never make a difference.
So, how can I change ripple color when I use ?attr/selectableItemBackground as background. I only focus on Lollipop and above. Thank you in advance!
Finally I find the solution: instead of using android:colorControlHighlight directly in theme SelectableItemBackground, I should write another style:
<style name="SelectableItemTheme">
<item name="colorControlHighlight">#color/ripple_color</item>
</style>
Then:
<style name="SelectableItemBackground">
<item name="android:theme">#style/SelectableItemTheme</item>
<item name="android:background">?attr/selectableItemBackground</item>
</style>
Finally add style="#style/SelectableItemBackground" to View in layout.xml.
UPDATED ON 2016/8/26
After N's release, I found that sometimes we cannot use this method to set ripple color for some kind of View(for example, the CardView). Now I highly recommend developers using RippleDrawable, which can also be declared in xml. Here is an example:
I want to show a ripple effect when user touches/clicks a CardView above API21, and of course there should be another kind of feedback before Lollipop. So I should write:
<android.support.v7.widget.CardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:foreground="#drawable/selectable_item_background"/>
and selectable_item_background in drawable folder:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="false" android:drawable="#android:color/transparent" />
<item android:drawable="#color/color_clicked" />
</selector>
selectable_item_background in drawable-v21 folder:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/ripple_black" />
</selector>
finally, the ripple_black in drawable(or drawable-v21) folder:
<ripple
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:color="#color/color_clicked"
tools:ignore="NewApi" /> <!--you can remove this line if it's in v21 folder-->
That's it. For other views, maybe you should use android:background="#drawable/selectable_item_background". Don't forget to set an OnClickListener, OnTouchListener or something like those for them, otherwise ripple won't show.
Ripple effect on pre- and Lollipop+ devices
harrane and Liuting are right. The accepted answer is not the best way.
Let me show in code how to change ripple color for pre-Lollipop versions and higher
Your AppTheme should inherit from any AppCompat theme and contain colorControlHighlight attribute (without 'android:' prefix)
<!-- Application theme. -->
<style name="AppTheme" parent="#style/Theme.AppCompat.Light.NoActionBar">
<item name="colorControlHighlight">#40ffffff</item>
</style>
Your view should contain clickable="true" (or should have a click listener set programmatically) and background should be "?attr/selectableItemBackgroundBorderless" or "?attr/selectableItemBackground" :
<LinearLayout
...
android:clickable="true"
android:background="?attr/selectableItemBackgroundBorderless"/>
Note: that if your parent view has white background you won't see ripple effect since it's white. Change colorControlHighlight value for a different color
Also, if you want different ripple colors on different activities you can set personal theme for each activity in Manifest file, for example:
<activity
android:name="com.myapp.GalleryActivity"
android:theme="#style/RedRippleTheme"
/>
Different ripple colors for different fragments in the same activity?
You can change attributes of Activity Theme for each fragment in runtime. Just overwrite them before fragment was inflated with your custom style and apply to a current Theme:
in values/styles.xml
<style name="colorControlHighlight_blue">
<item name="colorControlHighlight">#color/main_blue_alpha26</item>
</style>
Then, in your fragment before inflation in onCreateView():
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
getContext().getTheme().applyStyle(R.style.colorControlHighlight_blue, true); //blue ripple color
View view = inflater.inflate(R.layout.my_fragment_layout, container, false);
return view;
}
This style will work only for this fragment
Different ripple color for different Views? (Lollipop +)
You can change the ripple color for each view seperately using
colorControlHighlight attribute, it doesn't work if you apply them to a view directly:
<TextView
...
colorControlHighlight="#40ffffff"/> <!-- DOESN'T WORK -->
you should apply it as a theme:
<TextView
...
android:theme="#style/colorControlHighlight_blue"/>
P.S. Also, sometimes this approach helps if you have unknown issues with ripple and you can't figure it out.
In my case, I used 3rd party sliding lib which messed up ripple effects for the entire layout and adding explicitly this theme to all clickable views worked out for me.
It's showing ripple effect with color on API +21, and simple gray background on press for API -21.
Add this style:
<style name="AppTheme.MyRipple">
<item name="colorControlHighlight">#color/your_color</item>
<item name="android:background">?selectableItemBackgroundBorderless</item>
</style>
And set it to the view:
<Button
...
android:theme="#style/AppTheme.MyRipple" />
Use the below steps:
1. Make changes to button view in your layout.xml
2. Add new styles in styles.xml
your_layout.xml
<Button
android:id="#+id/setup_submit_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="#string/action_sign_in"
android:textStyle="bold"
android:background="#color/colorPrimary"
android:textColor="#color/white"
style="#style/SelectableItemBackground"
android:foreground="?android:attr/selectableItemBackground"/>
-The style attribute calls the style that we created.
-Foreground attribute calls the andorid's default selectable attribute.
styles.xml
<style name="SelectableItemTheme">
<item name="colorControlHighlight">#color/white</item>
</style>
<style name="SelectableItemBackground">
<item name="android:theme">#style/SelectableItemTheme</item>
<item name="android:background">?attr/selectableItemBackground</item>
</style>
The accepted answer is wrong.
The correct way to use is what Liuting mentioned in the comment.
Use colorControlHighlight instead of android:colorControlHighlight for changing the default colorControlHighlight from AppCompat
* Please refer to http://android-developers.blogspot.co.uk/2014/10/appcompat-v21-material-design-for-pre.html in the Theming section *
This code works for me to create a ripple:
public static void setRippleDrawable(View view, int normalColor, int touchColor) {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
RippleDrawable rippleDrawable = new RippleDrawable(ColorStateList.valueOf(touchColor), view.getBackground(), null);
view.setBackground(rippleDrawable);
} else {
StateListDrawable stateListDrawable = new StateListDrawable();
stateListDrawable.addState(new int[]{android.R.attr.state_pressed}, new ColorDrawable(touchColor));
stateListDrawable.addState(new int[]{android.R.attr.state_focused}, new ColorDrawable(touchColor));
stateListDrawable.addState(new int[]{}, new ColorDrawable(normalColor));
view.setBackground(stateListDrawable);
}
} catch (Exception e) {
Log.e(LOG_TAG, "" + e);
}
}
I did not found any way to modify the selectableItemBackground attribute.
That's why I did it like above.
In dark black theme(Or any other) app try to use like below
first create ripple_effect.xml in drawable folder and add code like
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#f5f5f5">
<item android:id="#android:id/mask">
<shape android:shape="rectangle">
<solid android:color="#f5f5f5" />
</shape>
</item>
</ripple>
then set background to your Any view like Linear layout, Button, TextView etc.
<TextView
android:id="#+id/tvApply"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/ripple_effect"
android:clickable="true"
android:text="APPLY"
android:textColor="#FFFFFF"
android:gravity="center"
android:textSize="#dimen/_8sdp"
android:padding="#dimen/_8sdp"
android:focusable="true" />
Use the foreground attribute as selectableItemBackground
and background attribute as the color you want.
android:foreground="?attr/selectableItemBackground"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:background="#color/white"
I haven't been able to find quite what I am trying to do on SO, but I feel like it should be such a common interface need that there must be a straightforward way of accomplishing this that I'm missing.
In my style.xml I have two button styles, a standard "active" button and an "inactive" button.
<style name="ButtonStandard">
<item name="android:background">#color/colorGreen</item>
<item name="android:textColor">#android:color/white</item>
<item name="android:padding">#dimen/element_padding</item>
</style>
<style name="ButtonInactive">
<item name="android:background">#color/colorLight</item>
<item name="android:textColor">#android:color/black</item>
<item name="android:padding">#dimen/element_padding</item>
</style>
I am setting one button to ButtonStandard and the other to ButtonInactive. When I click the inactive button, I want to change it to use the ButtonStandard type and vice versa. I don't want to programmatically set the styles individually in case I decide to later change the button styles and it would be unreliable to have to change it in every location.
activeButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
activeButton.[somehowsetstyle](R.style.ButtonInactive);
inactiveButton.[somehowsetstyle](R.style.ButtonStandard);
}
});
How can I change between these styles when users click on buttons? The most important is to not have to set specific styles within the code which is just a last resort imho.
Thanks!
Solution Notes
Generally I followed the solution below but instead I created the selector as a drawable and used android:drawable instead because it seems the button background needs that, even if just specifying a color. I also used state_activated rather than enabled so that it is only changing the look of the button and doesn't prevent clicks.
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_activated="false"
android:drawable="#color/colorPrimaryDark" />
<item android:state_activated="true"
android:drawable="#color/colorGreen" />
<item android:drawable="#color/colorGreen" />
In XML
android:background="#drawable/selector_btn_bkg"
android:state_activated="false"
In Java
myButton.setActivated(true);
What you are looking for is ColorStateList
drawable/my_selector.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:color="#color/enabled_color"/>
<item android:color="#color/enabled_color"
android:state_enabled = "true"/>
<item android:color="#color/disbaled_color"
android:state_enabled = "false"/>
</selector>
my_view.xml
...
<Button
android:id="#+id/my_button"
android:enabled="false"
android:background="#drawable/my_selector"/>
Java code
onClick(View v){
myButton.setEnabled(true);
}
I want to put an indeterminate progress bar inside my ActionBar (using ActionBarSherlock). Everything works, but I want it to be the small progress bar. I use following style:
<style name="IndeterminateProgress" parent="#android:style/Widget.ProgressBar.Small">
<item name="android:progressBarPadding">32dp</item>
<item name="progressBarPadding">32dp</item>
<item name="android:itemPadding">32dp</item>
<item name="itemPadding">32dp</item>
</style>
<style name="Widget.Styled.ActionBar.Tiles" parent="Widget.Sherlock.Light.ActionBar">
<item name="android:indeterminateProgressStyle">#style/IndeterminateProgress</item>
<item name="android:progressBarPadding">32dp</item>
<item name="progressBarPadding">32dp</item>
<item name="android:itemPadding">32dp</item>
<item name="itemPadding">32dp</item>
</style>
The problem is that I cannot set the padding on the progress bar. As you can see above, I've tried every possible combination of itemPadding and progressBarPadding, etc.
The result is always the same:
Any ideas?
I found a working solution how to set indeterminate progress bar with proper size and padding. My solution doesn't use workaround with setActionView(). It is solution for built-in progress bar functionality, supported by native action bar (ActionBarSherlock). Progress bar is enabled/disabled via setProgressBarIndeterminateVisibility(boolean) method. I tested it on Android 2, 3, 4 and ldpi, mdpi, xhdpi.
AndroidManifest.xml:
<application
...
android:theme="#style/Theme.Example">
/res/values/styles.xml:
<resources xmlns:android="http://schemas.android.com/apk/res/android">
...
<style name="Theme.Example" parent="Theme.Sherlock">
<item name="actionBarStyle">#style/Example.ActionBar</item>
<item name="android:actionBarStyle">#style/Example.ActionBar</item>
</style>
<style name="Example.ActionBar" parent="Widget.Sherlock.ActionBar">
<item name="indeterminateProgressStyle">#style/Example.ActionBar.IndeterminateProgressBar</item>
<item name="android:indeterminateProgressStyle">#style/Example.ActionBar.IndeterminateProgressBar</item>
</style>
<style name="Example.ActionBar.IndeterminateProgressBar" parent="#android:style/Widget.ProgressBar.Large.Inverse">
<item name="android:indeterminateDrawable">#drawable/layer_list_ab_indeterminate_progress_bar</item>
<item name="android:minWidth">#dimen/ab_indeterminate_progress_bar_size</item>
<item name="android:maxWidth">#dimen/ab_indeterminate_progress_bar_size</item>
<item name="android:minHeight">#dimen/ab_indeterminate_progress_bar_size</item>
<item name="android:maxHeight">#dimen/ab_indeterminate_progress_bar_size</item>
</style>
</resources>
/res/drawable/layer_list_ab_indeterminate_progress_bar.xml:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<!--
/res/drawable-mdpi/ab_indeterminate_progress_bar asset is taken from
/sdk/platforms/android-18/data/res/mdpi/spinner_white_48.png
and its content (optical square) is resized to ~0.6 (must be even number)
/res/drawable-mdpi-v14/ab_indeterminate_progress_bar asset is taken from
/sdk/platforms/android-18/data/res/mdpi/spinner_48_outer_holo.png
and its content (optical square) is resized to 0.75
-->
<rotate
android:drawable="#drawable/ab_indeterminate_progress_bar"
android:interpolator="#android:anim/linear_interpolator"
android:pivotX="50%"
android:pivotY="50%"
android:fromDegrees="0"
android:toDegrees="360" />
</item>
</layer-list>
/res/values/dimens.xml:
<dimen name="ab_indeterminate_progress_bar_size">48dp</dimen>
Finally I created progress bar assets. I used these two assets from Android SDK:
/sdk/platforms/android-18/data/res/mdpi/spinner_white_48.png for Honeycomb and older
/sdk/platforms/android-18/data/res/mdpi/spinner_48_outer_holo.png for ICS and newer
To get proper size and padding, we need to resize the assets. I resized spinner_white_48.png to ~0.6. For mdpi, it was 28px. It must be even number to be centrally symmetric. I resized only the content, not the whole icon. So icon in mdpi has still 48px, but its content (optical square) is smaller (28px). You can easily resize the content this way: first change "image size" to 28px X 28px, then change "canvas size" back to 48px X 48px. I resized spinner_48_outer_holo.png to 0.75. You can download the assets below.
Why do I use different assets for Honeycomb- and ICS+? Because if I'm using only Holo assets, the animation is little bit snatchy on some devices with Honeycomb-.
Tip: you can add another item with some animation to layer_list_ab_indeterminate_progress_bar.xml. For example standard Holo progress bar uses 2 animations with opposite direction and different degrees range. See progress_medium_holo.xml in SDK.
/res/drawable-mdpi/ab_indeterminate_progress_bar.png:
/res/drawable-mdpi-v14/ab_indeterminate_progress_bar.png (hardly visible on this page):
/res/drawable-hdpi/ab_indeterminate_progress_bar.png:
/res/drawable-hdpi-v14/ab_indeterminate_progress_bar.png (hardly visible on this page):
/res/drawable-xhdpi/ab_indeterminate_progress_bar.png:
/res/drawable-xhdpi-v14/ab_indeterminate_progress_bar.png (hardly visible on this page):
I don't know the exact answer but these settings worked for me..
This is my refresh_spinner.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center">
<ProgressBar android:layout_width="32dp"
android:layout_height="32dp"
android:layout_gravity="center"
android:layout_marginRight="12dp"
android:layout_marginLeft="12dp"
style="?indeterminateProgressStyle" />
</FrameLayout>
And this in the corresponding style xml
<style name="Widget.MyTheme.ActionBar" parent="Widget.Sherlock.ActionBar">
<item name="indeterminateProgressStyle">?android:attr/progressBarStyleSmallInverse</item>
</style>
These settings worked for me.
Please let me know if you have any doubts.
Regards
Parvaz Bhaskar
EDIT2 : since I was trying different methods I ended up using ?android:attr/progressBarStyleSmallInverse
as the only property in my style.xml which i later refrenced it from my spinner xml under style as style="?indeterminateProgressStyle"
EDIT:
keep a reference of your menuItem and whenever you want to show a refresh progressbar use setActionView(R.layout.your_layout), and change it to null when the need is over. onCreateOptionsMenu would be a good place to grab the menuItem at start.
I meet this today and find a solution for Android 3/4+
ProgressBar mProgressBarInActionBar = null;
Resources res = Resources.getSystem();
int id = res.getIdentifier("progress_circular", "id", "android");
View internal = findViewById(id);
if(internal != null && internal instanceof ProgressBar){
mProgressBarInActionBar = (ProgressBar)internal;
}
mProgressBarInActionBar.setPadding(0, 0, right, 0);
Set a suitable right :)
I had the same problem and I found an easy answer:
<style name="ActionBarProgressBar.MyStyle" parent="#android:style/Widget.Holo.ProgressBar.Large">
<item name="android:minWidth">56dp</item>
<item name="android:maxWidth">56dp</item>
<item name="android:minHeight">35dp</item>
<item name="android:maxHeight">35dp</item>
</style>
The Width is the standard Actionbar item width. If you change the minHeight and maxHeight, then the image will scale both ways.
And here is the Actionbar styling where you set the appearance of the Indeterminate Progress:
<style name="action_bar_theme" parent="#android:style/Widget.Holo.ActionBar">
<item name="android:indeterminateProgressStyle">#style/ActionBarProgressBar.MyStyle</item>
</style>
And the definition in the Theme you are using (don't forget to use it in your manifest):
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="android:actionBarStyle">#style/action_bar_theme</item>
</style>
I need to prevent seekbar from user inputs in special cases. If I use setEnabled(false) it becomes gray instead of white.
Is there any method to disable seekbar without dimming or set another drawable for progress in disabled seekbar ?
Yes. It is possible! But you need to override SeekBar's drawableStateChanged function, with something like this:
#Override
protected void drawableStateChanged() {
super.drawableStateChanged();
final Drawable progressDrawable = getProgressDrawable();
if(isEnabled() == false && progressDrawable != null) progressDrawable.setAlpha(255);
}
Actually I was very angry, when I saw hardcoded alpha value in AbsSeekBar:
mDisabledAlpha = a.getFloat(com.android.internal.R.styleable.Theme_disabledAlpha, 0.5f);
Because there is no function, which will turn off, or even change disabled alpha value for SeekBar. Just take a look at those lines of code in drawableStateChanged function:
if (progressDrawable != null) {
progressDrawable.setAlpha(isEnabled() ? NO_ALPHA : (int) (NO_ALPHA * mDisabledAlpha));
}
I'm not sure why you'd want to change this, and I don't believe it's good practice to override the visual queue for a user that something is disabled. If it looks active, but doesn't interact, I'm going to be mad at your app.
Regardless, to answer your question, you should look at StateListDrawable this question outlines it specifically for seek bars.
Better solution here....
seekBar.setOnTouchListener(new OnTouchListener(){
#Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
You can use setEnabled(false) and set the Theme_disabledAlpha attribute as #Ilya Pikin mentioned above like this:
<item name="android:disabledAlpha">1.0</item>
Android changes alpha value of color to 127 from 255 in disabled state. Just make sure you set it back to 255 after disabling seekbar.
seekBar.post(new Runnable(){
#Override
public void run()
{
seekBar.getProgressDrawable().setAlpha(255);
}
});
view.post is required only if you are unsure that seekbar is rendered yet or not, otherwise just
seekBar.getProgressDrawable().setAlpha(255);
is enough.
I´m a bit late to the party, but here is a solution to solve your question.
First of all I recommand to use com.google.android.material.slider.Slider nowadays. It is much more flexible than the old seekbar was. To do so, use the following import in your gradle file
implementation 'com.google.android.material:material:1.6.0' //1.4.0 or newer
Now create your layout file, let´s it call layout_slider
e.g.:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/white">
<com.google.android.material.slider.Slider
android:id="#+id/sbSize"
style="#style/sliderTheme"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:value="25"
android:valueFrom="0.0"
android:valueTo="100.0"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Now open your styles.xml file and create the sliderTheme. It should look like this:
<style name="sliderTheme" parent="Widget.MaterialComponents.Slider">
<item name="trackColorInactive">#color/slider_track_inactive</item>
<item name="thumbColor">#color/slider_thumb_color</item>
<item name="trackColorActive">#color/slider_track_active</item>
</style>
The next step we need to do is create a new Resource Directory named color inside the res folder. (Resource type is color)
Now create a file to change the trackColor for active and inactive state. Let´s name it slider_track_inactive.xml
Copy the following content inside that file:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:alpha="0.24" android:color="?attr/colorPrimary" android:state_enabled="true"/>
<item android:alpha="0.12" android:color="?attr/colorOnSurface"/>
</selector>
the first value is for the active and the second is for the inactive color. Change alpha and color to a value to want. All my sample values are the Google default values.
Now create a file called slider_thumb_color.xml inside the color folder. It should look like this:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="?attr/colorPrimary" android:state_enabled="true"/>
<item android:alpha="0.38" android:color="?attr/colorOnSurface"/>
</selector>
Again, change these values as you want.
Last, create a file called slider_track_active.xml inside the color folder. It should look like this:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="?attr/colorPrimary" android:state_enabled="true"/>
<item android:alpha="0.32" android:color="?attr/colorOnSurface"/>
</selector>
Now you have customized all colors for the disabled slider. There are much more values you can customize with the same technique. All default keys you can customize inside your styles.xml file are:
<item name="haloColor">#color/material_slider_halo_color</item>
<item name="haloRadius">#dimen/mtrl_slider_halo_radius</item>
<item name="labelStyle">#style/Widget.MaterialComponents.Tooltip</item>
<item name="thumbColor">#color/material_slider_thumb_color</item>
<item name="thumbElevation">#dimen/mtrl_slider_thumb_elevation</item>
<item name="thumbRadius">#dimen/mtrl_slider_thumb_radius</item>
<item name="tickColorActive">#color/material_slider_active_tick_marks_color</item>
<item name="tickColorInactive">#color/material_slider_inactive_tick_marks_color</item>
<item name="trackColorActive">#color/material_slider_active_track_color</item>
<item name="trackColorInactive">#color/material_slider_inactive_track_color</item>
<item name="trackHeight">#dimen/mtrl_slider_track_height</item>
<item name="minSeparation">0dp</item>
There's a question for the same functionality on Blackberry, and a few different threads referred to this bug (which has since been closed without resolution as far as I can tell), but I haven't found one specifically for Android.
I'm calling setEnabled(false) on certain MenuItems based on some state, but they visually look the same. I'd like them to be offset in some way, so that the user knows that the option currently isn't available -- is there any way to do that?
On all android versions, easiest way to use this to SHOW a menu action icon as disabled AND make it FUNCTION as disabled as well:
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
MenuItem item = menu.findItem(R.id.menu_my_item);
if (myItemShouldBeEnabled) {
item.setEnabled(true);
item.getIcon().setAlpha(255);
} else {
// disabled
item.setEnabled(false);
item.getIcon().setAlpha(130);
}
}
I had the same issue. There are two ways of getting this to work:
Put your icons in a StateList so that a different icon will be used on disable
What I use now. Change the icon yourself with something like this in onPrepareOptionsMenu():
public boolean onPrepareOptionsMenu(Menu menu) {
boolean menusEnabled = reachedEndOfSlidehow(); // enable or disable?
MenuItem item = menu.findItem(R.id.menu_next_slide);
Drawable resIcon = getResources().getDrawable(R.drawable.ic_next_slide);
if (!menusEnabled)
resIcon.mutate().setColorFilter(Color.GRAY, PorterDuff.Mode.SRC_IN);
item.setEnabled(menusEnabled); // any text will be automatically disabled
item.setIcon(resIcon);
}
You can call invalidateOptionsMenu() (or from ABS, supportInvalidateOptionsMenu()) to rebuild the menu.
EDIT: Updated solution 2
Source: https://groups.google.com/forum/?fromgroups#!topic/actionbarsherlock/Z8Ic8djq-3o
I found a new way to solve this issue using a drawable selector xml file. You just create a selector with the icon you want to use in your menu item, then you can either change the tint, alpha or both of the bitmap:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="true">
<bitmap android:src="#drawable/ic_menu_item"
android:tint="#color/enabled_color"
android:alpha="#integer/enabled_alpha"/>
</item>
<item android:state_enabled="false">
<bitmap android:src="#drawable/ic_menu_item"
android:tint="#color/disabled_color"
android:alpha="#integer/disabled_alpha"/>
</item>
</selector>
As a side note; I like to set the tint to "?android:attr/textColorPrimary" for enabled state and "?android:attr/textColorHint" for disabled state. This way it will adjust depending on the theme used.
Then you can just set the icon in your menu xml file to the selector resource:
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="#+id/menu_action"
android:orderInCategory="0"
android:title="#string/title_menu_action"
android:icon="#drawable/ic_menu_item_selector"
app:showAsAction="ifRoom"/>
</menu>
Then when you call item.setEnabled(enabled) the color and/or alpha of the icon will change along with the state!
The way I did it is by using "itemIconTint" in NavigationView, you can also grey out the text by using "itemTextColor"
This is Navigationview:
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:itemBackground="#color/white"
android:background="#color/white"
app:itemTextColor="#color/menu_text_color"
app:itemIconTint="#color/menu_text_color"
app:menu="#menu/main_drawer" />
and the "#color/menu_text_color" is a selector:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:color="#color/primaryColor" />
<item android:state_enabled="false" android:color="#color/disabled_text_color" />
<item android:color="#color/primaryText" />
</selector>
Finally, if you want to disable a menuitem,
MenuItem item = mNavigationView.getMenu().findItem(R.id.your_menu_item);
item.setEnabled(isEnable);
Done!
I was having difficulty with this on modern android with MaterialComponents theme. My problem was I had set <item name="actionMenuTextColor">#color/blue</item> in styles.xml and this overrides the text color whether the item is enabled or disabled. The solution is to set a Color state list and not a color directly.
My styles attribute now looks like:
<item name="actionMenuTextColor">#color/menu_color_selector</item>
I had an issue where neither my the text nor the icon was visibly changing. The other answers either didn't work for me or weren't very elegant. Here's an answer that works for the latest Material recommendations.
You should be able to simply call menu.findItem(R.id.menu_my_item).isEnabled = false in onPrepareOptionsMenu(menu: Menu).
(If you need onPrepareOptionsMenu to run again, you can simply call invalidateOptionsMenu() or activity?.invalidateOptionsMenu() (from a fragment) and the application will queue up the menu to be recreated. Alternatively you can store off the menu item in a member variable to modify it later, but be careful to destroy your reference to it within onDestroyOptionsMenu to avoid a memory leak.)
The fact that the menu item is disabled should be enough to grey out the text or the icon automatically. The difficulty is in setting up your styles to make this work.
Short Answer
First create a color state list my_color_state_list.xml that you want your icons and text to use (e.g. black when enabled, grey when disabled). (See the full answer for an example.)
If you're using com.google.android.material.appbar.MaterialToolbar, you can tell it to use this selector for icons and text by providing a custom theme overlay. In your activity's XML, give the toolbar the attribute android:theme="#style/Foo" and define that style somewhere as:
<style name="Foo">
<item name="colorControlNormal">#color/my_color_state_list</item>
<item name="actionMenuTextColor">#color/my_color_state_list</item>
</style>
Now when the menu item is enabled or disabled via menu.findItem(R.id.menu_my_item).isEnabled = false the text will automatically change color, and any icons which use the color ?attr/colorControlNormal will also automatically change color.
Full answer
My starting place
My menu items are part of a Material toolbar. This answer may help for other kinds of toolbar/app bar, but your mileage may vary. In my activity I have something like this:
<com.google.android.material.appbar.MaterialToolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:theme="#style/ThemeOverlay.MaterialComponents.Toolbar.Surface"/>
and the theme I'm using looks something like this:
<style name="Theme.MyApp" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<item name="colorPrimary">#color/blue</item>
<item name="colorSecondary">#color/green</item>
<item name="colorSurface">#color/lightGrey</item>
<item name="colorOnSurface">#color/black</item>
[...]
<item name="windowActionModeOverlay">true</item>
</style>
It is also convention that the icon you use in buttons and menu items (and everywhere really) should have their default color be ?attr/colorControlNormal. So for example I might have a vector image which looks like:
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal"
android:tintMode="src_atop">
<path android:pathData="..." android:fillColor="#android:color/white"/>
</vector>
If you download an icon from Material Icons you will see they all use colorControlNormal.
What I needed to do
If you look back at the definition of my toolbar, you will see it uses a ThemeOverlay ThemeOverlay.MaterialComponents.Toolbar.Surface which is defined as:
<style name="ThemeOverlay.MaterialComponents.Toolbar.Surface" parent="">
<item name="colorControlNormal">#color/material_on_surface_emphasis_medium</item>
<item name="actionMenuTextColor">#color/material_on_surface_emphasis_medium</item>
</style>
This sets the menu item text color and icon color to #color/material_on_surface_emphasis_medium which does not respond to being enabled or not. #color/material_on_surface_emphasis_medium looks like:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:alpha="#dimen/material_emphasis_medium" android:color="?attr/colorOnSurface"/>
</selector>
(You may be using ThemeOverlay.MaterialComponents.Toolbar.Primary instead, which has a similar issue - it simply uses colorOnPrimary.)
We need to replace this with our own color state list which responds to enabled state. So, make a new file res/color/menu_item_selector.xml that looks something like this:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="true" android:alpha="#dimen/material_emphasis_medium" android:color="?attr/colorOnSurface"/>
<item android:alpha="#dimen/material_emphasis_disabled" android:color="?attr/colorOnSurface"/>
</selector>
You see I've used the same conventions that the material library does by using their constants to define the alpha values, and I used colorOnSurface as my color. If you were using ThemeOverlay.MaterialComponents.Toolbar.Primary you would want colorOnPrimary instead. Of course you can use any color or alpha here, it's up to you.
And now make a new ThemeOverlay in res/values/styles.xml to point to this selector, inheriting from whatever ThemeOverlay you were using:
<!-- Toolbar - overrides the menu text color to use a selector that responds to whether it's enabled or not -->
<style name="ThemeOverlay.MyTheme.Toolbar" parent="ThemeOverlay.MaterialComponents.Toolbar.Surface">
<!-- Color used in the icons of menu actions (i.e. non-overflow menu items). This is just convention, this will affect anything that uses ?attr/colorControlNormal) -->
<item name="colorControlNormal">#color/menu_item_color_selector</item>
<!-- Color used in the text of menu actions (i.e. non-overflow menu items) -->
<item name="actionMenuTextColor">#color/menu_item_color_selector</item>
</style>
And now finally we can apply this ThemeOverlay to the toolbar:
<com.google.android.material.appbar.MaterialToolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:theme="#style/ThemeOverlay.MyTheme.Toolbar"/>
setEnabled(false) works fine on API Level < 14 but on 14 the item still clickable.
Have a look at this link
setEnabled can also be used for MenuItems.
Here's a simple way to do it (using Kotlin):
fun changeMenuItemColour(enabled: Boolean) {
var menuItem = SpannableString(mCustomToolbar?.menu?.findItem(R.id.some_menu_item)?.title)
var style = activity?.resources?.getColor(R.color.darkGraphite)!!
if (enabled) style = activity?.resources?.getColor(R.color.black)!!
menuItem.setSpan(ForegroundColorSpan(style), 0, menuItem.length, 0)
}