Prevent my android:theme from modifying dialogs? - android

My theme gives my app black text and yellow background, this works but I noticed it was also affecting AlertDialogs and making them look buggy.
I want to ensure my app theme only modifies Activities and Fragment's parent layout, but not dialogs or toasts. How can I restore them so they use the phone's default styling?
This is what I'm trying:
<style name="MyTheme" parent="android:style/Theme.Holo.NoActionBar.Fullscreen">
<!-- Colors -->
<item name="android:textColor">#000000</item>
<item name="android:background">#fffdf12a</item>
<!-- Restore Dialogs to default style -->
<item name="android:alertDialogStyle"></item>
</style>

According to my knowledge you can't do that for Dialogs created by System, like the ones in the Preferences but you can change of Dialogs which you create from sratch
Here's what I found from another answer :
protected AlertDialog(Context context) {
this(context, com.android.internal.R.style.Theme_Dialog_Alert);
}
public Builder(Context context) {
this(context, com.android.internal.R.style.Theme_Dialog_Alert);
}
You can see the values are Hardcoded & hence can't be changed

Related

How can you locate the default style for a widget (i.e. AppCompatEditText)

UPDATE: As pointed out in the comments, 'Widget.AppCompat.EditText' is the correct parent style for an AppCompatEditText subclass. In my case, the real issue was I had forgotten to assign a value to our control's default style attribute in our theme, so our control wasn't getting any style to use as a default.
However, this question still could use an answer as to how one properly identifies which style to use as a parent when defining your own default styles when subclassing the standard controls. As such, I've also renamed its title.
As such, I'm leaving this open in hopes someone can answer that question since it will help any who wish to do something similar.
We're trying to define a common look-and-feel for all AppCompatEditText controls used throughout the app. As such, rather than having to manually apply the 'style' attribute on each usage, we're instead trying to replace the default style with our own.
Replacing the default style is actually the easy part. What isn't is knowing what the parent style for our style should be set to so we still have all aspects of the original style which we haven't explicitly overwritten with those in ours.
Digging in the source code for AppCompatEditText, it shows the default style to be stored in R.attr.editTextStyle but I'm not sure where now to look to see what value is stored in it.
Experimenting too didn't get us anywhere. No matter what we have tried so far, we lose the default appearance completely. No underline, no background, no padding, nothing. Just the values we've set, which means it's not picking up the parent style.
We've tried the following without success...
<style name="ZinEditText" parent="android:Widget.EditText">
<item name="zinTypeface">light</item>
<item name="android:textSize">#dimen/defaultTextSize</item>
<item name="android:lineSpacingMultiplier">#dimen/defaultLineSpacing</item>
</style>
<style name="ZinEditText" parent="Widget.AppCompat.EditText">
<item name="zinTypeface">light</item>
<item name="android:textSize">#dimen/defaultTextSize</item>
<item name="android:lineSpacingMultiplier">#dimen/defaultLineSpacing</item>
</style>
<style name="ZinEditText" parent="Base.V7.Widget.AppCompat.EditText">
<item name="zinTypeface">light</item>
<item name="android:textSize">#dimen/defaultTextSize</item>
<item name="android:lineSpacingMultiplier">#dimen/defaultLineSpacing</item>
</style>
<style name="ZinEditText" parent="Widget.Holo.EditText">
<item name="zinTypeface">light</item>
<item name="android:textSize">#dimen/defaultTextSize</item>
<item name="android:lineSpacingMultiplier">#dimen/defaultLineSpacing</item>
</style>
As I said, none of the above seemed to work.
So how does one find the actual parent style to use?
To address the immediate issue, the default style for an AppCompatEditText is Widget.AppCompat.EditText. The second example you've shown is the correct one:
<style name="ZinEditText" parent="Widget.AppCompat.EditText">
...
This needs to be set as the editTextStyle in your app theme.
<style name="AppTheme" parent="#style/Theme.AppCompat">
<item name="editTextStyle">#style/ZinEditText</item>
...
Finding these default styles and attributes is not well documented anywhere officially, as far as I'm aware. The official documentation for Styles and Themes simply directs one to the various R.attr pages for the framework and support packages, to "discover" what's available. However, a generally reliable way to find this for most Views that allow a default style is to inspect the source code.
A View subclass will often implement at least three constructors: one that takes only a Context; one that takes a Context and an AttributeSet; and one that takes a Context, an AttributeSet, and an int for defStyleAttr, a default style attribute. This attribute is what we're looking for. It will usually have a sensible name, like editTextStyle, textViewStyle, checkboxStyle, etc. If you already know the name, you can skip checking the View class for it.
In Views that chain their constructors, this attribute will be normally be in the call to the three-parameter constructor from the two-parameter one. In AppCompatEditText, we can see that the name of this attribute is editTextStyle.
public AppCompatEditText(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.editTextStyle);
}
After we've got the name for the attribute, we then head to the res/values/ directory for the platform or support package the View is in. The default value will be in the relevant themes*.xml file for your app's parent theme.
For the platform themes, there is a base themes.xml, and a few others for specific theme versions, such as Holo and Material.
For support library Views, these theme files will be under the package-specific res/values/ directory, and the default attribute value may be in themes.xml or themes_base.xml.
In v7 appcompat, our app's exact parent theme is likely in v7/appcompat/res/values/themes.xml, though most of the themes there are just direct aliases for base themes; i.e., they don't override any of their parents' attribute values. The default for AppCompatEditText is actually in v7/appcompat/res/values/themes_base.xml. There are separate entries for different themes - the regular, and the light - but they are both the same.
<item name="editTextStyle">#style/Widget.AppCompat.EditText</item>
This is enough to determine which style to use as our parent, but should we want to check out the style specifics, we can then refer to v7/appcompat/res/values/styles.xml, where we find that style's parent:
<style name="Widget.AppCompat.EditText" parent="Base.Widget.AppCompat.EditText"/>
which leads us to v7/appcompat/res/values/styles_base.xml:
<style name="Base.Widget.AppCompat.EditText" parent="Base.V7.Widget.AppCompat.EditText" />
<style name="Base.V7.Widget.AppCompat.EditText" parent="android:Widget.EditText">
<item name="android:background">?attr/editTextBackground</item>
<item name="android:textColor">?attr/editTextColor</item>
<item name="android:textAppearance">?android:attr/textAppearanceMediumInverse</item>
</style>

