Change Toolbar overflow icon color - java

I have an android.support.v7.widget Toolbar in my Android app. The background color of this is bright orange and the best looking color on top of this would be white instead of black.
I have the default color on black and not white. Since it would conflict with other stuff, that is almost impossible to override. I cannot change the primary text color to white!
I've managed to change the title color.
What I'm looking for right now is how I can change the action button color as well (to white).
My code:
Main activity:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".UI.activities.MainActivity">
<android.support.v7.widget.Toolbar
android:id="#+id/r2_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:elevation="4dp"
app:titleTextColor="#color/primary_text_material_light"
app:subtitleTextColor="#color/primary_text_material_light"
android:theme="#style/R2Theme.Toolbar"/>
<fragment android:name="com.r2retail.r2retailapp.UI.fragments.SetupFragment"
android:layout_below="#+id/r2_toolbar"
android:id="#+id/list"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
Menu bar:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="#+id/about"
android:icon="#drawable/ic_menu"
android:title="About"
app:showAsAction="never"/>
</menu>
Styles:
<resources>
<style name="R2Theme" parent="Theme.AppCompat.Light.NoActionBar">=
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/colorPrimary</item>
<item name="android:textColorPrimary">#color/secondary_text_material_dark</item>
<item name="android:textColorSecondaryInverse">#color/primary_text_material_light</item>
</style>
<style name="R2Theme.Toolbar" parent="R2Theme">
<item name="actionMenuTextColor">#color/primary_text_material_light</item>
</style>
</resources>

In styles:
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
...
<item name="actionOverflowButtonStyle">#style/MyOverflowButtonStyle</item>
</style>
<style name="MyOverflowButtonStyle" parent="Widget.AppCompat.ActionButton.Overflow">
<item name="android:tint">#62ff00</item>
</style>
Result:

The solution is to replace icon itself.
1st
Go to values/styles and in your styles.xml file add:
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="android:actionOverflowButtonStyle">#style/MyActionButtonOverflow</item>
</style>
<style name="MyActionButtonOverflow" parent="android:style/Widget.Holo.Light.ActionButton.Overflow">
<!--Here you need to put name of drawable you will create during the next step-->
<item name="android:src">#drawable/your_white_icon</item>
</style>
2nd
Then go to drawable folder. Right mouse click -> new -> vector asset.
Then press on Icon image and choose from suggested icon named ic_more_vert_black_24dp.
Customize it -> press next -> finish.
Then open newly created icon file. Code looks like this.
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF" <!-- Here u can change color-->
android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
</vector>
Change fillColor attribute to the color you need. Put this file to the styles how described in 1st step.
Voila! Color of our three dots changed not depending on base app styles (result for #FF2012 color).

An alternative way, in code instead of XML:
public static boolean colorizeToolbarOverflowButton(#NonNull Toolbar toolbar, #ColorInt int color) {
final Drawable overflowIcon = toolbar.getOverflowIcon();
if (overflowIcon == null)
return false;
toolbar.setOverflowIcon(getTintedDrawable(toolbar.getContext(), overflowIcon, toolbarIconsColor));
return true;
}
public static Drawable getTintedDrawable(#NonNull Context context, #NonNull Drawable inputDrawable, #ColorInt int color) {
Drawable wrapDrawable = DrawableCompat.wrap(inputDrawable);
DrawableCompat.setTint(wrapDrawable, color);
DrawableCompat.setTintMode(wrapDrawable, Mode.SRC_IN);
return wrapDrawable;
}
The function will return true if succeeded to colorize the overflow icon.
And another alternative, in case you prefer not to use a tinted drawable:
public static boolean colorizeToolbarOverflowButton(#NonNull Toolbar toolbar, #ColorInt Integer color) {
final Drawable overflowIcon = toolbar.getOverflowIcon();
if (overflowIcon == null)
return false;
final PorterDuffColorFilter colorFilter = toolbarIconsColor == null ? null : new PorterDuffColorFilter(toolbarIconsColor, PorterDuff.Mode.MULTIPLY);
overflowIcon.setColorFilter(colorFilter);
return true;
}
In addition, if you wish to colorize the icons of the action items and the nav item, you can try this (based on here):
/**
* Use this method to colorize toolbar icons to the desired target color
*
* #param toolbarView toolbar view being colored
* #param toolbarIconsColor the target color of toolbar icons
*/
#JvmStatic
#UiThread
fun colorizeToolbarActionItemsAndNavButton(toolbarView: Toolbar, #ColorInt toolbarIconsColor: Int?) {
//https://snow.dog/blog/how-to-dynamicaly-change-android-toolbar-icons-color/
val colorFilter = if (toolbarIconsColor == null) null else PorterDuffColorFilter(toolbarIconsColor, Mode.MULTIPLY)
for (i in 0 until toolbarView.childCount) {
val v = toolbarView.getChildAt(i)
//Step 1 : Changing the color of back button (or open drawer button).
if (v is ImageButton) {
//Action Bar back button
v.drawable.mutate().colorFilter = colorFilter
}
if (v is ActionMenuView) {
for (j in 0 until v.childCount) {
//Step 2: Changing the color of any ActionMenuViews - icons that
//are not back button, nor text, nor overflow menu icon.
val innerView = v.getChildAt(j)
if (innerView is ActionMenuItemView) {
val drawablesCount = innerView.compoundDrawables.size
for (k in 0 until drawablesCount) {
if (innerView.compoundDrawables[k] != null) {
innerView.post { innerView.compoundDrawables[k].mutate().colorFilter = colorFilter }
}
}
}
}
}
}
}
Usage:
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_main, menu)
toolbar.doOnPreDraw {
colorizeToolbarActionItemsAndNavButton(toolbar,0xffff0000.toInt())
}
return true
}

