Change theme dynamically for multiple view - Android - 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);
}

Related

Set theme color dynamically

I am using themes (dynamically) in my android app, like this:
my_layout.xml (extract):
<TextView
android:id="#+id/myItem"
style="?my_item_style" />
attrs.xml (extract):
<attr name="my_item_style" format="reference" />
themes.xml (extract):
<style name="MainTheme.Blue">
<item name="my_item_style">#style/my_item_style_blue</item>
</style>
<style name="MainTheme.Green">
<item name="my_item_style">#style/my_item_style_green<item>
</style>
styles.xml (extract):
<style name="my_item_style_blue">
<item name="android:textColor">#color/my_blue</item>
</style>
<style name="my_item_style_green">
<item name="android:textColor">#color/my_blue</item>
</style>
So, as you can see, I am setting themes dynamically. I am using this class:
public class ThemeUtils {
private static int sTheme;
public final static int THEME_BLUE = 1;
public final static int THEME_GREEN = 2;
public static void changeToTheme(MainActivity activity, int theme) {
sTheme = theme;
activity.startActivity(new Intent(activity, MyActivity.class));
}
public static void onActivityCreateSetTheme(Activity activity)
{
switch (sTheme)
{
default:
case THEME_DEFAULT:
case THEME_BLUE:
activity.setTheme(R.style.MainTheme_Blue);
break;
case THEME_GREEN:
activity.setTheme(R.style.MainTheme_Green);
break;
}
}
}
What I want to know, is there a way how to do this (change theme color) in code? For example, I have following code (extract):
((TextView) findViewById(R.id.myItem)).setTextColor(R.color.blue);
It can be done by some helper method, which would use switch command for available themes and return correct color for a theme. But I would like to know if there is some better, nicer and faster way.
Thanks!
I have finally done it using following method:
public static int getColor(String colorName) {
Context ctx = getContext();
switch (sTheme) {
default:
case THEME_DEFAULT:
return ctx.getResources().getIdentifier("BLUE_" + colorName, "color", ctx.getPackageName());
case THEME_BLUE:
return ctx.getResources().getIdentifier("BLUE_" + colorName, "color", ctx.getPackageName());
case THEME_GREEN:
return ctx.getResources().getIdentifier("GREEN_" + colorName, "color", ctx.getPackageName());
}
}
This returns color according to my theme (I used prefixes).
If I understand corectly you're looking for a way to
extract a style from a theme,
extract a value (text color) from said style.
Let's get to it.
// Extract ?my_item_style from a context/activity.
final TypedArray a = context.obtainStyledAttributes(new int[] { R.attr.my_item_style });
#StyleRes final int styleResId = a.getResourceId(0, 0);
a.recycle();
// Extract values from ?my_item_style.
final TypedArray b = context.obtainStyledAttributes(styleResId, new int[] { android.R.attr.textColor });
final ColorStateList textColors = b.getColorStateList(0);
b.recycle();
// Apply extracted values.
if (textColors != null) {
textView.setTextColor(textColors);
}
A couple of notes:
TypedArray does not support getting support vector drawables and theme references in color state lists on older API levels. If you're willing to use AppCompat internal API you may want to try TintTypedArray.
Allocating int[] all the time is costly, make it a static final.
If you want to resolve multiple attributes at once the array of attributes has to be sorted! Else it crashes sometimes. <declare-styleable> generates such array and corresponding indices for you.
Have you check this MultipleThemeMaterialDesign demo?
SettingActivity:
#Override
protected void onCreate(Bundle savedInstanceState) {
Preferences.applyTheme(this);
getDelegate().installViewFactory();
getDelegate().onCreate(savedInstanceState);
super.onCreate(savedInstanceState);
setToolbar();
addPreferencesFromResource(R.xml.preferences);
Preferences.sync(getPreferenceManager());
mListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
Preferences.sync(getPreferenceManager(), key);
if (key.equals(getString(R.string.pref_theme))) {
finish();
final Intent intent = IntentCompat.makeMainActivity(new ComponentName(
SettingsActivity.this, MainActivity.class));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | IntentCompat.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
}
}
};
}
See full example for demo.
What about passing theme id via Intent?
Intent intent = new Intent(activity, MyActivity.class);
intent.putExtra("theme", R.style.MainTheme_Green);
activity.startActivity(intent);
And then in onCreate:
// assuming that MainTheme_Blue is default theme
setTheme(getIntent().getIntExtra("theme", R.style.MainTheme_Blue));
Given the fact that every resource is a field into the R class, you can look for them using reflection. That's costly, but since you are going to get an int value, you can store them after you get them and avoid the performance drop. And since the methods that use resources take any int, you can use an int variable as placeholder, and then put the desired color into it.
for getting any resource:
String awesomeColor = "blue";
int color = getResourceId(R.color, awesomeColor, false);
if(blue>0) ((TextView) findViewById(R.id.myItem)).setTextColor(color);
The function:
public static int getResourceId(Class rClass, String resourceText, boolean showExceptions){
String key = rClass.getName()+"-"+resourceText;
if(FailedResourceMap.containsKey(key)) return 0;
if(ResourceMap.containsKey(key)) return ResourceMap.get(rClass.getName()+"-"+resourceText);
try {
String originalText = resourceText;
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.GINGERBREAD){
resourceText = ValidationFunctions.normalizeText(resourceText);
}
resourceText = resourceText.replace("?", "").replace(" ", " ").replace(" ", "_").replace("(", "").replace(")", "");
int resource = rClass.getDeclaredField(resourceText).getInt(null);
ResourceMap.put(rClass.getName()+"-"+originalText, resource);
return resource;
} catch (IllegalAccessException | NullPointerException e) {
FailedResourceMap.put(key, 0);
if(showExceptions) e.printStackTrace();
} catch (NoSuchFieldException e) {
FailedResourceMap.put(key, 0);
if(showExceptions) e.printStackTrace();
}
return 0;
}
Working version here: https://github.com/fcopardo/AndroidFunctions/blob/master/src/main/java/com/grizzly/functions/TextFunctions.java
This treatment is valid for any android resource. You can set the theme this way too instead of using intermediate variables:
public static void onActivityCreateSetTheme(Activity activity)
{
int theme = getResourceId(R.style, activity.getClass().getSimpleName(), false);
if(theme > 0) activity.setTheme(theme);
}