Theme style for custom view

My app has several themes from which the user can chose (red, blue, green etc.) Every theme has a corresponding button style (RedTheme => RedButton).
Now I have created a custom view which slightly extends "Button" and unfortunately this button does not get any style, except I use the "style" attribute in a layout.xml.
I don’t use any additional attributes, I just want that my Button style is applied.
I want to do something similar than:
<item name="android:imageButtonStyle">#style/ImageButtonmyTimeRed</item>
I have already read many other posts like this one:
How to: Define theme (style) item for custom widget
but I’m not 100% sure if this solution fits for me since I don’t need any additional attributes.
I'm using the three parameter super constructor and pass the button style resource id. This works for all my custom themes. Thanks #pskink for pointing me into right direction.
public ClockButton(Context context, AttributeSet attrs) {
super(context, attrs, R.attr.buttonStyle);
...
}
My theme looks like this:
<style name="LilaTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="buttonStyle">#style/ButtonmyTimeLila</item>
</style>

How to switch themes (night mode) without restarting the activity?

I have made a few apps that support multiple themes, but I always had to restart the app when user switches theme, because setTheme() needs to be called before setContentView().
I was okay with it, until I discovered this app. It can seamlessly switch between two themes, and with transitions/animations too!
Please give me some hints on how this was implemented (and animations too). Thanks!
#Alexander Hanssen's answer basically has answered this...
Don't know why it was not accepted... Maybe because of the finish()/startActivity().
I voted for it and I tried to comment but cannot...
Anyway, I would do exactly what he described in terms of styles.
<style name="AppThemeLight" parent="Theme.AppCompat.Light">
<!-- Customize your theme here. -->
<item name="android:windowAnimationStyle">#style/WindowAnimationTransition</item>
</style>
<style name="AppThemeDark" parent="Theme.AppCompat">
<!-- Customize your theme here. -->
<item name="android:windowAnimationStyle">#style/WindowAnimationTransition</item>
</style>
<!-- This will set the fade in animation on all your activities by default -->
<style name="WindowAnimationTransition">
<item name="android:windowEnterAnimation">#android:anim/fade_in</item>
<item name="android:windowExitAnimation">#android:anim/fade_out</item>
</style>
But instead of finish/start with new intent:
Intent intent = new Intent(this, <yourclass>.class);
startActivity(intent);
finish();
I would do:
#Override
protected void onCreate(Bundle savedInstanceState) {
// MUST do this before super call or setContentView(...)
// pick which theme DAY or NIGHT from settings
setTheme(someSettings.get(PREFFERED_THEME) ? R.style.AppThemeLight : R.style.AppThemeDark);
super.onCreate(savedInstanceState);
}
// Somewhere in your activity where the button switches the theme
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// decide which theme to use DAY or NIGHT and save it
someSettings.save(PREFFERED_THEME, isDay());
Activity.this.recreate();
}
});
The effect is as shown in the video...
The transition/animation makes the theme change seamless when you restart the activity, and this can be done by adding the items "android:windowanimationStyle" to your themes, and then referencing a style where you specifiy how the Activity should animate when it enters and exits.
Note that this makes the animation apply on all activities with that theme.
<style name="AppThemeLight" parent="Theme.AppCompat.Light">
<!-- Customize your theme here. -->
<item name="android:windowAnimationStyle">#style/WindowAnimationTransition</item>
</style>
<style name="AppThemeDark" parent="Theme.AppCompat">
<!-- Customize your theme here. -->
<item name="android:windowAnimationStyle">#style/WindowAnimationTransition</item>
</style>
<!-- This will set the fade in animation on all your activities by default -->
<style name="WindowAnimationTransition">
<item name="android:windowEnterAnimation">#android:anim/fade_in</item>
<item name="android:windowExitAnimation">#android:anim/fade_out</item>
</style>
Then, when you want to change theme you could do this when clicking a button:
AppSettings settings = AppSettings.getInstance(this);
settings.set(AppSettings.Key.USE_DARK_THEME,
!settings.getBoolean(AppSettings.Key.USE_DARK_THEME));
Intent intent = new Intent(this, <yourclass>.class);
startActivity(intent);
finish();
Then in your onCreate method, use the setTheme() to apply the theme that is currently set in AppSettings like this:
AppSettings settings = AppSettings.getInstance(this);
setTheme(settings.getBoolean(AppSettings.Key.USE_DARK_THEME) ? R.style.AppThemeDark : R.style.AppThemeLight);
super.onCreate(savedInstanceState);
setContentView(<yourlayouthere>);
Check out this gist for reference: https://gist.github.com/alphamu/f2469c28e17b24114fe5
for those who are trying to find solution for android version 10 or updated.
to set dark/light mode use this:
AppCompatDelegate.setDefaultNightMode(state) //state can be AppCompatDelegate.MODE_NIGHT_YES or AppCompatDelegate.MODE_NIGHT_NO
it will change the display of your app but with a flicker
to avoid the activity recreation flicker (for smooth transition), in your activity add the below method
#Override
public void recreate() {
finish();
overridePendingTransition(R.anim.anime_fade_in,
R.anim.anime_fade_out);
startActivity(getIntent());
overridePendingTransition(R.anim.anime_fade_in,
R.anim.anime_fade_out);
}
setTheme() before super.onCreate(savedInstanceState) in GKA answer is perfect approach and work well, thanks to GKA.
but it creates new instances for all resources again, including activities, fragments, and recycler views. I think it may be heavy work and cause to loss of some saved data like local variables.
accourding to google document: https://developer.android.com/reference/android/app/Activity#recreate()
Cause this Activity to be recreated with a new instance. This results
in essentially the same flow as when the Activity is created due to a
configuration change -- the current instance will go through its
lifecycle to onDestroy() and a new instance then created after it.
there is another approach that you can change the theme programmatically with code (Java or Kotlin), in this approach you don't need to recreate all resources, and also you can use custom animation like ripple.
check my GitHub library:
https://github.com/imandolatkia/Android-Animated-Theme-Manager
in this library, you can create your custom themes and change them dynamically with ripple animation without recreating any resources.
Simply efficient one liner in fragment:
requireActivity().recreate();
For activity:
recreate();
There isn't anything preventing you from calling setTheme() and then setContentView() again. You'll just need to restructure your app a bit so that, if you change the theme, you need to reinitialize any member variables you might have that are holding references to View objects.