For AndroidX users (really don't know if it works using old Support Library):
TL;DR:
<style name="MyToolbarTheme">
<item name="colorControlNormal">#color/white</item>
</style>
Apply MyToolbarTheme to your Toolbar view.
Long explanation:
Widget.AppCompat.ActionButton.Overflow extends Base.Widget.AppCompat.ActionButton.Overflow. We'll be talking about the latter:
On the default implementation:
<style name="Base.Widget.AppCompat.ActionButton.Overflow" parent="RtlUnderlay.Widget.AppCompat.ActionButton.Overflow">
<item name="srcCompat">#drawable/abc_ic_menu_overflow_material</item>
...
</style>
On API 21 implementation:
<style name="Base.Widget.AppCompat.ActionButton.Overflow" parent="android:Widget.Material.ActionButton.Overflow">
<item name="android:src">#null</item>
<item name="srcCompat">#drawable/abc_ic_menu_overflow_material</item>
</style>
On API 23 and higher implementation:
It extends android:Widget.Material.ActionButton.Overflow.
<style name="Widget.Material.ActionButton.Overflow">
<item name="src">#drawable/ic_menu_moreoverflow_material</item>
...
</style>
We can notice that every implementation uses #drawable/ic_menu_moreoverflow_material.
Inside this drawable's implementation you can see the following:
android:tint="?attr/colorControlNormal"

If you want to change the color of icons (Navigation icon, menu item icons) in your toolbar, you can simply use the code below. I had saved problem and solved using this.
<!--Light Theme-->
<style name="AppThemeLight" parent="Theme.MaterialComponents.Light.NoActionBar">
<!--other colors and properties-->
<item name="iconTint">#color/colorBlack</item>
</style>
<!-- Dark/Night theme. -->
<style name="AppThemeDark" parent="Theme.MaterialComponents.NoActionBar">
<!--other colors and properties-->
<item name="iconTint">#color/colorWhite</item>
</style>

If anyone's looking to change it programmatically, and the following didn't work:
mBinding.toolbar.overflowIcon?.setTint(Color.WHITE)
OR
mBinding.toolbar.overflowIcon?.setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_ATOP)
OR
mBinding.toolbar.overflowIcon?.colorFilter = BlendModeColorFilterCompat.createBlendModeColorFilterCompat(Color.WHITE, BlendModeCompat.SRC_ATOP)
OR
val overflowIcon = ContextCompat.getDrawable(this, R.drawable.dots_vertical_black)
overflowIcon?.setTint(Color.WHITE)
mBinding.toolbar.overflowIcon = overflowIcon
TRY THIS.
Finally the below line worked for me (after 2 days of trial and error -_-)
mBinding.toolbar.menu?.findItem(R.id.menu)?.icon?.setTint(Color.WHITE)

