I have a custom widget in a library project (Spinnerbutton) that I want to use in an application project.
The custom widget contains a TextView and I want to pass a style to that TextView from my app project.
This is my attrs.xml (in the library project):
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="Spinnerbutton">
<attr name="myTextAppearence" format="reference" />
</declare-styleable>
</resources>
And the app's layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:custom="http://schemas.android.com/apk/lib/com.example.spinnerbuttonlib"
android:id="#+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.example.spinnerbuttonlib.spinnerbutton.Spinnerbutton
android:id="#+id/sbp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
custom:myTextAppearence="#style/SmallTextGray" />
</RelativeLayout>
Here's how I try to read my custom attribute in the Spinnerbutton class:
public Spinnerbutton(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.Spinnerbutton);
int textStyleId = a.getResourceId(
R.styleable.Spinnerbutton_myTextAppearence, -1);
a.recycle();
}
textStyleId always return -1, so the value is not passed from my layout to the class.
What's wrong here?
The library project has a Customview Spinnerbutton which extends TextView (in you case it may be different. For testing i extended TextView).
Now if i understand correctly this view is used in android project and you need to set the style to that custom view which can be done as below.
Use the style in android library project as the parent style and then customize the style in android project styles.xml. Now set the style to the customview.
package com.example.customviewattributes.p1;
import com.example.customviewattributes.R;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.TextView;
public class Spinnerbutton extends TextView{
public Spinnerbutton(Context context) {
this(context, null);
}
public Spinnerbutton(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public Spinnerbutton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// real work here
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.Spinnerbutton,
0, 0
);
try {
int textStyleId = a.getResourceId(
R.styleable.Spinnerbutton_myTextAppearence, -1);
Log.i("................ID is",""+textStyleId);
// to make sure i logged the id
this.setText("hello");
this.setTextAppearance(context,textStyleId);
// set the style to text
} finally {
// release the TypedArray so that it can be reused.
a.recycle();
}
}
}
styles.xml
<resources>
<style name="AppBaseTheme" parent="android:Theme.Light">
<item name="android:textViewStyle">#style/QText</item>
</style>
<style name="AppTheme" parent="AppBaseTheme">
</style>
<style name="QText" parent="#android:style/TextAppearance.Medium">
<item name="android:textSize">20sp</item>
<item name="android:textColor">#color/ccolor</item>
<item name="android:textStyle">bold</item>
<item name="android:typeface">sans</item>
</style>
</resources>
attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="Spinnerbutton">
<attr name="myTextAppearence" format="reference" />
</declare-styleable>
</resources>
colors.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ccolor">#ff3232</color>
</resources>
All the above in library project.
Now in Another Android Project
activity_main.xml
<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"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
>
<com.example.customviewattributes.p1.Spinnerbutton
android:id="#+id/sbp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
/>
</RelativeLayout>
In MainActivity.java
setContentView(R.layout.activity_main);
com.example.customviewattributes.p1.Spinnerbutton cv = (Spinnerbutton) findViewById(R.id.sbp);
cv.setTextAppearance(this,R.style.QText1);
cv.setText("hello");
styles.xml
<resources>
<style name="AppBaseTheme" parent="android:Theme.Light">
<item name="android:textViewStyle">#style/QText</item>
</style>
<style name="AppTheme" parent="AppBaseTheme">
</style>
<style name="QText1" parent="#style/QText">
<item name="android:textSize">50sp</item>
<item name="android:textColor">#color/ccolor</item>
<item name="android:textStyle">bold</item>
<item name="android:typeface">sans</item>
</style>
</resources>
colors.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ccolor">#4F47B7</color>
</resources>
Snap
This is for android project
Now if i run library project as a normal android project
Snap
I think you should try to put the xmlns:custom with your app package name, like this :
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:custom="http://schemas.android.com/apk/res/com.example.yourapppackage"
android:id="#+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.example.spinnerbuttonlib.spinnerbutton.Spinnerbutton
android:id="#+id/sbp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
custom:myTextAppearence="#style/SmallTextGray" />
</RelativeLayout>
If you still have the problem, try to use the default xmlns namespace, like this :
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:id="#+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.example.spinnerbuttonlib.spinnerbutton.Spinnerbutton
android:id="#+id/sbp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
custom:myTextAppearence="#style/SmallTextGray" />
</RelativeLayout>
I think you will have better luck if your custom XML namespace is:
xmlns:custom="http://schemas.android.com/apk/res-auto"
change layout:
android:id="#+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.example.spinnerbuttonlib.spinnerbutton.Spinnerbutton
xmlns:custom="http://schemas.android.com/apk/res/android"
android:id="#+id/sbp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
custom:myTextAppearence="#style/SmallTextGray" />
try with this in attrs.xml
from
<attr name="myTextAppearence" format="reference" />
to this
<attr name="myTextAppearence" format="integer" />
and
int textStyleId = a.getResourceId(
R.styleable.Spinnerbutton_myTextAppearence, -1); in Spinnerbutton() constructor
to
int textStyleId = a.getInt(
R.styleable.Spinnerbutton_myTextAppearence, -1);
it will work
Related
Google recently released the android.support.design.widget.NavigationView widget as part of the com.android.support:design:22.2.0 library, which greatly simplified (and standardises) the process of creating a NavigationDrawer.
However according to the design specs, the list item should be Roboto Medium, 14sp, 87% #000000. The NavigationView exposes no textSize or textStyle to customise this.
What are my options if I'm pedantic about maintaining the correct design specifications using the Google provided NavigationView (or customising it in any other way)?
Create new style at the file app/src/main/res/values/styles.xml
<style name="NavigationDrawerStyle">
<item name="android:textSize">20sp</item><!-- text size in menu-->
<!-- item size in menu-->
<item name="android:listPreferredItemHeightSmall">40dp</item>
<item name="listPreferredItemHeightSmall">40dp</item>
<!-- item padding left in menu-->
<item name="android:listPreferredItemPaddingLeft">8dp</item>
<item name="listPreferredItemPaddingLeft">8dp</item>
<!-- item padding right in menu-->
<item name="android:listPreferredItemPaddingRight">8dp</item>
<item name="listPreferredItemPaddingRight">8dp</item>
</style>
Add it to your main_layout.xml
<android.support.design.widget.NavigationView
...
app:theme="#style/NavigationDrawerStyle"
....>
</android.support.design.widget.NavigationView>
All params of the navigation items (which you can change) are located here (path to file ...\sdk\extras\android\support\design\res\layout\design_navigation_item.xml )
design_navigation_item.xml
<android.support.design.internal.NavigationMenuItemView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="?attr/listPreferredItemHeightSmall"
android:paddingLeft="?attr/listPreferredItemPaddingLeft"
android:paddingRight="?attr/listPreferredItemPaddingRight"
android:drawablePadding="#dimen/navigation_icon_padding"
android:gravity="center_vertical|start"
android:maxLines="1"
android:fontFamily="sans-serif-thin"
android:textSize="22sp"
android:textAppearance="?attr/textAppearanceListItem" />
Also you can override *.xml file (copy file from ...\sdk\extras\android\support\design\res\layout\design_navigation_item.xml), just in your app/src/main/res/layout folder create a layout named the same design_navigation_item.xml.
All layouts which can be Overriden are located here ...\sdk\extras\android\support\design\res\layout\
design_layout_snackbar.xml
design_layout_snackbar_include.xml
design_layout_tab_icon.xml
design_layout_tab_text.xml
design_navigation_item.xml
design_navigation_item_header.xml
design_navigation_item_separator.xml
design_navigation_item_subheader.xml
design_navigation_menu.xml
[UPDATE] Each version of com.android.support:design-{version} lib has different items to override.
Check all what you need in
[UPDATE 04/14/2020]
If you are using com.google.android.material.navigation.NavigationView
then open the class, and you will see:
public NavigationView(#NonNull Context context, #Nullable AttributeSet attrs) {
this(context, attrs, R.attr.navigationViewStyle);
}
So you can use attr navigationViewStyle to set your own style for the NavigationView via theme of your app:
NB: parent theme of AppTheme should be Theme.MaterialComponents
<style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar.Bridge">
...
<item name="navigationViewStyle">#style/AppNavigationViewStyle</item>
...
</style>
<style name="AppNavigationViewStyle" parent="Widget.MaterialComponents.NavigationView">
<item name="itemTextAppearance">#style/AppNavigationViewItemTextAppearance</item>
</style>
<style name="AppNavigationViewItemTextAppearance" parent="#style/TextAppearance.MaterialComponents.Subtitle2">
<item name="android:textSize">18sp</item>
</style>
Just open parent theme to see all <item name attrs for override
Since Android Support Library 22.2.1, Google has changed default textSize of items in NavigationView from 16sp to 14sp, which suits Material Design guideline well. However, in some cases(for example, when you want to support Chinese language), it seems larger textSize is better. Solution is simple:
add app:theme="#style/yourStyle.Drawer" to your NavigationView in your layout.xml
in styles.xml, add android:textSize="16sp" in style yourStyle.Drawer
You can customize everything from text color to size and font in your style.xml
<style name="NavDrawerTextStyle" parent="Base.TextAppearance.AppCompat">
<item name="android:textColor">#color/colorPrimaryDark</item>
<item name="android:textSize">16sp</item>
<item name="android:textStyle">bold</item>
</style>
and then in your NavigationView:
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<android.support.design.widget.NavigationView
...
android:itemTextAppearance="#style/NavDrawerTextStyle"
/>
you can use this attributes inside xml file
app:itemTextAppearance="?android:attr/textAppearanceMedium"
or for small text
app:itemTextAppearance="?android:attr/textAppearance"
or for large text
app:itemTextAppearance="?android:attr/textAppearanceLarge"
This worked for me:
activity_main.xml
<android.support.design.widget.NavigationView
android:id="#+id/navigation_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:theme="#style/NavigationDrawerStyle"
app:headerLayout="#layout/navdrawer_header"
app:menu="#menu/navdrawer_menu" />
styles.xml
<style name="NavigationDrawerStyle">
<item name="android:textSize">16sp</item>
</style>
Scouring through the source code I found this layout file
/platform/frameworks/support/.../design/res/layout/design_drawer_item.xml
with the following attribute
<android.support.design.internal.NavigationMenuItemView
...
android:textAppearance="?attr/textAppearanceListItem"
Which meant all we had to do was to override the textAppearanceListItem style in our project.
res/values/styles.xml
<style name="AppTheme" ... >
...
<item name="textAppearanceListItem">#style/list_item_appearance</item>
</style>
<style name="list_item_appearance">
<item name="android:textSize">14sp</item>
<item name="android:fontFamily">sans-serif-medium</item>
</style>
I'm not totally sure what else this will affect but if anyone has a better answer I'd be happy to accept that instead!
Maybe it might help. Recently I had to do this programmatically.
I used this class:
public class CustomTypefaceSpan extends TypefaceSpan {
private final Typeface newType;
private final float newSp;
public CustomTypefaceSpan(String family, Typeface type, float sp) {
super(family);
newType = type;
newSp = sp;
}
#Override
public void updateDrawState(TextPaint ds) {
applyCustomTypeFace(ds, newType, newSp);
}
#Override
public void updateMeasureState(TextPaint paint) {
applyCustomTypeFace(paint, newType, newSp);
}
private static void applyCustomTypeFace(Paint paint, Typeface tf, float sp) {
int oldStyle;
Typeface old = paint.getTypeface();
if (old == null) {
oldStyle = 0;
} else {
oldStyle = old.getStyle();
}
int fake = oldStyle & ~tf.getStyle();
if ((fake & Typeface.BOLD) != 0) {
paint.setFakeBoldText(true);
}
if ((fake & Typeface.ITALIC) != 0) {
paint.setTextSkewX(-0.25f);
}
paint.setTextSize(sp);
paint.setTypeface(tf);
}
#SuppressWarnings("unused")
public static final Parcelable.Creator<CustomTypefaceSpan> CREATOR = new Parcelable.Creator<CustomTypefaceSpan>() {
#Override
public CustomTypefaceSpan createFromParcel(Parcel in) {
return null;
}
#Override
public CustomTypefaceSpan[] newArray(int size) {
return new CustomTypefaceSpan[size];
}
};
}
Then I used like this:
// This is for color
SpannableString s = new SpannableString(item.getTitle().toString());
s.setSpan(new ForegroundColorSpan(Color.RED), 0, s.length(), 0);
// This is for typeface and size
Typeface typeFace = Functions.getTypeface(this, "Avenir");
if (typeFace != null) {
int size = 19;
float scaledSizeInPixels = size * getResources().getDisplayMetrics().scaledDensity;
CustomTypefaceSpan spanTypeFace = new CustomTypefaceSpan(item.getTitle().toString(), typeFace, scaledSizeInPixels);
s.setSpan(spanTypeFace, 0, s.length(), 0);
}
item.setTitle(s);
Hope this helps.
Goto activity_main.xml and select nav_view in design and you can change menu item text size by updating itemTextAppearance and itemTextColor like as follows
For com.google.android.material.navigation.NavigationView you should use the app namespace with your custom style:
app:itemTextAppearance="#style/NavDrawerTextStyle"
List Adapter Layout of your Navigation bar:
<?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">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:orientation="horizontal"
android:background="#drawable/pressed_state">
<TextView
android:id="#+id/textView_list_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toRightOf="#+id/imageView_icons"
android:textStyle="bold"
android:layout_marginLeft="10dp"
android:textColor="#color/white"
android:textSize="17sp" />
<ImageView
android:id="#+id/list_adapter_image"
android:layout_width="10dp"
android:layout_height="10dp"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:visibility="visible"
android:layout_marginRight="50dp"
android:background="#drawable/circle_orange"/>
</RelativeLayout>
<LinearLayout
android:layout_height="1dp"
android:layout_width="match_parent"
android:background="#EC1294"></LinearLayout>
</LinearLayout>
This param in RelativeLayout set the background color --> android:background="#drawable/pressed_state"
Make this "pressed_state.xml" in drawable folder.
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:drawable="#color/light_blue" android:state_pressed="true"/>
Excuse me for my english.
Open or create values\dimens.xml
Add this code:
<dimen name="design_bottom_navigation_text_size" tools:override="true">11sp</dimen>
<dimen name="design_bottom_navigation_active_text_size" tools:override="true">12sp</dimen>
It should work
The following constructor call attempts to style my custom RelativeLayout2 using the defStyleRes parameter but it has no effect. I ported this sample project to AndroidStudio and it worked ok.
public RelativeLayout2(Context context, IAttributeSet attributeSet)
: base(context, attributeSet, 0, Resource.Style.RelativeLayout2)
{
}
styles.xml
<resources>
<style name="RelativeLayout2">
<item name="android:layout_width">40dp</item>
<item name="android:layout_height">300dp</item>
<item name="android:background">#114499</item>
<item name="android:padding">50dp</item>
</style>
</resources>
activity_main.axml
<?xml version="1.0" encoding="utf-8"?>
<InflationWithStyle.RelativeLayout2
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="needs some style."/>
</InflationWithStyle.RelativeLayout2>
MainActivity.cs
namespace InflationWithStyle
{
[Activity(Label = "#string/app_name", Theme = "#style/AppTheme", MainLauncher = true)]
public class MainActivity : AppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.activity_main);
}
}
public class RelativeLayout2 : RelativeLayout
{
public RelativeLayout2(Context context, IAttributeSet attributeSet)
: base(context, attributeSet, 0, Resource.Style.RelativeLayout2)
{
}
}
}
Update (2018.09.12)
I tried styling a TextView as well, and set it's style's parent to android:Widget.TextView but it also had no effect.
styles.xml
<style name="TextView2" parent="android:Widget.TextView">
<item name="android:background">#204090</item>
</style>
TextView2
public class TextView2 : TextView
{
public TextView2(Context context, IAttributeSet attributeSet)
: base(context, attributeSet, 0, Resource.Style.TextView2)
{
}
}
activity_main.axml
<?xml version="1.0" encoding="utf-8"?>
<InflationWithStyle.RelativeLayout2
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:appNS="http://schemas.android.com/apk/res/InflationWithStyle.InflationWithStyle"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<!--style="#style/RelativeLayout2"-->
<!--appNS:style1="#style/RelativeLayout2"-->
<InflationWithStyle.TextView2
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="asdfasdfasdfasfasfasdfasfdasdfasfasdf"
/>
<!--style="#style/TextView2"-->
</InflationWithStyle.RelativeLayout2>
The following constructor call attempts to style my custom RelativeLayout2 using the defStyleRes parameter but it has no effect.
Neither the Styles and Themes documentation nor the Style resource documentation implies that the //style/#name value can be a View name and have things "magically linked". Instead, they both use a style attribute on the View, e.g.
<?xml version="1.0" encoding="utf-8"?>
<CustomeView.RelativeLayout2
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
style="#style/RelativeLayout2">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="An utter lack of style."/>
</CustomeView.RelativeLayout2>
I have tested your code with this method, it works fine.
Google recently released the android.support.design.widget.NavigationView widget as part of the com.android.support:design:22.2.0 library, which greatly simplified (and standardises) the process of creating a NavigationDrawer.
However according to the design specs, the list item should be Roboto Medium, 14sp, 87% #000000. The NavigationView exposes no textSize or textStyle to customise this.
What are my options if I'm pedantic about maintaining the correct design specifications using the Google provided NavigationView (or customising it in any other way)?
Create new style at the file app/src/main/res/values/styles.xml
<style name="NavigationDrawerStyle">
<item name="android:textSize">20sp</item><!-- text size in menu-->
<!-- item size in menu-->
<item name="android:listPreferredItemHeightSmall">40dp</item>
<item name="listPreferredItemHeightSmall">40dp</item>
<!-- item padding left in menu-->
<item name="android:listPreferredItemPaddingLeft">8dp</item>
<item name="listPreferredItemPaddingLeft">8dp</item>
<!-- item padding right in menu-->
<item name="android:listPreferredItemPaddingRight">8dp</item>
<item name="listPreferredItemPaddingRight">8dp</item>
</style>
Add it to your main_layout.xml
<android.support.design.widget.NavigationView
...
app:theme="#style/NavigationDrawerStyle"
....>
</android.support.design.widget.NavigationView>
All params of the navigation items (which you can change) are located here (path to file ...\sdk\extras\android\support\design\res\layout\design_navigation_item.xml )
design_navigation_item.xml
<android.support.design.internal.NavigationMenuItemView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="?attr/listPreferredItemHeightSmall"
android:paddingLeft="?attr/listPreferredItemPaddingLeft"
android:paddingRight="?attr/listPreferredItemPaddingRight"
android:drawablePadding="#dimen/navigation_icon_padding"
android:gravity="center_vertical|start"
android:maxLines="1"
android:fontFamily="sans-serif-thin"
android:textSize="22sp"
android:textAppearance="?attr/textAppearanceListItem" />
Also you can override *.xml file (copy file from ...\sdk\extras\android\support\design\res\layout\design_navigation_item.xml), just in your app/src/main/res/layout folder create a layout named the same design_navigation_item.xml.
All layouts which can be Overriden are located here ...\sdk\extras\android\support\design\res\layout\
design_layout_snackbar.xml
design_layout_snackbar_include.xml
design_layout_tab_icon.xml
design_layout_tab_text.xml
design_navigation_item.xml
design_navigation_item_header.xml
design_navigation_item_separator.xml
design_navigation_item_subheader.xml
design_navigation_menu.xml
[UPDATE] Each version of com.android.support:design-{version} lib has different items to override.
Check all what you need in
[UPDATE 04/14/2020]
If you are using com.google.android.material.navigation.NavigationView
then open the class, and you will see:
public NavigationView(#NonNull Context context, #Nullable AttributeSet attrs) {
this(context, attrs, R.attr.navigationViewStyle);
}
So you can use attr navigationViewStyle to set your own style for the NavigationView via theme of your app:
NB: parent theme of AppTheme should be Theme.MaterialComponents
<style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar.Bridge">
...
<item name="navigationViewStyle">#style/AppNavigationViewStyle</item>
...
</style>
<style name="AppNavigationViewStyle" parent="Widget.MaterialComponents.NavigationView">
<item name="itemTextAppearance">#style/AppNavigationViewItemTextAppearance</item>
</style>
<style name="AppNavigationViewItemTextAppearance" parent="#style/TextAppearance.MaterialComponents.Subtitle2">
<item name="android:textSize">18sp</item>
</style>
Just open parent theme to see all <item name attrs for override
Since Android Support Library 22.2.1, Google has changed default textSize of items in NavigationView from 16sp to 14sp, which suits Material Design guideline well. However, in some cases(for example, when you want to support Chinese language), it seems larger textSize is better. Solution is simple:
add app:theme="#style/yourStyle.Drawer" to your NavigationView in your layout.xml
in styles.xml, add android:textSize="16sp" in style yourStyle.Drawer
You can customize everything from text color to size and font in your style.xml
<style name="NavDrawerTextStyle" parent="Base.TextAppearance.AppCompat">
<item name="android:textColor">#color/colorPrimaryDark</item>
<item name="android:textSize">16sp</item>
<item name="android:textStyle">bold</item>
</style>
and then in your NavigationView:
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<android.support.design.widget.NavigationView
...
android:itemTextAppearance="#style/NavDrawerTextStyle"
/>
you can use this attributes inside xml file
app:itemTextAppearance="?android:attr/textAppearanceMedium"
or for small text
app:itemTextAppearance="?android:attr/textAppearance"
or for large text
app:itemTextAppearance="?android:attr/textAppearanceLarge"
This worked for me:
activity_main.xml
<android.support.design.widget.NavigationView
android:id="#+id/navigation_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:theme="#style/NavigationDrawerStyle"
app:headerLayout="#layout/navdrawer_header"
app:menu="#menu/navdrawer_menu" />
styles.xml
<style name="NavigationDrawerStyle">
<item name="android:textSize">16sp</item>
</style>
Scouring through the source code I found this layout file
/platform/frameworks/support/.../design/res/layout/design_drawer_item.xml
with the following attribute
<android.support.design.internal.NavigationMenuItemView
...
android:textAppearance="?attr/textAppearanceListItem"
Which meant all we had to do was to override the textAppearanceListItem style in our project.
res/values/styles.xml
<style name="AppTheme" ... >
...
<item name="textAppearanceListItem">#style/list_item_appearance</item>
</style>
<style name="list_item_appearance">
<item name="android:textSize">14sp</item>
<item name="android:fontFamily">sans-serif-medium</item>
</style>
I'm not totally sure what else this will affect but if anyone has a better answer I'd be happy to accept that instead!
Maybe it might help. Recently I had to do this programmatically.
I used this class:
public class CustomTypefaceSpan extends TypefaceSpan {
private final Typeface newType;
private final float newSp;
public CustomTypefaceSpan(String family, Typeface type, float sp) {
super(family);
newType = type;
newSp = sp;
}
#Override
public void updateDrawState(TextPaint ds) {
applyCustomTypeFace(ds, newType, newSp);
}
#Override
public void updateMeasureState(TextPaint paint) {
applyCustomTypeFace(paint, newType, newSp);
}
private static void applyCustomTypeFace(Paint paint, Typeface tf, float sp) {
int oldStyle;
Typeface old = paint.getTypeface();
if (old == null) {
oldStyle = 0;
} else {
oldStyle = old.getStyle();
}
int fake = oldStyle & ~tf.getStyle();
if ((fake & Typeface.BOLD) != 0) {
paint.setFakeBoldText(true);
}
if ((fake & Typeface.ITALIC) != 0) {
paint.setTextSkewX(-0.25f);
}
paint.setTextSize(sp);
paint.setTypeface(tf);
}
#SuppressWarnings("unused")
public static final Parcelable.Creator<CustomTypefaceSpan> CREATOR = new Parcelable.Creator<CustomTypefaceSpan>() {
#Override
public CustomTypefaceSpan createFromParcel(Parcel in) {
return null;
}
#Override
public CustomTypefaceSpan[] newArray(int size) {
return new CustomTypefaceSpan[size];
}
};
}
Then I used like this:
// This is for color
SpannableString s = new SpannableString(item.getTitle().toString());
s.setSpan(new ForegroundColorSpan(Color.RED), 0, s.length(), 0);
// This is for typeface and size
Typeface typeFace = Functions.getTypeface(this, "Avenir");
if (typeFace != null) {
int size = 19;
float scaledSizeInPixels = size * getResources().getDisplayMetrics().scaledDensity;
CustomTypefaceSpan spanTypeFace = new CustomTypefaceSpan(item.getTitle().toString(), typeFace, scaledSizeInPixels);
s.setSpan(spanTypeFace, 0, s.length(), 0);
}
item.setTitle(s);
Hope this helps.
Goto activity_main.xml and select nav_view in design and you can change menu item text size by updating itemTextAppearance and itemTextColor like as follows
For com.google.android.material.navigation.NavigationView you should use the app namespace with your custom style:
app:itemTextAppearance="#style/NavDrawerTextStyle"
List Adapter Layout of your Navigation bar:
<?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">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:orientation="horizontal"
android:background="#drawable/pressed_state">
<TextView
android:id="#+id/textView_list_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toRightOf="#+id/imageView_icons"
android:textStyle="bold"
android:layout_marginLeft="10dp"
android:textColor="#color/white"
android:textSize="17sp" />
<ImageView
android:id="#+id/list_adapter_image"
android:layout_width="10dp"
android:layout_height="10dp"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:visibility="visible"
android:layout_marginRight="50dp"
android:background="#drawable/circle_orange"/>
</RelativeLayout>
<LinearLayout
android:layout_height="1dp"
android:layout_width="match_parent"
android:background="#EC1294"></LinearLayout>
</LinearLayout>
This param in RelativeLayout set the background color --> android:background="#drawable/pressed_state"
Make this "pressed_state.xml" in drawable folder.
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:drawable="#color/light_blue" android:state_pressed="true"/>
Excuse me for my english.
Open or create values\dimens.xml
Add this code:
<dimen name="design_bottom_navigation_text_size" tools:override="true">11sp</dimen>
<dimen name="design_bottom_navigation_active_text_size" tools:override="true">12sp</dimen>
It should work
The problem I am trying to solve is to have a custom font in an android application. I have followed a few tutorials and stack overflow questions but I can't seem to get exactly what I want.
I have a custom attribute defined in attrs.xml:
<resources>
<declare-styleable name="CustomTextView">
<attr name="customTypeface" format="string"/>
</declare-styleable>
and that customTypeface defined in the style:
<style name="posTheme" parent="#android:style/Theme.Holo.Light">
<item name="android:textViewStyle">#style/posThemeTextViewStyle</item>
</style>
<style name="posThemeTextViewStyle" parent="android:Widget.TextView">
<item name="android:textSize">50sp</item>
<item name="customTypeface">Fonts/MuseoSans_100.otf</item>
</style>
in an activity the form looks looks like:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:id="#+id/tv1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="LOL OL U MAD BRO!"
/>
<myApplication.Controls.CustomTextView
android:id="#+id/tv2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="LOL OL U MAD BRO!"
></myApplication.Controls.iQTextView>
</LinearLayout>
and when I go about trying to get the attribute:
public CustomTextView(Context context, IAttributeSet attrs, int defStyle)
: base(context, attrs, defStyle)
{
var a = context.ObtainStyledAttributes(attrs,
Resource.Styleable.CustomTextView);
var customFont = a.GetString(Resource.Styleable.CustomTextView_customTypeface);
SetCustomFont(customFont);
a.Recycle();
}
customFont is null, unless I implicitly define custom:customTypeface="" in the activity but I don't want to have to define the font for every single instance of the control.
What am I missing?
Shouldn't those two lines :
var a = context.ObtainStyledAttributes(attrs,
Resource.Styleable.CustomTextView);
var customFont = a.GetString(Resource.Styleable.CustomTextView_customTypeface);
be :
var a = context.ObtainStyledAttributes(attrs,
R.Styleable.CustomTextView);
var customFont = a.GetString(R.Styleable.CustomTextView_customTypeface);
I'm trying to figure out how to add an outer glow to a TextView when it's touched. The approach I'm working with is to use a Selector, but it doesn't seem to be working.
I've got the following structure
layout\HomeView.axml
<TextView
android:id="#+id/textview1"
android:clickable="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
style="#drawable/control_selector_state" />
drawable\control_selector_state.xml
<!-- yes these are all the same for testing purposes -->
<?xml version="1.0" encoding="utf-8" ?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true"
style="#style/control_style_focused"/>
<item android:state_focused="true"
android:state_pressed="true"
style="#style/control_style_focused" />
<item android:state_pressed="true"
style="#style/control_style_focused" />
<item style="#style/control_style_focused" />
</selector>
values\styles.xml
<resources>
<style name="control_style_focused">
<item name="android:shadowColor">#0000ff</item>
<item name="android:textColor">#ff0000</item>
<item name="android:shadowDx">0.0</item>
<item name="android:shadowRadius">8</item>
</style>
</resources>
The problem I'm having is that my TextView text is white, and the style doesn't seem to be applying.
How do I get this style to apply to my TextView?
so as #Longwayto said, selector styles are only available for drawables. That doesn't mean it's impossible.
Here's a working approach.
First you create a custom TextView that extends TextView
public class MyTextView: TextView
{
private readonly Context _context;
public FontIconTextView(Context context, IAttributeSet attrs) : base(context)
{
_context = context;
Initialize(attrs);
}
private void Initialize(IAttributeSet attrs)
{
var a = _context.Theme.ObtainStyledAttributes(attrs, Resource.Styleable.MyTextView, 0, 0);
_touchGlowColor = a.GetString(Resource.Styleable.MyTextView_TouchGlowColor);
_touchGlowSize = a.GetInteger(Resource.Styleable.MyTextView_TouchGlowSize, 0);
Initialize();
}
private void Initialize()
{
// other initialize stuff happens here...
}
private int _touchGlowSize;
private string _touchGlowColor;
public override bool OnTouchEvent(MotionEvent motionEvent)
{
if (Enabled)
{
var color = string.IsNullOrEmpty(_touchGlowColor) ? new Color(255, 255, 255, 255) : Color.ParseColor(_touchGlowColor);
switch (motionEvent.Action)
{
case MotionEventActions.Down:
SetShadowLayer(_touchGlowSize, 0, 0, color);
break;
case MotionEventActions.Up:
case MotionEventActions.Cancel:
SetShadowLayer(0, 0, 0, new Color(255, 255, 255, 255));
break;
}
}
return base.OnTouchEvent(motionEvent);
}
}
then, you have to go into your values directory and specify your custom attributes.
Resources\values\CustomBindingAttributes.xml
<?xml version="1.0" encoding="utf-8" ?>
<resources>
<declare-styleable name="MyTextView">
<attr name="TouchGlowColor" format="string" />
<attr name="TouchGlowSize" format="integer" />
</declare-styleable>
</resources>
All of the above will be reusable across your entire application... no more duplicating shit on every view.
Lastly, here's how your button will look.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- obviously the foo/bar is just to show that you add android attrs like normal -->
<some.name.space.MyTextView
android:foo="foo"
amdroid:bar="bar"
local:TouchGlowColor="#66e400"
local:TouchGlowSize="20" />
</LinearLayout>
one gotcha I ran into is setting TouchGlowSize to 30 caused the app to crash. not sure why atm