How to style PopupMenu and AlertDialog with theme.xml and style.xml - android

I want to skin my Android App with multiple Color Themes.
This Guides/Tools helped me to generate the basic theme.xml and style.xml
http://android-holo-colors.com
http://jgilfelt.github.io/android-actionbarstylegenerator
http://blog.stylingandroid.com/archives/1240
But i cant figure it out to style the PopupMenu and AlertDialog Header?
I want to change only the Color to streamline with my App Theme!
Example:
to look like
I’m using Theme.Holo and Android SDK 21.1 RC3/Tools 16.0. I've tried a lot with styles and themes but nothing worked

public class AlertDialogThemed extends AlertDialog {
public AlertDialogThemed(Context context) {
super(context);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Resources resources = getContext().getResources();
final int color = resources.getColor(R.color.dialog_color);
final View title = findViewById(resources.getIdentifier("alertTitle", "id", "android"));
if (title != null) {
((TextView) title).setTextColor(color);
}
final View titleDivider = findViewById(resources.getIdentifier("titleDivider", "id", "android"));
if (titleDivider != null) {
titleDivider.setBackgroundColor(color);
}
}
}

Related

Change theme dynamically for multiple view - Android

I am trying change theme when the app device is offline. But to achieve changing the background color is not gonna help and i needed to change the whole view and the text colors. But for that getting all the view with FindViewById is not an effective method to achieve that as I got lots of views to the Activity and as i tried using Themes
<item name="android:textColor">#android:color/black</item>
<item name="android:windowBackground">#android:color/white</item>
But as it shows only one colored TextView I cant use this method to activity as it has multiple colors and changing theme has to be done before you create the activity.
Please provide a solution which supports changing theme with multiple colored View
public class Utils {
private static int sTheme;
public final static int THEME_MATERIAL_LIGHT = 0;
public final static int THEME_YOUR_CUSTOM_THEME = 1;
public static void changeToTheme(Activity activity, int theme) {
sTheme = theme;
activity.finish();
activity.startActivity(new Intent(activity, activity.getClass()));
activity.overridePendingTransition(android.R.anim.fade_in,
android.R.anim.fade_out);
}
public static void onActivityCreateSetTheme(Activity activity) {
switch (sTheme) {
default:
case THEME_MATERIAL_LIGHT:
activity.setTheme(R.style.Theme_Material_Light);
break;
case THEME_YOUR_CUSTOM_THEME:
activity.setTheme(R.style.Theme_YOUR_CUSTOM_THEME);
break;
}
}
}
In Your Activity:
#Override // Any Activity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// MUST BE SET BEFORE setContentView
Utils.onActivityCreateSetTheme(this);
// AFTER SETTING THEME
setContentView(R.layout.activity_theme);
}

Apply Color Filter to Action Overflow Icon at Runtime

Is there any way to get the Action bar overflow icon drawable at runtime to apply a color filter? I'm looking for something similar to menu.findItem(R.id.menu_id).getIcon() except for the 3 dot overflow so that I can do a .setColorFilter.
Thanks!
Yes, there is a way. You just have to find overflow icon in view hierarchy. One good way is searching in ViewGroup returned by getDecorView(). You can search for it using findViewsWithText with flag FIND_VIEWS_WITH_CONTENT_DESCRIPTION.
Sample code:
public static void setOverflowButtonColor(final Activity activity, final int visibleFontColor) {
final String overflowDescription = activity.getString(R.string.abc_action_menu_overflow_description);
final ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
final ViewTreeObserver viewTreeObserver = decorView.getViewTreeObserver();
viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
final ArrayList<View> outViews = new ArrayList<View>();
decorView.findViewsWithText(outViews, overflowDescription, View.FIND_VIEWS_WITH_CONTENT_DESCRIPTION);
if (outViews.isEmpty()) {
return;
}
TintImageView overflow = (TintImageView) outViews.get(0);
overflow.setColorFilter(Color.CYAN);
removeOnGlobalLayoutListener(decorView, this);
}
});
}
public static void removeOnGlobalLayoutListener(View v, ViewTreeObserver.OnGlobalLayoutListener listener) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
v.getViewTreeObserver().removeGlobalOnLayoutListener(listener);
}
else {
v.getViewTreeObserver().removeOnGlobalLayoutListener(listener);
}
}
For more details see my answer in similar question: https://stackoverflow.com/a/27672844/2707179
You cant get the OverflowIcon within the onCreateOptionsMenu, but you can still change the appearance of it at runtime so instead of applying a filter on it programatically you can create your own OverflowIcon image instead.
sample:
You can change the overflow icon within the style of your activity
<style name="YOUR_THEME" parent="android:style/Theme.Holo.Light">
<item name="android:actionOverflowButtonStyle">#style/CustomOverflow</item>
</style>
<style name="CustomOverflow" parent="android:style/Widget.Holo.ActionButton.Overflow">
<item name="android:src">#drawable/your_custom_overflow_image</item>
</style>