Related

Transparent Android Material buttons have weird border

As in the title, my material buttons have a strange border around them that appears when I make them transparent. I'm not really sure what's causing this, any help would be appreciated.
My initial thought was that the button automatically contained a textview, and my code was setting the background of the textview and button, making them overlay, making them visible while transparent. However, I tried removing the "text" tag, and removing the android:text xml line, and still had this same result.
Button Style:
<style name="button" parent="Widget.MaterialComponents.Button">
<item name="android:textSize">25sp</item>
<item name="shapeAppearanceOverlay">#style/bgShape</item>
<item name="android:textAllCaps">false</item>
</style>
<style name="clock" parent="Widget.MaterialComponents.TextView">
<item name="android:textSize">25sp</item>
<item name="android:textAllCaps">false</item>
<item name="android:textStyle">bold</item>
<item name="android:textColor">?colorOnPrimary</item>
<item name="shapeAppearanceOverlay">#style/bgShape</item>
</style>
<style name="bgShape">
<item name="cornerFamily">rounded</item>
<item name="cornerSize">15sp</item>
</style>
Button XML:
<Button
android:id="#+id/home"
android:layout_width="match_parent"
android:layout_height="80sp"
android:layout_marginBottom="60dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="10dp"
android:layout_gravity="bottom"
android:text="#string/home"
style="#style/button"
android:tag="text-foreground"/>
Code that changes view colours:
Object tag = view.getTag();
if(tag != null){
String sTag = (String) tag;
if(sTag.contains(bgTag)){
if(sTag.contains(wpTag)){
} else {
view.setBackgroundColor(theme.bgColor);
}
}
if(sTag.contains(fgTag)){
if(!sTag.contains("clock") ){
view.setBackgroundColor((theme.fgColor & 0x00ffffff) | (180 << 24));
}
}
if(sTag.contains(txTag)){
if(view instanceof TextView){
if(sTag.contains(fgTag)){
((TextView)view).setTextColor(theme.fgtxColor);
} else {
((TextView)view).setTextColor(theme.txColor);
}
}
}
}
It seems this problem is related to your transparent background revealing your button shadow. See this SO answer for possible solution

Remove Toolbar title margin in ActionMode

I'm looking to remove the space between the navigation icon and the title of my actionMode. I managed to remove it for the toolbar thanks to:
<style name="AppTheme" parent="Theme.MaterialComponents.Light">
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/colorPrimary</item>
<item name="toolbarStyle">#style/cusToolbarStyle</item>
</style>
<style name="cusToolbarStyle" parent="#style/Widget.MaterialComponents.Toolbar">
<item name="titleMargin">0dp</item>
<item name="contentInsetStartWithNavigation">0dp</item>
<item name="contentInsetStart">0dp</item>
<item name="android:background">#color/white</item>
</style>
However I can not change the mode action to remove the space on the photo:
Ok, it was complex and difficult but I used LayoutInspector such as suggested to me #cgb_pandey. So I found the system identifier of the close ImageView and add the below code to the onPrepareActionMode method:
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
AppCompatImageView imageView = findViewById(com.google.android.material.R.id.action_mode_close_button);
if (imageView != null) {
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.setMargins(0, 0, 0, 0);
imageView.setLayoutParams(params);
}
return false;
}

Contextual Action Bar (CAB) does not overlay Toolbar