Why is Cast MediaRouteButton always white even on Holo.Light Action-Bar?

I'm moving from a custom MediaRouteButton to one inside the action-bar but it doesn't display properly. The button when custom was white which is what I wanted. However, the button is still white (and barely visible) on the action-bar even though the action-bar is of "Holo.Light" style. The button should be dark.
The button is created as an XML menu item:
<item
android:id="#+id/menu_item_media_route"
android:title="#string/menu_item_media_route"
android:actionViewClass="android.support.v7.app.MediaRouteButton"
android:actionProviderClass="android.support.v7.app.MediaRouteActionProvider"
android:showAsAction="always" />
My app is of style "#style/AppTheme":
<style name="AppTheme" parent="android:Theme.Holo.Light">
</style>
My activity of of theme "#style/FullscreenActionbarTheme":
<style name="FullscreenActionbarTheme" parent="android:Theme.Holo.Light">
<item name="android:windowFullscreen">true</item>
<item name="android:windowActionBarOverlay">true</item>
<item name="android:windowContentOverlay">#null</item>
<item name="android:windowBackground">#null</item>
<item name="android:actionBarStyle">#style/FullscreenActionbar</item>
</style>
<style name="FullscreenActionbar" parent="#android:style/Widget.Holo.Light.ActionBar.Solid">
</style>
I have no custom "ic_media_route_(on|off).png" drawables -- I used to but removed them.
I've tried changing various styles and though the action-bar will turn dark, the cast button is always white. (As it should be on a dark action bar but not a light one.)
The button is fully functional, just the wrong color. The "chooser" dialog that appears when I press the button is styled "Holo.Light".
So why is my cast button colored white on a "Holo.Light" theme as though it was a "Holo" (dark) theme?
Taken from: Link
Caution: When implementing an activity that provides a media router
interface you must extend either ActionBarActivity or FragmentActivity
from the Android Support Library, even if your android:minSdkVersion
is API 11 or higher.
ActionBarActivity has been superseded by AppCompatActivity, so you should use that instead.
Support-V7 MediaRouteButton depends on this. Look at the super call:
public MediaRouteButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(MediaRouterThemeHelper.createThemedContext(context), attrs, defStyleAttr);
....
....
}
MediaRouterThemeHelper.createThemedContext(Context):
public static Context createThemedContext(Context context) {
boolean isLightTheme = isLightTheme(context);
return new ContextThemeWrapper(context, isLightTheme ?
R.style.Theme_MediaRouter_Light : R.style.Theme_MediaRouter);
}
isLightTheme is set by resolving R.attr.isLightTheme <<== This is a support library attribute. It will not be present when your parent theme is provided by the framework, as is the case with android:Theme.Holo.Light.
private static boolean isLightTheme(Context context) {
TypedValue value = new TypedValue();
return context.getTheme().resolveAttribute(R.attr.isLightTheme, value, true)
&& value.data != 0;
}
So, isLightTheme is false & you get the dark-theme version of MediaRouteButton ==> ... always white.
Note that the Caution statement implies that your parent theme must be an AppCompat theme - AppCompatActivity (or ActionBarActivity) can't work with android:Theme.*.
Edit:
A lot of discussion took place here: Link
One can go through the chat-log to read on the approaches tried. In the end, it seems that the media-router support library needs some work to be production-ready. Read more here: MediaRouteActionProvider connection dialog theme.
If all else fails you can change the color programmatically in onCreate():
ImageButton button = ((ImageButton) toolbar.getChildAt( ... )); // The view index of the button
button.setColorFilter(Color.BLACK, PorterDuff.Mode.MULTIPLY);