Changing the color of the background of an Activity

I am trying to change the color of the background in my android app. At the moment when I press the button it changes the color for that specific activity and not for all the other activities. Is there a way to change it for the whole app?
public class colorPicker extends AppCompatActivity {
View view;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_color_picker);
view = this.getWindow().getDecorView();
}
public void goPink(View v){
view.setBackgroundResource(R.color.Pink);
}
public void goGreen(View v){
view.setBackgroundResource(R.color.Green);
}
public void goYellow(View v){
view.setBackgroundResource(R.color.Yellow);
}
}
create a theme in your styles.xml and add following to that theme
<item name="android:windowBackground">#color/window_background
and set android:theme="#style/YourTheme" in your
<application>
...
</application
in manifest file
In this case, You need to add few changes in your activity.
In on onCreate
if(getIntent().getExtras() != null)
{
int theme = getIntent().getIntExtra("theme", R.style.AppTheme);
setTheme(theme);
getApplication().setTheme(theme);
//recreate();
}
Condition onCLick
if(condition)
getIntent().putExtra("theme", R.style.AppTheme2);
else
getIntent().putExtra("theme", R.style.AppTheme);
and maintain 2 theme
<style name="BaseTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary"></item></style>
and the second theme similar to it just change the name as BaseTheme2.
But this is not suggested to change the app theme at runtime.
You could change the window background color of your app theme and don't use a background for activities or you can use a transparent background for activities.

Change style of all buttons dynamically