I am really stuck with this.
I want to use a CAB in a fragment, so I'm using
actionMode = ((MainActivity)getActivity()).startActionMode(actionModeCallbacks);
to call startActionMode
I've been changing themes and adding and testing several lines of code (together and separated) to xml styles like:
<item name="android:windowActionModeOverlay">true</item>
<item name="android:windowActionBarOverlay">true</item>
<item name="android:windowActionBar">false</item>
<item name="windowActionBar">false</item>
<item name="windowActionModeOverlay">true</item>
<item name="windowActionBarOverlay">true</item>
Relevant information:
I have my toolbar defined inside and <include/>in my main activity.
Toolbar is included just before the frame of MainActivity, between that frame and the DrawerLayout, so I can use the toolbar in the fragments.
I have tested the CAB inside Main Activity, but it also gets above
the Toolbar.
I also tried a dirty workoaround toggling Toolbar visibility when CAB
is created/destroyed, but it also doesn't work!
I'm using android.view.ActionMode instead of
android.support.v7.view.ActionMode because I can't call
startActionMode if I use Support Library (?).
My toolbar (*android.support.v7.widget.Toolbar):
toolbar = findViewById(R.id.toolbar);
mDrawerLayout = findViewById(R.id.drawer_layout);
toolbar.setTitle(R.string.addWordLabel_Act);
setSupportActionBar(toolbar);
toolbar.setNavigationIcon(R.drawable.ic_menu_white_24dp);
XML (toolbar)
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#FAFAFA"
android:theme="#style/AppTheme.NoActionBar"
app:collapseIcon="#drawable/ic_arrow_back_white_24dp"
app:contentInsetStartWithNavigation="0dp"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
app:title="#string/addWordLabel_Act"
app:titleTextColor="#color/colorAccent"
/>
</android.support.constraint.ConstraintLayout>
ActionMode.Callback
private ActionMode actionMode;
private ActionMode.Callback actionModeCallbacks = new ActionMode.Callback()
{
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mode.getMenuInflater().inflate(R.menu.action_mode_menu, menu);
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.share_actionMode:
shareWord();
mode.finish();
return true;
case R.id.deleteWords_actionMode:
deleteWords();
mode.finish();
return true;
default:
return false;
}
}
#Override
public void onDestroyActionMode(ActionMode mode) {
actionMode = null;
}
};
XML (CAB)
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:title="Share"
android:icon="#drawable/ic_share_white_24dp"
android:id="#+id/share_actionMode"/>
<item android:id="#+id/deleteWords_actionMode"
android:title="Delete"
android:icon="#drawable/ic_round_delete_outline_white_24px"/>
</menu>
And styles...
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="android:windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/lightAccent</item>
<item name="colorSecondary">#color/colorSecondary</item>
<item name="android:fontFamily">#font/sans_serif_roboto</item>
<item name="alertDialogTheme">#style/AlertDialogStyle</item>
<item name="android:windowActionModeOverlay">true</item>
</style>
<style name="AppTheme.NoActionBar"
parent="Theme.MaterialComponents.NoActionBar">
</style>
I don't know what else I can do.
Solved
I completely forgot to check Manifest, and that was the problem!
The AppTheme was set to "Theme.AppCompat.Light.NoActionBar" instead of "AppTheme". Thus, any change I made in AppTheme didn't take effect on the App.
I completely forgot to check Manifest, and that was the problem! The AppTheme was set to "Theme.AppCompat.Light.NoActionBar" instead of "AppTheme". Thus, any change I made in AppTheme didn't take effect on the App.

How to consider variation while switching theme?