Android Theming Preference Dialog

I have an application that uses a preference activity to set some user settings. I been trying to figure this out all day. I am trying to theme the alert dialog when an user presses an Edit Text Preference object. A dialog opens up and the user can set the shared preference. The dialog pops up:
I want the text green. I want the divider green. The line and cursor green.
This is what I have so far.
<style name="CustomDialogTheme" parent="#android:style/Theme.Dialog">
<item name="android:background">#color/text_green</item>
<item name="android:textColor">#color/text_green</item>
</style>
Can someone point me in the right direction or maybe share some code. I am at lost. I've been surfing the net to find something most of the day. Thanks in advance.
If you don't want to create a custom layout or use a third party library, you can subclass EditTextPreference, then access each View you want to edit by using Resources.getIdentifier then using Window.findViewById. Here's a quick example.
public class CustomDialogPreference extends EditTextPreference {
public CustomDialogPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public CustomDialogPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
/**
* {#inheritDoc}
*/
#Override
protected void showDialog(Bundle state) {
super.showDialog(state);
final Resources res = getContext().getResources();
final Window window = getDialog().getWindow();
final int green = res.getColor(android.R.color.holo_green_dark);
// Title
final int titleId = res.getIdentifier("alertTitle", "id", "android");
final View title = window.findViewById(titleId);
if (title != null) {
((TextView) title).setTextColor(green);
}
// Title divider
final int titleDividerId = res.getIdentifier("titleDivider", "id", "android");
final View titleDivider = window.findViewById(titleDividerId);
if (titleDivider != null) {
titleDivider.setBackgroundColor(green);
}
// EditText
final View editText = window.findViewById(android.R.id.edit);
if (editText != null) {
editText.setBackground(res.getDrawable(R.drawable.apptheme_edit_text_holo_light));
}
}
}
Implementation
Replace <EditTextPreference.../> with <path_to_CustomDialogPreference.../> in your xml.
Note
I used Android Holo Colors to create the background for the EditText.
You can build your custom layout for your own dialog theme using your own customized components or you can use external libs, for example android-styled-dialogs
So in this case use can customize dialogs as you want:
<style name="DialogStyleLight.Custom">
<!-- anything can be left out: -->
<item name="titleTextColor">#color/dialog_title_text</item>
<item name="titleSeparatorColor">#color/dialog_title_separator</item>
<item name="messageTextColor">#color/dialog_message_text</item>
<item name="buttonTextColor">#color/dialog_button_text</item>
<item name="buttonSeparatorColor">#color/dialog_button_separator</item>
<item name="buttonBackgroundColorNormal">#color/dialog_button_normal</item>
<item name="buttonBackgroundColorPressed">#color/dialog_button_pressed</item>
<item name="buttonBackgroundColorFocused">#color/dialog_button_focused</item>
<item name="dialogBackground">#drawable/dialog_background</item>
</style>

How to remove border from Dialog?