I have a style for all buttons declared in values->styles.xml, like this.
<style name="BlueButton" parent="android:style/Widget.Button">
<item name="android:background">#color/blue</item>
</style>
and in the overall theme as
<style name="AppBaseTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="android:buttonStyle">#style/BlueButton</item>
</style>
I want to change the color of all buttons in my application, depending on what color the user chooses. Is there a way to define different styles in styles.xml and assign them to buttons dynamically.
Please note, i want to change the color of all the buttons in my application at a time and not one by one. For example, let's say, currently all my buttons are in black and when user chooses a theme of red, i want all the buttons in the application to have red background.
Hi try this code.
ThemeUtils class:
public class ThemeUtils {
private static int cTheme;
public final static int RED = 0;
public final static int GREEN = 1;
public static void changeToTheme(Activity activity, int theme) {
cTheme = theme;
activity.finish();
activity.startActivity(new Intent(activity, activity.getClass()));
}
public static void onActivityCreateSetTheme(Activity activity) {
switch (cTheme) {
case BLUE:
activity.setTheme(R.style.AppBaseTheme);
break;
default:
}
}
}
And to set theme use this code:
ThemeUtils.changeToTheme(this, ThemeUtils.BLUE);
If you want to create custom theme in android see this link:
http://romannurik.github.io/AndroidAssetStudio/
Try to use theming concept.
First create attribute for the button
<attr format="reference" name="button_style"/>
Then create a style as you want:
<style name="BlueButton" parent="android:style/Widget.Button">
<item name="android:background">#color/blue</item>
</style>
And then apply to Theme:
<style name="AppBaseTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="button_style">#style/BlueButton</item>
</style>
Finally apply this to button in Layout xml
<Button style="?button_style" />
Then if you want to change other theme create same like (2 and 3 point) it will automatically apply to your button
You can change the button background programmatically. And yes, call this method only once in every Activity such as you declare a theme for an Activity in manifest.xml. One color or drawable resource is applied for all button in your Activity. So, follow my steps:
Create a new third party class
Here, I named this class with ButtonBackground:
import android.app.Activity;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.widget.Button;
public class ButtonBackground {
/* This method is used to change the background with "drawable" resource. Maximum
* button to change its background is 5, no more. It caused by button's parameter
* only available for 5. You can add new parameter (button6, button 7, etc) with "int" type if needed.
*/
public void setButtonBackgroundDrawable(Context context, Activity activity, int drawable,
int button1, int button2, int button3, int button4, int button5) {
Drawable backgroundDrawable = context.getResources()
.getDrawable(drawable);
Button a = (Button) activity.findViewById(button1);
Button b = (Button) activity.findViewById(button2);
Button c = (Button) activity.findViewById(button3);
Button d = (Button) activity.findViewById(button4);
Button e = (Button) activity.findViewById(button5);
if (button1 != 0) {
a.setBackground(backgroundDrawable);
}
if (button2 != 0) {
b.setBackground(backgroundDrawable);
}
if (button3 != 0) {
c.setBackground(backgroundDrawable);
}
if (button4 != 0) {
d.setBackground(backgroundDrawable);
}
if (button5 != 0) {
e.setBackground(backgroundDrawable);
}
}
/* This method is used to change the background with "color" resource. Maximum
* button to change its background is 5, no more. It caused by button's parameter
* only available for 5. You can add new parameter (button6, button 7, etc) with "int" type if needed.
*/
public void setButtonBackgroundColor(Context context, Activity activity, int color,
int button1, int button2, int button3, int button4, int button5) {
int backgroundColor = context.getResources().getColor(color);
Button a = (Button) activity.findViewById(button1);
Button b = (Button) activity.findViewById(button2);
Button c = (Button) activity.findViewById(button3);
Button d = (Button) activity.findViewById(button4);
Button e = (Button) activity.findViewById(button5);
if (button1 != 0) {
a.setBackgroundColor(backgroundColor);
}
if (button2 != 0) {
b.setBackgroundColor(backgroundColor);
}
if (button3 != 0) {
c.setBackgroundColor(backgroundColor);
}
if (button4 != 0) {
d.setBackgroundColor(backgroundColor);
}
if (button5 != 0) {
e.setBackgroundColor(backgroundColor);
}
}
}
How to use?
For example, I have 3 buttons and I want to change its background using drawable resource. They are buttonId1, buttonId2 and buttonId3. My drawable's name is background_button_drawable.xml, and my current Activity named MainActivity. So I write the code below inside onCreate() method:
ButtonBackground buttonBackground = new ButtonBackground();
buttonBackground.setButtonBackgroundDrawable(getApplicationContext(), MainActivity.this,
R.drawable.background_button_drawable, R.id.buttonId1, R.id.buttonId2, R.id.buttonId3, 0, 0);
Note:
There are two 0 on the code above. It means button4 and button5 are empty in the parameter. So give 0 value if a button is empty or excess parameter.
What if I have 6 buttons?
You need one parameter again and must add a new parameter (button6). The parameter must int type:
public void setButtonBackgroundDrawable(... , int button6) {
And add it inside:
Button f = (Button) activity.findViewById(button6);
if (button6 != 0) {
f.setBackground(backgroundDrawable);
}
So when you use it:
ButtonBackground buttonBackground = new ButtonBackground();
buttonBackground.setButtonBackgroundDrawable(getApplicationContext(), MainActivity.this,
R.drawable.background_button_drawable, R.id.buttonId1, R.id.buttonId2, R.id.buttonId3, buttonId4, buttonId5, buttonId6);
What about change its background using color resource?
You need to change setButtonBackgroundDrawable() method with setButtonBackgroundColor(). It will looks like this:
ButtonBackground buttonBackground = new ButtonBackground();
buttonBackground.setButtonBackgroundColor(getApplicationContext(), MainActivity.this,
R.color.background_button_blue, R.id.buttonId1, R.id.buttonId2, R.id.buttonId3, 0, 0);
It's very simple to use, isn't?

How to add Action Bar from support library into PreferenceActivity?

Action Bar compatibility has been added into support library, revision 18. It now has ActionBarActivity class for creating activities with Action Bar on older versions of Android.
Is there any way to add Action Bar from support library into PreferenceActivity?
Previously I used ActionBarSherlock and it has SherlockPreferenceActivity.
EDIT: In appcompat-v7 22.1.0 Google added the AppCompatDelegate abstract class as a delegate you can use to extend AppCompat's support to any activity.
Use it like this:
...
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatDelegate;
import android.support.v7.widget.Toolbar;
...
public class SettingsActivity extends PreferenceActivity {
private AppCompatDelegate mDelegate;
#Override
protected void onCreate(Bundle savedInstanceState) {
getDelegate().installViewFactory();
getDelegate().onCreate(savedInstanceState);
super.onCreate(savedInstanceState);
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
getDelegate().onPostCreate(savedInstanceState);
}
public ActionBar getSupportActionBar() {
return getDelegate().getSupportActionBar();
}
public void setSupportActionBar(#Nullable Toolbar toolbar) {
getDelegate().setSupportActionBar(toolbar);
}
#Override
public MenuInflater getMenuInflater() {
return getDelegate().getMenuInflater();
}
#Override
public void setContentView(#LayoutRes int layoutResID) {
getDelegate().setContentView(layoutResID);
}
#Override
public void setContentView(View view) {
getDelegate().setContentView(view);
}
#Override
public void setContentView(View view, ViewGroup.LayoutParams params) {
getDelegate().setContentView(view, params);
}
#Override
public void addContentView(View view, ViewGroup.LayoutParams params) {
getDelegate().addContentView(view, params);
}
#Override
protected void onPostResume() {
super.onPostResume();
getDelegate().onPostResume();
}
#Override
protected void onTitleChanged(CharSequence title, int color) {
super.onTitleChanged(title, color);
getDelegate().setTitle(title);
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
getDelegate().onConfigurationChanged(newConfig);
}
#Override
protected void onStop() {
super.onStop();
getDelegate().onStop();
}
#Override
protected void onDestroy() {
super.onDestroy();
getDelegate().onDestroy();
}
public void invalidateOptionsMenu() {
getDelegate().invalidateOptionsMenu();
}
private AppCompatDelegate getDelegate() {
if (mDelegate == null) {
mDelegate = AppCompatDelegate.create(this, null);
}
return mDelegate;
}
}
No more hacking. Code taken from AppCompatPreferenceActivity.java.
There is currently no way to achieve with AppCompat. I've opened a bug internally.
I have managed to create a workaround similar to what the Google Play Store uses. Link to Original Answer
Please find the GitHub Repo: Here
Very Similar to your own code but added xml to allow for set title:
Continuing to use PreferenceActivity:
settings_toolbar.xml :
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/toolbar"
app:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
app:navigationContentDescription="#string/abc_action_bar_up_description"
android:background="?attr/colorPrimary"
app:navigationIcon="?attr/homeAsUpIndicator"
app:title="#string/action_settings"
/>
SettingsActivity.java :
public class SettingsActivity extends PreferenceActivity {
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
LinearLayout root = (LinearLayout)findViewById(android.R.id.list).getParent().getParent().getParent();
Toolbar bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false);
root.addView(bar, 0); // insert at top
bar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
finish();
}
});
}
}
Result :
UPDATE (Gingerbread Compatibility) :
As pointed out here, Gingerbread Devices are returning NullPointerException on this line:
LinearLayout root = (LinearLayout)findViewById(android.R.id.list).getParent().getParent().getParent();
FIX:
SettingsActivity.java :
public class SettingsActivity extends PreferenceActivity {
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
Toolbar bar;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
LinearLayout root = (LinearLayout) findViewById(android.R.id.list).getParent().getParent().getParent();
bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false);
root.addView(bar, 0); // insert at top
} else {
ViewGroup root = (ViewGroup) findViewById(android.R.id.content);
ListView content = (ListView) root.getChildAt(0);
root.removeAllViews();
bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false);
int height;
TypedValue tv = new TypedValue();
if (getTheme().resolveAttribute(R.attr.actionBarSize, tv, true)) {
height = TypedValue.complexToDimensionPixelSize(tv.data, getResources().getDisplayMetrics());
}else{
height = bar.getHeight();
}
content.setPadding(0, height, 0, 0);
root.addView(content);
root.addView(bar);
}
bar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
finish();
}
});
}
}
Any issues with the above let me know!
UPDATE 2: TINTING WORKAROUND
As pointed out in many dev notes PreferenceActivity does not support tinting of elements, however by utilising a few internal classes you CAN achieve this. That is until these classes are removed. (Works using appCompat support-v7 v21.0.3).
Add the following imports:
import android.support.v7.internal.widget.TintCheckBox;
import android.support.v7.internal.widget.TintCheckedTextView;
import android.support.v7.internal.widget.TintEditText;
import android.support.v7.internal.widget.TintRadioButton;
import android.support.v7.internal.widget.TintSpinner;
Then override the onCreateView method:
#Override
public View onCreateView(String name, Context context, AttributeSet attrs) {
// Allow super to try and create a view first
final View result = super.onCreateView(name, context, attrs);
if (result != null) {
return result;
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
// If we're running pre-L, we need to 'inject' our tint aware Views in place of the
// standard framework versions
switch (name) {
case "EditText":
return new TintEditText(this, attrs);
case "Spinner":
return new TintSpinner(this, attrs);
case "CheckBox":
return new TintCheckBox(this, attrs);
case "RadioButton":
return new TintRadioButton(this, attrs);
case "CheckedTextView":
return new TintCheckedTextView(this, attrs);
}
}
return null;
}
Result:
AppCompat 22.1
AppCompat 22.1 introduced new tinted elements, meaning that there is no longer a need to utilise the internal classes to achieve the same effect as the last update. Instead follow this (still overriding onCreateView):
#Override
public View onCreateView(String name, Context context, AttributeSet attrs) {
// Allow super to try and create a view first
final View result = super.onCreateView(name, context, attrs);
if (result != null) {
return result;
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
// If we're running pre-L, we need to 'inject' our tint aware Views in place of the
// standard framework versions
switch (name) {
case "EditText":
return new AppCompatEditText(this, attrs);
case "Spinner":
return new AppCompatSpinner(this, attrs);
case "CheckBox":
return new AppCompatCheckBox(this, attrs);
case "RadioButton":
return new AppCompatRadioButton(this, attrs);
case "CheckedTextView":
return new AppCompatCheckedTextView(this, attrs);
}
}
return null;
}
NESTED PREFERENCE SCREENS
A lot of people are experiencing issues with including the Toolbar in nested <PreferenceScreen />s however, I have found a solution!! - After a lot of trial and error!
Add the following to your SettingsActivity:
#SuppressWarnings("deprecation")
#Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
super.onPreferenceTreeClick(preferenceScreen, preference);
// If the user has clicked on a preference screen, set up the screen
if (preference instanceof PreferenceScreen) {
setUpNestedScreen((PreferenceScreen) preference);
}
return false;
}
public void setUpNestedScreen(PreferenceScreen preferenceScreen) {
final Dialog dialog = preferenceScreen.getDialog();
Toolbar bar;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
LinearLayout root = (LinearLayout) dialog.findViewById(android.R.id.list).getParent();
bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false);
root.addView(bar, 0); // insert at top
} else {
ViewGroup root = (ViewGroup) dialog.findViewById(android.R.id.content);
ListView content = (ListView) root.getChildAt(0);
root.removeAllViews();
bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false);
int height;
TypedValue tv = new TypedValue();
if (getTheme().resolveAttribute(R.attr.actionBarSize, tv, true)) {
height = TypedValue.complexToDimensionPixelSize(tv.data, getResources().getDisplayMetrics());
}else{
height = bar.getHeight();
}
content.setPadding(0, height, 0, 0);
root.addView(content);
root.addView(bar);
}
bar.setTitle(preferenceScreen.getTitle());
bar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dialog.dismiss();
}
});
}
The reason that PreferenceScreen's are such a pain is because they are based as a wrapper dialog, so we need to capture the dialog layout to add the toolbar to it.
Toolbar Shadow
By design importing the Toolbar does not allow for elevation and shadowing in pre-v21 devices, so if you would like to have elevation on your Toolbar you need to wrap it in a AppBarLayout:
`settings_toolbar.xml :
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
.../>
</android.support.design.widget.AppBarLayout>
Not forgetting to add the add the Design Support library as a dependency in build.gradle file:
compile 'com.android.support:support-v4:22.2.0'
compile 'com.android.support:appcompat-v7:22.2.0'
compile 'com.android.support:design:22.2.0'
Android 6.0
I have investigated the reported overlapping issue and I cannot reproduce the issue.
The full code in use as above produces the following:
If I am missing something please let me know via this repo and I will investigate.
Found a PreferenceFragment implementation based on support-v4 Fragment:
https://github.com/kolavar/android-support-v4-preferencefragment
Edit: I just tested it and its working great!
Integrating PreferenceActivity with ABC is not possible, at least for me. I tried the two possibilities I could find but none worked:
Option 1:
ActionBarPreferenceActivity extends PreferenceActivity. When you do this you get restricted by ActionBarActivityDelegate.createDelegate(ActionBarActivity activity). Also you need to implement ActionBar.Callbacks which is not accessible
Option 2:
ActionBarPreferenceActivity extends ActionBarActivity. This approach requires rewriting a whole new PreferenceActivity, PreferenceManager and may be PreferenceFragment which means you need access to hidden classes like com.android.internal.util.XmlUtils
The solution to this can only come from Google devs implementing an ActionBarWrapper that can be added to any activity.
If you really need a preference activity, my advice for now is ActionBarSherlock.
However, I managed to implement it here.
Problem Background:
The OP wants to know how can we put MenuItems in the ActionBar of PreferenceActivity for pre-Honeycomb because Android's support library has a bug which doesn't allow this to happen.
My Solution:
I've found a much cleaner way, than already proposed, to achieve the target (and found it in the Android Docs):
android:parentActivityName
The class name of the logical parent of the
activity. The name here must match the class name given to the
corresponding element's android:name attribute.
The system reads this attribute to determine which activity should be
started when the use presses the Up button in the action bar. The
system can also use this information to synthesize a back stack of
activities with TaskStackBuilder.
To support API levels 4 - 16, you can also declare the parent activity
with a element that specifies a value for
"android.support.PARENT_ACTIVITY". For example:
<activity
android:name="com.example.app.ChildActivity"
android:label="#string/title_child_activity"
android:parentActivityName="com.example.myfirstapp.MainActivity" >
<!-- Parent activity meta-data to support API level 4+ -->
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.example.app.MainActivity" />
</activity>
Now do what you would normally do in your onOptionsItemSelected(). Since it's a part of Android Docs, it has no side-affects.
Happy coding. :)
Update:
This solution no longer works if you're targeting Lollipop. If you're using AppCompat, this answer is what you should be looking for.
I was able to get android.app.Actionbar by using getActionBar(). It returned a null value at first... then I went to the manifest and changed the theme to:
android:theme="#style/Theme.AppCompat"
Then I was able to have the actionbar again. I'm assuming this will only work for certain build levels. So you might want to do a check for the build number or check if the value returned is null.
It'll be fine for me because the app I'm working on is for ICS/4.0+.
Now the official answer for this problem has been released. It is the v7/v14 Preference Support library.
See How to use the v7/v14 Preference Support library? for the discussion how to use it.

Change text size and color in one time?

I create many activities and classes in my app. However I have a function to change font size and color in every activity. This function changes text in own activity. When I go to other activity I must change textSize and color again. How can I create a function to change TextView in many classes and activities in one shot?
My app Structure:
Main.java main.xml/
Suad1.java suad1.xml/
Suad2.java suad2.xml/
Suad3.java suad3.xml/
Suad4.java suad4.xml/
I want to change these activity in one time. Here my code in Suad1.class.
public void ShowDialog() {
final AlertDialog.Builder popDialog = new AlertDialog.Builder(this);
final SeekBar seek = new SeekBar(this);
seek.getProgress();
seek.setMax(100);
popDialog.setIcon(R.drawable.conp);
popDialog.setTitle(R.string.menu_settings);
popDialog.setView(seek);
try {
seek.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
public void onStartTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
public void onStopTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
subtitles.setTextSize(progress);
}
});
}
catch (Exception e) {
e.printStackTrace();
}
popDialog.setSingleChoiceItems(items , -1,
new DialogInterface.OnClickListener() {
int i;
public void onClick(DialogInterface dialog, int item) {
i = item;
if(items[i] =="Blue") {
subtitles.setTextColor(getResources().getColor(R.color.font3));
} else if(items[i] == "Yellow") {
subtitles.setTextColor(getResources().getColor(R.color.font1));
} else if(items[i]== "Red") {
subtitles.setTextColor(getResources().getColor(R.color.font2));
}
}
}
);
// Button
popDialog.setPositiveButton("OK",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(Suad1.this, "Your setting is complete", Toast.LENGTH_LONG).show();
dialog.dismiss();
}
}
);
popDialog.create();
popDialog.show();
}
And two more questions:
Can I update SeekBar when out dialog and back again?
Can I have two Titles or more in one AlertDialog?
Create a separate class with method which you can use in multiple Activities for Changing TextView text,color :
public class ChangetextAttr {
public Activity context;
public ChangetextAttr(Activity context){
this.context=context;
}
// Create an Method for Changing TextView Attributes
public void settextViewAttr(Activity activity, TextView txtView){
txtView.setTextSize(15);
txtView.setTextColor(activity.getResources().getColor(R.color.font1));
//....
}
and from Any Activity you can settextViewAttr method for setting TextView Attributes :
ChangetextAttr obj=new ChangetextAttr(Your_Activity.this);
obj.settextViewAttr(this,any_textview_instance);
Hey create a(Customized textview) class which extends TextView and do whatever you want to do for the textview like changing text color and textstyle. now use this class in all your xml's . if your class name MyTextView. then your xml should be like the following...
<urpackage.MyTextView
android:id="#+id/text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
To answer your questions:
1- What you need is two styles (Bold & normal) and change between the used style for Text using View.setTextAppearance. Check Android documentaion and this answer.
2- To update seekbar with a value that is unchanged from View to View, then you need to keep its progress in a shared preference for e.g. and set the progress in onResume.
3- Consider using a custom Dialog instead (you can define it in XML as you wish). Or you can include /n to have multi lines in the Title string
Android provides you with mechanisms already to change the appearance of widgets, via Styles and Themes.
Here is how you define a style that sets the text size and color of any view that holds text:
<style name="BigColoredText">
<item name="android:textColor">#FF0000</item>
<item name="android:textSize">25sp</item>
</style>
and here is how you apply it to a TextView:
<TextView style="#style/BigColoredText" .../>
Styles can only be supplied to Views at construction time, you cannot change it afterwards. However, you can programmatically change the textAppearance with is the subset of a style that refers to text attributes via:
TextView v = ...;
v.setTextAppearance(R.styles.BigColoredText);
Now, if you want all TextViews within your Activity or Application using that same style (or at least use it by default), then you need a Theme:
<style name="Theme.MyTheme" parent="#android:style/Theme">
<item name="android:textViewStyle">#style/BigColoredText</item>
</style>
and then apply the theme to either the entire Application or one or more Activities in your manifest:
<application or activity android:theme="#style/Theme.MyTheme" .../>
Or you can change it programmatically at runtime via:
Activity activity = ...;
activity.setTheme(R.style.Theme_MyTheme);

Categories

Resources