I'm Working on an android app that has a requirement to switch theme based on the themeCode given from server. I'm using sharePref to save the theme code and applying it with setTheme(R.style.themeName);. Its working fine till the basic theme attributes like
colorPrimary
colorPrimaryDark
colorAccent
windowActionBar
windowNoTitle
For this I has created different styles in styles.xml. But I have a limitation that some fields say EditText has variation as EditText
person name
email
phone
password etc.
And similarly TextView has variation as TextView
Heading
Single Line
Mutiline
Link etc.
Before multi-theme requirement I had created separate themes for all as
Apptheme.Edittext.email
Apptheme.Edittext.Password
Apptheme.Edittext.PersonName etc.
And was applying to specific view in xml like
style="#style/AppTheme.EditText.PersonName"
Now I have viewed many tutorials/posts but did not find solution to the variations in attribute. Please help to apply these variation, I'll be thankful for this.
Regards:
Inzimam Tariq
In my opinion changing app theme at runtime, will definitely need to reload activity; this in most cases will create issues at some point (if project is extended to a mid scale, having a user control like toggle or a switch and if user taps switch repeatedly app may easily crash)
I would suggest to use custom control classes (Textviews, Buttons..etc); wherein this properties are differentiated with current theme value from sharedPref.
This approach has a con; it will require to change all views manually of current screen and those in already rendered in memory(if any), rest all it will be much smoother transition in compare to our conventional approach
EDIT: Example for CustomTextView ##
This is an example for customtextview class
public class CustomTextView extends android.support.v7.widget.AppCompatTextView {
private static final String TAG = "TextView";
private Typeface tf = null;
private SharedPreferenceUtils preferenceUtils = SharedPreferenceUtils.getInstance();
/**
* #param context:This is an abstract class whose implementation is provided by Android Operating System.
* #param attrs:A collection of attributes, as found associated with a tag in an XML document.
* #param defStyle:
*/
public CustomTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
if (preferenceUtils.getBooleanValue(PrefsKeyValue.bTheme)) {
this.setTextColor(ResourceUtils.getColor(R.color.lightThemeTextColor));
} else {
this.setTextColor(ResourceUtils.getColor(R.color.colorWhite));
}
try {
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.CustomEditText, defStyle, 0);
String str = a.getString(R.styleable.CustomTextView_FontEnum);
int original = a.getInt(R.styleable.CustomEditText_FontEnum, 0);
CustomEnum.CustomFontType customEnumValue = CustomEnum.CustomFontType.fromId(a.getInt(R.styleable.CustomEditText_FontEnum, 0));
a.recycle();
switch (customEnumValue) {
case BOLD:
setTypeface(HelveticaNeueBold.getInstance(context).getTypeFace());
break;
case LIGHT:
setTypeface(HelveticaNeueMedium.getInstance(context).getTypeFace());
break;
case REGULAR:
setTypeface(HelveticaNeue.getInstance(context).getTypeFace());
break;
default:
break;
}
} catch (Exception e) {
e.printStackTrace();
}
}
public CustomTextView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public boolean setCustomFont(Context ctx, String asset) {
try {
tf = Typeface.createFromAsset(ctx.getAssets(), asset);
} catch (Exception e) {
LogUtils.LogE(TAG, "Could not get typeface: " + e.getMessage());
return false;
}
setTypeface(tf);
return true;
}}
Herein I have changed textcolor in accordance to theme value from sharedPref
if (preferenceUtils.getBooleanValue(PrefsKeyValue.bTheme)) {
this.setTextColor(ResourceUtils.getColor(R.color.lightThemeTextColor));
} else {
this.setTextColor(ResourceUtils.getColor(R.color.colorWhite));
}
Then use this class as textview tag in xml file.
<com.mypkg.customview.CustomTextView
style="#style/signup_textViewStyle"
android:text="#string/activity_login_password" />
I believe, you can handle property variation with theme for controls in same manner.
What you can do is create custom attributes for your view types (e.g. TextView.Person, TextView.Date...), in your xml you can reference the attributes and then define the attributes in different themes. For instance, you style.xml could be
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar" >
<item name="TextView.Date">#style/DateTextViewDefault</item>
</style>
<style name="DateTextViewDefault">
<item name="android:textColor">#ff333333</item>
<item name="android:fontFamily">monospace</item>
</style>
<!-- Theme A -->
<style name="AppTheme.A">
<item name="colorPrimary">#3F51B5</item>
<item name="colorPrimaryDark">#303F9F</item>
<item name="colorAccent">#FF4081</item>
<item name="TextView.Person">#style/PersonTextViewA</item>
</style>
<style name="PersonTextViewA">
<item name="android:textSize">16sp</item>
<item name="android:fontFamily">serif</item>
<item name="android:textColor">#ff999999</item>
</style>
<!-- Theme B -->
<style name="AppTheme.B">
<item name="colorPrimary">#888888</item>
<item name="colorPrimaryDark">#555555</item>
<item name="colorAccent">#000000</item>
<item name="TextView.Person">#style/PersonTextViewB</item>
<item name="TextView.Date">#style/DateTextViewB</item>
</style>
<style name="PersonTextViewB">
<item name="android:textSize">20sp</item>
<item name="android:fontFamily">monospace</item>
<item name="android:textColor">#ff55aa</item>
</style>
<style name="DateTextViewB">
<item name="android:textColor">#ff0000BB</item>
<item name="android:fontFamily">sans-serif</item>
</style>
<attr name="TextView.Person" format="reference" />
<attr name="TextView.Date" format="reference" />
</resources>
then your activity xml layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
style="?attr/TextView.Person"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="John Doe" />
<TextView
style="?attr/TextView.Date"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="31/12/1999" />
<Button
android:id="#+id/buttonA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="THEME A" />
<Button
android:id="#+id/buttonB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="THEME B" />
</LinearLayout>
notice that the styles of the TextView are
style="?attr/TextView.Person"
and
style="?attr/TextView.Date"
AppTheme.A and AppTheme.B have 2 different resolutions for those attributes
In this example the attributes are entire styles for your views but you could easily have one style per view type (TextView.person) and then define generic attributes for single items of that style, e.g.
<attr name="TextView.Person.TextColor" format="color" />
and only change that single attribute in your themes.
Then in your Activity you just need to set the theme in onCreate with setTheme(int), the value could be in this case either R.style.AppTheme_A or R.style.AppTheme_B.
With this method you can add as many styles as you want without touching the layouts. Also, you can always define some default styles in your base theme and then only override that value in some of the custom themes, while others use the default one as for TextView.Date in the sample above.
If you want to give it a quick try, here's the code of the Activity I used to test style.xml and activity_main.xml above
class MainActivity : AppCompatActivity() {
private val prefs by lazy { getSharedPreferences("SharedPrefs", Context.MODE_PRIVATE) }
private var customTheme: Int
get() = prefs.getInt("theme", R.style.AppTheme_A)
set(value) = prefs.edit()
.putInt("theme", value)
.apply()
.also { recreate() }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setTheme(customTheme)
setContentView(R.layout.activity_main)
buttonA.setOnClickListener { customTheme = R.style.AppTheme_A }
buttonB.setOnClickListener { customTheme = R.style.AppTheme_B }
}
}