I have an activity which is shown in a dialog:
In order to remove border and rounded corners, i tried this:
<resources>
<style name="ActivityDialog" parent="#android:style/Theme.Dialog">
<item name="android:windowBackground">#null</item>
<item name="android:windowFrame">#null</item>
</style>
The border is gone, but sadly also the margin around the dialog.
Without creating a custom background drawable and adding a special style just add one line to your code:
dialog.getWindow().setBackgroundDrawableResource(android.R.color.transparent);
The border, round corners and margin are all defined by android:windowBackground. (Parameter android:windowFrame is already set to #null in Theme.Dialog style, therefore setting it to #null again has no effect.)
In order to remove the border and round corners you have to change the android:windowBackground appropriately. The Theme.Dialog style sets it to #android:drawable/panel_background. Which is a 9-patch drawable that looks like this (this one is the hdpi version):
As you can see the 9-patch png defines the margin, border and round corners of the dialog theme. To remove the border and round corners you have to create an appropriate drawable. If you want to keep the shadow gradient you have to create set of new 9-patch drawables (one drawable for each dpi). If you don't need the shadow gradient you can create a shape drawable.
The required style is then:
<style name="ActivityDialog" parent="#android:style/Theme.Dialog">
<item name="android:windowBackground">#drawable/my_custom_dialog_background</item>
</style>
I played around a bit with other possibilities but using a 9 patch with fixed margins and found out that the layer-list drawable is allowing to define offsets, hence margins around its enclosed drawables, so this worked for me:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:drawable="#drawable/my_custom_background"
android:top="5dp" android:bottom="5dp" android:left="5dp" android:right="5dp">
</item>
</layer-list>
and then you can use this as the "android:windowBackground":
<style name="ActivityDialog" parent="#android:style/Theme.Dialog">
<item name="android:windowBackground">#drawable/my_custom_layer_background</item>
</style>
Another option
Resources\Values\styles.xml
<style name="MessageDialog" parent="android:Theme.Holo.Light.Dialog">
<item name="android:windowBackground">#android:color/transparent</item>
</style>
where
AlertDialog.Builder builder = new AlertDialog.Builder(Activity, Resource.Style.MessageDialog);
These statements are excerpted from the following snippet:
public class MessageAlertDialog : DialogFragment, IDialogInterfaceOnClickListener
{
private const string DIALOG_TITLE = "dialogTitle";
private const string MESSAGE_TEXT = "messageText";
private const string MESSAGE_RESOURCE_ID = "messageResourceId";
private string _dialogTitle;
private string _messageText;
private int _messageResourceId;
public EventHandler OkClickEventHandler { get; set; }
public static MessageAlertDialog NewInstance(string messageText)
{
MessageAlertDialog dialogFragment = new MessageAlertDialog();
Bundle args = new Bundle();
args.PutString(MESSAGE_TEXT, messageText);
dialogFragment.Arguments = args;
return dialogFragment;
}
public static MessageAlertDialog NewInstance(string dialogTitle, string messageText)
{
MessageAlertDialog dialogFragment = new MessageAlertDialog();
Bundle args = new Bundle();
args.PutString(DIALOG_TITLE, dialogTitle);
args.PutString(MESSAGE_TEXT, messageText);
dialogFragment.Arguments = args;
return dialogFragment;
}
public static MessageAlertDialog NewInstance(int messageResourceId)
{
MessageAlertDialog dialogFragment = new MessageAlertDialog();
Bundle args = new Bundle();
args.PutInt(MESSAGE_RESOURCE_ID, messageResourceId);
dialogFragment.Arguments = args;
return dialogFragment;
}
public override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
_dialogTitle = Arguments.GetString(DIALOG_TITLE);
_messageText = Arguments.GetString(MESSAGE_TEXT);
_messageResourceId = Arguments.GetInt(MESSAGE_RESOURCE_ID);
}
public override Dialog OnCreateDialog(Bundle savedInstanceState)
{
base.OnCreateDialog(savedInstanceState);
AlertDialog.Builder builder = new AlertDialog.Builder(Activity, Resource.Style.MessageDialog);
if (_dialogTitle != null)
{
builder.SetTitle(_dialogTitle);
}
if (_messageText != null)
{
builder.SetMessage(_messageText);
}
else
{
View messageView = GetMessageView();
if (messageView != null)
{
builder.SetView(messageView);
}
}
builder.SetPositiveButton("OK", this);
//.SetCancelable(false);
this.Cancelable = false;
AlertDialog dialog = builder.Create();
dialog.SetCanceledOnTouchOutside(false);
//dialog.Window.SetBackgroundDrawableResource(Android.Resource.Color.Transparent);
return dialog;
}
private View GetMessageView()
{
if (_messageResourceId != 0)
{
View messageView = Activity.LayoutInflater.Inflate(_messageResourceId, null);
return messageView;
}
return null;
}
void IDialogInterfaceOnClickListener.OnClick(IDialogInterface di, int i)
{
OkClickEventHandler?.Invoke(this, null);
}
}
Usage
public static void ShowMessageAlertDialog(FragmentManager fragmentManager, string dialogTitle, string messageText, EventHandler okClickEventHandler)
{
MessageAlertDialog msgAlertDialog = MessageAlertDialog.NewInstance(dialogTitle, messageText);
msgAlertDialog.OkClickEventHandler += okClickEventHandler;
msgAlertDialog.Show(fragmentManager, "message_alert_dialog");
}
Another solution to this issue is to use android.support.v7.app.AlerDialog instead of android.app.AlertDialog. It's the most easiest and time effective solution. Design you custom view in the layout and then use it with your support package's AlertDialogBuilderclass and it will work like charm.

How to Change Height of Custom Dialog's Title Bar in Android

In my android app I have a custom dialog box. I want to set the height of dialog's Title bar. My style is as follows:
<resources>
<style name="customDialogStyle" parent="android:Theme.Dialog">
<item name="android:background">#04a9ee</item>
<item name="android:height">5dp</item>
</style>
</resources>
But there is no effect of "height" attribute on title bar. So, how can the height of custom dialog's title bar can be changed ?
Yeh I just check, you want to use "android:layout_height" other heights you can use also like: "android:minHeight"
This works for me
Your theme:
<resources>
<style name="MyDialog" parent="android:Theme.Holo.Dialog">
.......
</style>
</resources>
Your Custom Dialog Class:
public class CustomDialog extends Dialog
{
public CustomDialog(Context context, int theme) {
super(context, theme);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...........
Resources res = getContext().getResources();
int titleId = res.getIdentifier("title", "id", "android");
View title = findViewById(titleId);
if (title != null) {
title.getLayoutParams().height = 5; // your height
}
}
}
Create dialog and show in your code:
CustomDialog customDialog = new CustomDialog(this, R.style.MyDialog);
customDialog.show();

Categories

Resources