I have a customView
<com.google.android.libraries.onegoogle.account.disc.AccountParticleDisc
android:id="#+id/account_avatar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="?attr/disc_padding"
android:contentDescription="#null"
app:imageViewSize="?attr/disc_imageViewSize"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="#drawable/quantum_ic_account_circle_googblue_24"/>
and its java:
public AccountParticleDisc(#NonNull Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.account_particle_disc, this, true);
this.imageView = findViewById(R.id.og_apd_internal_image_view);
badgeWrapper = findViewById(R.id.badge_wrapper);
TypedArray style = context.obtainStyledAttributes(attrs, R.styleable.AccountParticleDisc);
int discSize;
int imageViewSize;
try {
avatarSize =
style.getDimensionPixelSize(R.styleable.AccountParticleDisc_avatarSize, SIZE_NOT_SET);
discSize =
style.getDimensionPixelSize(R.styleable.AccountParticleDisc_discSize, SIZE_NOT_SET);
imageViewSize =
style.getDimensionPixelSize(R.styleable.AccountParticleDisc_imageViewSize, SIZE_NOT_SET);
} finally {
style.recycle();
}
and these custom attributes:
<resources>
<declare-styleable name="AccountParticle">
<attr name="disc_padding" format="reference"/>
<attr name="disc_imageViewSize" format="reference"/>
</declare-styleable>
</resources>
with
<style name="Theme.ap.header" parent="Theme.AppCompat">
<item name="text_marginStart">#dimen/account_menu_header_signed_in_avatar_margin_start</item>
<item name="text_marginEnd"> #dimen/account_menu_header_signed_in_margin_end</item>
<item name="text_marginLeft"> #dimen/account_menu_header_signed_in_avatar_margin_start</item>
<item name="text_marginRight">#dimen/account_menu_header_signed_in_margin_end</item>
<item name="disc_imageViewSize"> #dimen/account_menu_header_signed_in_disc_size</item>
<item name="disc_padding"> #dimen/account_menu_header_signed_in_avatar_margin_end</item>
</style>
I inflate its viewGroup:
ContextThemeWrapper contextThemeWrapper = new ContextThemeWrapper(context,
R.style.Theme_ap_header);
LayoutInflater.from(contextThemeWrapper).inflate(R.layout.account_particle, this, true);
I get this error:
cause = {InflateException#12215} "android.view.InflateException: Binary XML file line #7: Error inflating class <unknown>"
detailMessage = "Binary XML file line #7: Binary XML file line #7: Error inflating class <unknown>"
how can i make the error more indicative?
I suspect that the package name for custom view is invalid.
If your package name is com.example.app & your CustomView is in the same package then you should use -
<com.example.app.CustomView
android:id="#+id/account_avatar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="?attr/disc_padding"
android:contentDescription="#null"
app:imageViewSize="?attr/disc_imageViewSize"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="#drawable/quantum_ic_account_circle_googblue_24"/>
Stucked with this problem when my activity was extending FragmentActivity. So with AppCompatActivity problem has gone.
Related
Is there a way to change the theme of a TextInputLayout programmatically in Android.
If I have the following TextInputLayout for ex.:
<android.support.design.widget.TextInputLayout
android:id="#+id/label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:paddingTop="16dp"
android:theme="#style/TextInputLayoutTheme"
app:errorTextAppearance="#style/Error">
<android.support.v7.widget.AppCompatEditText
android:id="#+id/edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="8dp"
android:paddingTop="8dp"/>
</android.support.design.widget.TextInputLayout>
Could I somehow change this line android:theme="#style/TextInputLayoutTheme" to another theme programmatically?
There is no way to change theme of any view or any layout at runtime. Because of themes and styles are applied during creation of view, recursively. (Themes also applies child views of layouts)
But, you can change that theme before creation of view using XML layout or programmatically.
Programmatically:
Method 1 - Create TextInputLayout programmatically with wrapping Context with android.view.ContextThemeWrapper and use.
TextInputLayout layout = new TextInputLayout(new ContextThemeWrapper(getContext(), R.style. TextInputLayoutTheme));
Method 2 - Extend TextInputLayout and use your own layout. Pass ContextThemeWrapper as context.
public class MyTextInputLayout extends TextInputLayout {
public MyTextInputLayout(Context context) {
super(new ContextThemeWrapper(context, R.style.AppTheme));
}
public MyTextInputLayout(Context context, AttributeSet attrs) {
super(new ContextThemeWrapper(context, R.style.AppTheme), attrs);
}
public MyTextInputLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(new ContextThemeWrapper(context, R.style.AppTheme), attrs, defStyleAttr);
}
}
Now, you can use MyTextInputLayout in your XML layout
With XML Layout:
1) In attrs.xml file, create new attribute named textInputLayoutTheme
<attr name="textInputLayoutTheme" format="reference"/>
2) In your AppTheme in styles.xml file set your #style/TextInputLayoutTheme as textInputLayoutTheme.
<resources>
<style name="AppTheme" parent="PARENT_THEME">
<item name="textInputLayoutTheme">#style/TextInputLayoutTheme</item>
</style>
<style name="AppTheme.Secondary">
<item name="textInputLayoutTheme">#style/TextInputLayoutTheme_Secondary</item>
</style>
</resources>
3) In your layout.xml file, set ?attr/textInputLayoutTheme as a TextInputLayout theme
<android.support.design.widget.TextInputLayout
android:id="#+id/label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:paddingTop="16dp"
android:theme="#?attr/textInputLayoutTheme"
app:errorTextAppearance="#style/Error">
Now, when you change your application theme from AppTheme to AppTheme.Secondary TextInputLayoutTheme_Secondary will be used as a theme of your TextInputLayout instead of TextInputLayoutTheme.
Unfortunately the accepted answer is not working for me.
My solution was to wrap TextInputLayout in a custom layout.
view_input_layout_wrapper.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:theme="#style/AppThemeMaterial"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/til"
style="#style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.textfield.TextInputEditText
android:id="#+id/edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>
</FrameLayout>
TextInputLayoutWrapper
class TextInputLayoutWrapper(context: Context) : FrameLayout(context) {
var inputLayout: TextInputLayout
private set
init {
inflate(context, R.layout.view_input_layout_wrapper, this)
inputLayout = findViewById(R.id.til)
}
}
Implementation in the view (fragment/activity):
private fun addNewField(fieldName: String) {
val textInputLayoutWrapper = TextInputLayoutWrapper(
requireContext()
).apply {
inputLayout.hint = fieldName
}
fieldsContainerViewGroup.addView(textInputLayoutWrapper)
}
NOTE: My app theme is not material theme, so I must add theme="#style/AppThemeMaterial" in the root ViewGroup of the TextInputLayout.
<style name="AppThemeMaterial" parent="Theme.MaterialComponents.Light">
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/colorAccent</item>
<item name="android:windowBackground">#android:color/black</item>
</style>
When I changed my minSdkVersion then I am getting this error:
android.view.InflateException: Binary XML file line #43: Error inflating class TextView
Eariler it was working fine before I have made the changes.
Here is my style :
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- All customizations that are NOT specific to a particular API-level can go here. -->
</style>
<style name="AppTheme.Dark" parent="Theme.AppCompat.NoActionBar">
<item name="colorPrimary">#color/primary</item>
<item name="colorPrimaryDark">#color/primary_dark</item>
<item name="colorAccent">#color/white</item>
<item name="colorControlNormal">#color/greyDark</item>
<item name="colorControlActivated">#color/off_white</item>
<item name="android:windowBackground">#color/pink</item>
<item name="android:fontFamily">sans-serif-light</item>
<item name="android:textStyle">normal</item>
<item name="android:windowContentTransitions" tools:targetApi="lollipop">true</item>
<item name="android:windowAllowEnterTransitionOverlap" tools:targetApi="lollipop">true</item>
<item name="android:windowAllowReturnTransitionOverlap" tools:targetApi="lollipop">true</item>
<item name="android:windowSharedElementEnterTransition" tools:targetApi="lollipop">#android:transition/move</item>
<item name="android:windowSharedElementExitTransition" tools:targetApi="lollipop">#android:transition/move</item>
</style>
<style name="AlertDialogCustom" parent="#android:style/Theme.Dialog">
<item name="android:textColor">#color/pink</item>
<item name="android:typeface">normal</item>
<item name="android:height">5dp</item>
<item name="android:textSize">20sp</item>
<item name="android:textStyle">bold</item>
<item name="android:background">#color/white</item>
</style>
I guess there is something wrong with the parent property of a style.
If you are changing your version then also change the support library.You have to change the support lib like for e.g.for api 23 you have to chnage the appcompact library version to 23.
Hope this help.:)
You should try changing
<style name="AlertDialogCustom" parent="#android:style/Theme.Dialog">
to
<style name="AlertDialogCustom" parent="Theme.AppCompat.Dialog">
This is the issue with your font family which you are using in style. May be sans-serif-light font is not available in your assests>>fonts folder. So check with this how to use custom fonts in android.
Here are the steps to follow:
Android Studio:
Step1: Adding font family files to app
A) Go to the (project folder)
B) Then app>src>main
C) Create folder 'assets>fonts' into the main folder.
D) Put your 'abc.ttf' or 'abc.otf' font file into the fonts folder.
Step 2:
Now Create attrs.xml under res folder if it's not exists and add declare-styleable
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="Font">
<attr name="typeface">
<enum name="FuturaLT" value="0" />
<enum name="FuturaLT_Heavy" value="1" />
<enum name="FuturaLT_Light" value="2" />
</attr>
</declare-styleable>
</resources>
//Here FuturaLT/FuturaLT_Heavy/FuturaLT_Light are file names
Note: – enum name should be font type name with underscore(_) uses, it will be easy for you to understand font family usage in your native code. No special character or other letter, otherwise you will got error in gen folder for same attribute id.
Step 3: Create your custom view(Button, TextView, EditText) class:-
package com.myapp.views;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.widget.TextView;
import com.myapp.R;
public class CustomTextView extends TextView {
public CustomTextView(Context context) {
super(context);
}
public CustomTextView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
try {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Font);
int font = a.getInt(R.styleable.Font_typeface, 0);
a.recycle();
String str;
switch (font) {
case 1:
str = "fonts/FuturaLT.otf";
break;
case 2:
str = "fonts/FuturaLT_Heavy.otf";
break;
case 3:
str = "fonts/FuturaLT_Light.otf";
break;
default:
str = "fonts/FuturaLT.otf";
break;
}
setTypeface(FontManager.getInstance(getContext()).loadFont(str));
} catch (Exception e) {
e.printStackTrace();
}
}
#SuppressWarnings("unused")
private void internalInit(Context context, AttributeSet attrs) {
}
}
Step 4: Add FontManager.java support class
package com.myapp.views;
import android.content.Context;
import android.graphics.Typeface;
import java.util.HashMap;
import java.util.Map;
public class FontManager {
private Map<String, Typeface> fontCache = new HashMap<String, Typeface>();
private static FontManager instance = null;
private Context mContext;
private FontManager(Context mContext2) {
mContext = mContext2;
}
public synchronized static FontManager getInstance(Context mContext) {
if (instance == null) {
instance = new FontManager(mContext);
}
return instance;
}
public Typeface loadFont(String font) {
if (false == fontCache.containsKey(font)) {
fontCache.put(font, Typeface.createFromAsset(mContext.getAssets(), font));
}
return fontCache.get(font);
}
}
Step 5: Usage in XML layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.myapp.views.CustomTextView
android:id="#+id/tv_time_slot"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
app:typeface="FuturaLT" />
</LinearLayout>
You can also use in java code directly:
Typeface tf = Typeface.createFromAsset(getAssets(), "fonts/FuturaLT.ttf");
tvText.setTypeface(tf);
Note:- If you don't use here FontManager to apply typeface and directly use
then you are not able to see your views in graphics preview.
I'm trying to put the custom XML namespace in the styles.xml and inherit it in the layout. I don't know how to declare the custom XML namespace in the styles.xml as I do in layout xml (e.g. xmlns:app="http://schemas.android.com/tools").
How do I use custom XML namespace in the styles.xml?
What I have:
The font asset, ReallyCoolFont.ttf is saved in the asset/fonts.
my_layout.xml:
<TextView
<!-- more attributes here -->
app:customFont="fonts/ReallyCoolFont.ttf"
<!-- more attributes here -->
</TextView>
styles.xml:
<style name="CoolTextView">
<!-- more items here -->
<!-- more items here -->
</style>
What I'd like to have:
my_layout.xml:
<TextView
<!-- more attributes here -->
style="#style/CoolTextView
<!-- more attributes here -->
</TextView>
styles.xml:
<style name="CoolTextView">
<!-- more items here -->
<item name="app:customFont">ReallyCoolFont.ttf</item>
<!-- more items here -->
</style>
Error I get:
Error:(1403, 21) No resource found that matches the given name: attr 'app:customFont'.
You need to define an attribute for your fonts in attr.xml file in res folder:
<attr name="myfonts" format="string" />
And you need to define custom style for your TextView and here we use our defined attribute(myfonts):
<declare-styleable name="MyCustomStyle">
<attr name="myfonts" />
</declare-styleable>
Then styles can be declared:
<style name="CoolTextView">
<item name="myfonts">ReallyCoolFont.ttf</item>
</style>
summary of what you have so far:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="myfonts" format="string">
</attr>
<declare-styleable name="MyCustomStyle">
<attr name="myfonts" />
</declare-styleable>
<style name="CoolTextView">
<item name="myfonts">ReallyCoolFont.ttf</item>
</style>
</resources>
4)Now your layout would be:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.example.MyCustomTextView
android:id="#+id/result"
style="#style/CoolTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="HELLO WORLD!"
android:textSize="24dp"
android:gravity="center" >
</com.example.MyCustomTextView>
</RelativeLayout>
5)and your MyCustomTextView is:
public class MyCustomTextView extends TextView {
private static final String TAG = "TextView";
public MyCustomTextView(Context context) {
super(context);
}
public MyCustomTextView(Context context, AttributeSet attrs) {
super(context, attrs);
settingFont(context, attrs);
}
public MyCustomTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
settingFont(context, attrs);
}
private void settingFont(Context ctx, AttributeSet attrs) {
TypedArray a = ctx.obtainStyledAttributes(attrs, R.styleable.MyCustomStyle);
String customFont = a.getString(R.styleable.MyCustomStyle_myfonts);
Typeface tf = null;
try {
tf = Typeface.createFromAsset(ctx.getAssets(), customFont);
} catch (Exception e) {
Log.e(TAG,e.getMessage());
a.recycle();
return;
}
setTypeface(tf);
a.recycle();
}
}
I assumed you put the font in asset not in asset/fonts directory.
also I highly recommend read this.
You don't need to add any prefix to reference your custom attributes in the style resource files. Doing it like this will work just fine:
<style name="CoolTextView">
<item name="customFont">ReallyCoolFont.ttf</item>
</style>
The answer is to NOT specify the namespace in the style.
<?xml version="1.0" encoding="utf-8" ?>
<resources xmlns:custom="http://schemas.android.com/apk/res/com.custom.project">
<style name="CustomStyle">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="customAttr">value</item> <!-- tee hee -->
</style>
</resources>
You don't need any prefixes, it will work without them. This is code from one of my projects, which works just fine
<style name="defaultTriangle">
<item name="triangleColor">#FF33B5E5</item>
<item name="triangleStrokeColor">#android:color/black</item>
<item name="triangleStrokeWidth">3dp</item>
</style>
<si.kseneman.views.Triangle
style="#style/defaultTriangle"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:padding="10dp"
android:rotation="0"
/>
I've done next for custom font
CustomTextView
public class KlavikaTextView extends TextView {
private final static int KLAVIKA_BOLD = 0;
private final static int KLAVIKA_BOLD_ITALIC = 1;
private final static int KLAVIKA_LIGHT = 2;
private final static int KLAVIKA_LIGHT_ITALIC = 3;
private final static int KLAVIKA_MEDIUM = 4;
private final static int KLAVIKA_MEDIUM_ITALIC = 5;
private final static int KLAVIKA_REGULAR = 6;
private final static int KLAVIKA_REGULAR_ITALIC = 7;
public KlavikaTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
parseAttributes(context, attrs);
}
public KlavikaTextView(Context context, AttributeSet attrs) {
super(context, attrs);
parseAttributes(context, attrs);
}
public KlavikaTextView(Context context) {
super(context);
}
private void parseAttributes(Context context, AttributeSet attrs) {
TypedArray values = context.obtainStyledAttributes(attrs, R.styleable.KlavikaTextView);
// The value 0 is a default, but shouldn't ever be used since the attr is an enum
int typeface = values.getInt(R.styleable.KlavikaTextView_typeface, KLAVIKA_REGULAR);
// You can instantiate your typeface anywhere, I would suggest as a
// singleton somewhere to avoid unnecessary copies
switch (typeface) {
case KLAVIKA_BOLD:
setTypeface(App.klavikaBold);
break;
case KLAVIKA_BOLD_ITALIC:
setTypeface(App.klavikaBoldItalic);
break;
case KLAVIKA_LIGHT:
setTypeface(App.klavikaLight);
break;
case KLAVIKA_LIGHT_ITALIC:
setTypeface(App.klavikaLightItalic);
break;
case KLAVIKA_MEDIUM:
setTypeface(App.klavikaMedium);
break;
case KLAVIKA_MEDIUM_ITALIC:
setTypeface(App.klavikaMediumItalic);
break;
case KLAVIKA_REGULAR_ITALIC:
setTypeface(App.klavikaRegularItalic);
break;
case KLAVIKA_REGULAR:
default:
setTypeface(App.klavikaRegular);
break;
}
}}
Then in values I've created attr.xml
<!-- Define the values for the attribute -->
<attr name="typeface" format="enum">
<enum name="klavika_bold" value="0" />
<enum name="klavika_bold_italic" value="1" />
<enum name="klavika_light" value="2" />
<enum name="klavika_light_italic" value="3" />
<enum name="klavika_medium" value="4" />
<enum name="klavika_medium_italic" value="5" />
<enum name="klavika_regular" value="6" />
<enum name="klavika_regular_italic" value="7" />
</attr>
<!--
Tell Android that the class "KlavikaTextView" can be styled,
and which attributes it supports-->
<declare-styleable name="KlavikaTextView">
<attr name="typeface" />
</declare-styleable>
Next created the style
<style name="TextView.Example">
<item name="typeface">klavika_bold</item>
</style>
This style you can use for your xml Layouts
style="#style/TextView.Example"
<?xml version="1.0" encoding="utf-8"?>
<resources
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res/com.my.project">
<style name="my_style"> <item name="custom:tag">some_value</item> </style>
</resources>
you are trying to apply XML namespacing to an attribute value, which won't work. In this case, you should specify the package name directly, like this:
<style name="my_style"> <item name="com.my.project:tag">some_value</item> </style>
Fast solution via code!
String pathFont = "fonts/ReallyCoolFont.ttf";
TextView text = (TextView) findViewById(R.id.TextView1);
Typeface fontFace = Typeface.createFromAsset( getAssets(), pathFont );
text.setTypeface( fontFace );
Third-party libraries , solve the problem, in XML!
1 - https://github.com/leok7v/android-textview-custom-fonts
2 - https://github.com/ragunathjawahar/android-typeface-textview
My suggestion
You will have other needs, and for each component
you will have to customize a class.
Another problem you have other layouts and N TextView components
for maintenance you will have a lot of work .
I use this method in projects in the OnCreate of my activity
if I need to change the font I have to do this
only in the OnCreate method of each activity .
private static final String FONT = "ReallyCoolFont.ttf";
public static void allTextView(final Context context, final View root) {
String fontPath = FONT;
try {
if (root instanceof ViewGroup) {
ViewGroup viewGroup = (ViewGroup) root;
int childCount = viewGroup.getChildCount();
for (int i = 0; i < childCount; i++)
allTextView(context, viewGroup.getChildAt(i) );
} else if (root instanceof TextView)
((TextView) root).setTypeface(Typeface.createFromAsset(context.getAssets(), fontPath));
} catch (Exception e) {
e.printStackTrace();
}
}
// call in OnCreate Activity
allTextView(this, findViewById(R.layout.main) );
The custom attributes are defined using <declare-styleable> tags; usually the file is called attrs.xml. The namespace declaration will have your app's package name in it.
The whole process is described here: Creating a View Class | Android Developers
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 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