How to make custom font in actionbar show up immediately

In order to change the font which is inside my actionbar, I implemented a custom TypefaceSpan class and used a SpannableString in my onCreate.
This has what I did:
How to Set a Custom Font in the ActionBar Title?
In the comments user, artwork ,said,
In the moment of starting the app, the default title style is visible
and about 1 sec later the custom style appears.
Then the guy who answered the question said
"that's because your activity's theme is being applied to the
DecorView before your code has spun up. You can work around this by
hiding the action bar in your theme, then show it as your activity is
being created."
I am not sure how to implement the following. Nor am I sure that is able to be done in my customized action bar.
And this is how I styled my actionbar:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.Customaction" parent="#style/android:Theme.Holo">
<item name="actionBarItemBackground">#drawable/selectable_background_customaction</item>
<item name="popupMenuStyle">#style/PopupMenu.Customaction</item>
<item name="dropDownListViewStyle">#style/DropDownListView.Customaction</item>
<item name="actionBarTabStyle">#style/ActionBarTabStyle.Customaction</item>
<item name="actionDropDownStyle">#style/DropDownNav.Customaction</item>
<item name="actionBarStyle">#style/ActionBar.Transparent.Customaction</item>
<item name="actionModeBackground">#drawable/cab_background_top_customaction</item>
<item name="actionModeSplitBackground">#drawable/cab_background_bottom_customaction</item>
<item name="actionModeCloseButtonStyle">#style/ActionButton.CloseMode.Customaction</item>
</style>
<style name="ActionBar.Solid.Customaction" parent="#style/Widget.AppCompat.ActionBar.Solid">
<item name="background">#drawable/ab_solid_customaction</item>
<item name="backgroundStacked">#drawable/ab_stacked_solid_customaction</item>
<item name="backgroundSplit">#drawable/ab_bottom_solid_customaction</item>
<item name="progressBarStyle">#style/ProgressBar.Customaction</item>
</style>
<style name="ActionBar.Transparent.Customaction" parent="#style/Widget.AppCompat.ActionBar">
<item name="background">#drawable/ab_transparent_customaction</item>
<item name="progressBarStyle">#style/ProgressBar.Customaction</item>
</style>
<style name="PopupMenu.Customaction" parent="#style/Widget.AppCompat.PopupMenu">
<item name="android:popupBackground">#drawable/menu_dropdown_panel_customaction</item>
</style>
<style name="DropDownListView.Customaction" parent="#style/Widget.AppCompat.ListView.DropDown">
<item name="android:listSelector">#drawable/selectable_background_customaction</item>
</style>
<style name="ActionBarTabStyle.Customaction" parent="#style/Widget.AppCompat.ActionBar.TabView">
<item name="android:background">#drawable/tab_indicator_ab_customaction</item>
</style>
<style name="DropDownNav.Customaction" parent="#style/Widget.AppCompat.Spinner.DropDown.ActionBar">
<item name="android:background">#drawable/spinner_background_ab_customaction</item>
<item name="android:popupBackground">#drawable/menu_dropdown_panel_customaction</item>
<item name="android:dropDownSelector">#drawable/selectable_background_customaction</item>
</style>
<style name="ProgressBar.Customaction" parent="#style/Widget.AppCompat.ProgressBar.Horizontal">
<item name="android:progressDrawable">#drawable/progress_horizontal_customaction</item>
</style>
<style name="ActionButton.CloseMode.Customaction" parent="#style/Widget.AppCompat.ActionButton.CloseMode">
<item name="android:background">#drawable/btn_cab_done_customaction</item>
</style>
<!-- this style is only referenced in a Light.DarkActionBar based theme -->
<style name="Theme.Customaction.Widget" parent="#style/Theme.AppCompat">
<item name="popupMenuStyle">#style/PopupMenu.Customaction</item>
<item name="dropDownListViewStyle">#style/DropDownListView.Customaction</item>
</style>
</resources>
This is part of what I have in my MainActivity:
#Override
protected void onCreate(Bundle savedInstanceState) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
super.onCreate(savedInstanceState);
//Make sure you find out why it appears after a whole 1 second after the app appears
SpannableString s = new SpannableString("GetDisciplined");
s.setSpan(new TypefaceSpan(this, "roboto-lightitalic.ttf"), 0, s.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
// Update the action bar title with the TypefaceSpan instance
ActionBar actionBar = getActionBar();
actionBar.setTitle(s);
setContentView(R.layout.merge);
I am just trying to solve the problem of the Custom ActionBar Font showing up after one second by making it show up immediately, but I am unsure to achieve this.
One way you could do it (not a very nice way) is to use a custom layout for your titlebar where you use a custom textview that displays the title.
public class CustomTextView extends TextView {
private static Typeface customFont = null;
public CustomTextView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
if (isInEditMode()) {
return;
}
if (customFont == null) {
customFont = Typeface.createFromAsset(context.getApplicationContext().getAssets(),
"fonts/custom_font.ttf");
}
setTypeface(customFont);
}
}
In your activity:
requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
setContentView(R.layout.activities);
getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.custom_title);
And the title in the layout uses that CustomTextView to hold the title.
Once again, pretty messy solution, but will do what you want it to.

Categories