Run a custom Dialog layout using Theme/Style

I need to run a custom dialog layout using only theme/style options. Running custom Dialog layout by code is not an option for me. I think this should be possible by mean of attributes "android:layout", "android:dialogLayout", "*android:dialogCustomTitleDecorLayout", "*android:dialogTitleIconsDecorLayout", "*android:dialogTitleDecorLayout".<br/><br/>
My Activity onCreate load layout in a Dialog Style:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTheme(R.style.MyDialog);
setContentView(R.layout.mydialog);
this.setTitle("A title");
}
style xml:
<style name="MyDialog" parent="android:Theme.Holo.Light.Dialog">
<item name="android:windowTitleStyle">#style/MyDialog.WindowTitle</item>
<item name="android:layout">#layout/dialog_title</item>
<item name="android:dialogLayout">#layout/dialog_title</item>
<item name="*android:dialogCustomTitleDecorLayout">#layout/dialog_title</item>
<item name="*android:dialogTitleIconsDecorLayout">#layout/dialog_title</item>
<item name="*android:dialogTitleDecorLayout">#layout/dialog_title</item>
</style>
<style name="MyDialog.WindowTitle">
<item name="android:maxLines">1</item>
<item name="android:scrollHorizontally">true</item>
<item name="android:textAppearance">#style/TextAppearance_WindowTitle</item>
</style>
<style name="TextAppearance_WindowTitle">
<item name="android:textSize">32sp</item>
<item name="android:textColor">#+color/verdeTI</item>
</style>
Please, note that Text colour of the title is correctly applied (#+color/verdeTI) so I am confident the cascading styling is right but it seems none of the layout options work at all because I continue to see the standard Dialog Layout. My "dialog_title" use a completely different ImageView for divider so I can be sure when it is loaded.
The custom divider is just the main reason because I need a different layout.
Update 15/4/2014
Android theme Guide stats:
Some style properties, however, are not supported by any View element and can only be applied as a theme. These style properties apply to the entire window and not to any type of View. For example, style properties for a theme can hide the application title, hide the status bar, or change the window's background. These kind of style properties do not belong to any View object. To discover these theme-only style properties, look at the R.attr reference for attributes that begin with window. For instance, windowNoTitle and windowBackground are style properties that are effective only when the style is applied as a theme to an Activity or application. See the next section for information about applying a style as a theme.
OK attributes starting with "window" are applied only in Themes not in Styles. What's about *Layout attributes ? When they are applied ?
You can try by passing ThemeName as argument of constructor like this way.
public class TestDialog extends Dialog{
public TestDialog(Context context) {
super(context, R.style.YourTheme);
// TODO Auto-generated constructor stub
}
}
Add window feature if you require.
Make object of this class in any Activity so you can use Dialog property.
:-
More info https://stackoverflow.com/a/18224754/942224
i was using this way. so it may be help you.
You can try by creating your required layout file and opening it with an activity class just in the manifest add this code to your activity
android:theme="#android:style/Theme. Dialog"
But you will be getting title bar in your dialog with this which is your label name for your activity. To remove it add this code before setContentView
requestWindowFeature(Window. FEATURE_NO_TITLE);

Categories

Resources