8

I have an application with min sdk 16 up to 23. I want to use Material design as much as possible. It also has to be fullscreen app. AppCompat support library is included. Now I have Logon activity with some buttons:

<Button
    android:id="@+id/act_logon_btn_logon"
    style="@style/ButtonDefault"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@string/act_logon_logon" />

Styles are as follows (values/styles.xml):

<style name="Theme.AppCompat.Light.NoActionBar.FullScreen" parent="@style/Theme.AppCompat.Light">
    <item name="windowNoTitle">true</item>
    <item name="windowActionBar">false</item>
    <item name="android:windowFullscreen">true</item>
    <item name="android:windowContentOverlay">@null</item>
</style>

<style name="AppThemeBase" parent="Theme.AppCompat.Light.NoActionBar.FullScreen"></style>

<style name="AppTheme" parent="AppThemeBase"></style>

<style name="ButtonDefault" parent="Widget.AppCompat.Button">
    <item name="android:textSize">?attr/font_medium</item>
</style>

<style name="FontStyle"></style>

<style name="FontStyle.Small">
    <item name="font_small">12sp</item>
    <item name="font_medium">14sp</item>
    <item name="font_large">16sp</item>
</style>

<style name="FontStyle.Medium">
    <item name="font_small">16sp</item>
    <item name="font_medium">18sp</item>
    <item name="font_large">20sp</item>
</style>

<style name="FontStyle.Large">
    <item name="font_small">20sp</item>
    <item name="font_medium">22sp</item>
    <item name="font_large">24sp</item>
</style>

And in values/attrs:

<declare-styleable name="FontStyle">
    <attr name="font_small" format="dimension" />
    <attr name="font_medium" format="dimension" />
    <attr name="font_large" format="dimension" />
</declare-styleable>

Attribute font_medium is defined as described here. The behavior I don't understand is that when the Logon activity gets opened, everything is OK, no exceptions. But when I open another activity from Logon activity with fragment inside and the fragment has a button with this style, I get an exception saying "Error inflating class Button". When I delete the textSize attribute from the ButtonDefault style, everything works. Why it does work somewhere and somewhere not? Is there something wrong with the custom attribute?

I've tried to create values-v21/styles.xml with that style but without effect.

Can you also please explain differences between following parent style definitions? I'm getting lost.

parent="Widget.AppCompat.Button"
parent="@style/Widget.AppCompat.Button"
parent="android:Widget.Button"
parent="android:Widget.AppCompat.Button"
parent="android:Widget.Material.Button"
parent="android:style/Widget.Material.Button"

Thank you.

EDIT 1 - exception:

12-17 10:56:53.950: E/AndroidRuntime(7251): FATAL EXCEPTION: main
12-17 10:56:53.950: E/AndroidRuntime(7251): Process: test.android, PID: 7251
12-17 10:56:53.950: E/AndroidRuntime(7251): java.lang.RuntimeException: Unable to start activity ComponentInfo{test.dci.android/test.dci.android.view.activity.TransactionActivity}: android.view.InflateException: Binary XML file line #49: Error inflating class Button
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2702)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2767)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.app.ActivityThread.access$900(ActivityThread.java:177)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1449)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.os.Handler.dispatchMessage(Handler.java:102)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.os.Looper.loop(Looper.java:145)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.app.ActivityThread.main(ActivityThread.java:5951)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at java.lang.reflect.Method.invoke(Native Method)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at java.lang.reflect.Method.invoke(Method.java:372)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1400)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1195)
12-17 10:56:53.950: E/AndroidRuntime(7251): Caused by: android.view.InflateException: Binary XML file line #49: Error inflating class Button
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:770)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.view.LayoutInflater.rInflate(LayoutInflater.java:813)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.view.LayoutInflater.rInflate(LayoutInflater.java:821)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.view.LayoutInflater.inflate(LayoutInflater.java:511)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.view.LayoutInflater.inflate(LayoutInflater.java:415)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at test.dci.android.view.fragment.TransactionFragment.onCreateView(TransactionFragment.java:71)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.support.v4.app.Fragment.performCreateView(Fragment.java:1962)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1036)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1226)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.support.v4.app.FragmentManagerImpl.addFragment(FragmentManager.java:1328)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.support.v4.app.FragmentManagerImpl.onCreateView(FragmentManager.java:2284)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.support.v4.app.FragmentController.onCreateView(FragmentController.java:111)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.support.v4.app.FragmentActivity.dispatchFragmentsOnCreateView(FragmentActivity.java:314)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.support.v4.app.BaseFragmentActivityHoneycomb.onCreateView(BaseFragmentActivityHoneycomb.java:31)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.support.v4.app.FragmentActivity.onCreateView(FragmentActivity.java:79)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at test.dci.android.view.activity.TransactionActivity.onCreateView(TransactionActivity.java:1)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:740)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.view.LayoutInflater.rInflate(LayoutInflater.java:813)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.view.LayoutInflater.inflate(LayoutInflater.java:511)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.view.LayoutInflater.inflate(LayoutInflater.java:415)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.view.LayoutInflater.inflate(LayoutInflater.java:366)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.support.v7.app.AppCompatDelegateImplV7.setContentView(AppCompatDelegateImplV7.java:256)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:109)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at test.dci.android.view.activity.TransactionActivity.onCreate(TransactionActivity.java:31)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.app.Activity.performCreate(Activity.java:6289)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1119)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2655)
12-17 10:56:53.950: E/AndroidRuntime(7251):     ... 10 more
12-17 10:56:53.950: E/AndroidRuntime(7251): Caused by: java.lang.RuntimeException: Failed to resolve attribute at index 12
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.content.res.TypedArray.getDimensionPixelSize(TypedArray.java:582)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.widget.TextView.<init>(TextView.java:1400)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.widget.Button.<init>(Button.java:115)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.widget.Button.<init>(Button.java:108)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.support.v7.widget.AppCompatButton.<init>(AppCompatButton.java:62)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.support.v7.widget.AppCompatButton.<init>(AppCompatButton.java:58)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.support.v7.app.AppCompatViewInflater.createView(AppCompatViewInflater.java:98)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.support.v7.app.AppCompatDelegateImplV7.createView(AppCompatDelegateImplV7.java:938)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at android.support.v7.app.AppCompatDelegateImplV7.onCreateView(AppCompatDelegateImplV7.java:992)
12-17 10:56:53.950: E/AndroidRuntime(7251):     at 
Community
  • 1
  • 1
Tomask
  • 2,344
  • 3
  • 27
  • 37
  • can you post your error – IntelliJ Amiya Dec 17 '15 at 09:54
  • 1
    Done. The error occurs not only with buttons but also with edittexts - with style that contains the custom fontSize attribute – Tomask Dec 17 '15 at 10:04
  • It seems that the exception `android.view.InflateException: Binary XML file line #49: Error inflating class Button` is caused by `java.lang.RuntimeException: Failed to resolve attribute at index 12` It seems that the inflater is having issues recognizing `?attr/font_medium`. Did you try changing that to a value, i.e.: 14sp, instead of removing textSize? – Luke47 Dec 17 '15 at 10:13
  • If I change the _textSize_ to specific value, as you said, it works. – Tomask Dec 17 '15 at 10:18

5 Answers5

11

COPY your image files from "drawable-v24" folder to the "drawable" folder as well. Problem solved. credit: https://github.com/chrisjenx/Calligraphy/issues/417

user3267567
  • 524
  • 4
  • 14
1

Solved. The problem is that the attribute is uknown (or not specified) for the inflater. The solution is to define attribute values before inflating views that use the attribute.

Solution 1: The style with this attribute must be specified not only in the activity, but also in the fragment that has some views with this attribute. So add this line to fragment's onCreateView() before the line that inflates fragment's root view:

getContext().getTheme().applyStyle(fontStyleResId, true);

Solution 2: Set attributes value directly in application's theme:

<style name="AppThemeBase" parent="Theme.AppCompat.Light.NoActionBar.FullScreen">
    <item name="font_small">@dimen/font_size_medium_small</item>
    <item name="font_medium">@dimen/font_size_medium_medium</item>
    <item name="font_large">@dimen/font_size_medium_large</item>
</style>
Community
  • 1
  • 1
Tomask
  • 2,344
  • 3
  • 27
  • 37
1

I fixed it by creating own appcompat style for api less then 21,

styles.xml

  <style name="ColoredButtonAppcompat">
    <item name="android:textAppearance">@style/ButtonTextStyle</item>
    <item name="android:background">@drawable/colored_button_background</item>
    <item name="android:minHeight">48dip</item>
    <item name="android:minWidth">88dip</item>
    <item name="android:focusable">true</item>
    <item name="android:clickable">true</item>
    <item name="android:gravity">center_vertical|center_horizontal</item>
</style>

<style name="ButtonTextStyle" >
    <item name="android:textSize">14dp</item>
    <item name="android:textColor">@android:color/white</item>
</style>

styles-v21.xml

<style name="ColoredButtonAppcompat" parent="Widget.AppCompat.Button.Colored"/>

0

As we discussed in the comment section, the problem is that the inflater somehow fails to recognize ?attr/font_medium, thus raising an exception.

You can use the dimens.xml file to specify custom dimensions, like this:

<resources> 
    <dimen name="small">14sp</dimen>
    <dimen name="medium">16sp</dimen>
    <dimen name="large">18sp</dimen>
</resources>

and then in your styles.xml you refer to these values like this:

<style name="ButtonDefault" parent="Widget.AppCompat.Button">
    <item name="android:textSize">@dimen/medium</item>
</style>

As every other resource, dimens.xml can be placed in the according resource folders to accomodate to a specific device configuration (screen dimensions, density, language, etc.).

Luke47
  • 1,583
  • 3
  • 11
  • 14
  • I'm a little rusty with Android development, but I think you can't refer to other attributes when using – Luke47 Dec 17 '15 at 10:51
  • But in that case I am not able to use different font size across the app as user choice in Preference activity... Or how to combine it? – Tomask Dec 18 '15 at 09:21
  • You can't set styles programmatically. You can allow the users to choose the preferred font and get the corresponding dimension from the dimens.xml file (remember that dimens.xml is a resource file). After that, you set the font size to your widgets. – Luke47 Dec 18 '15 at 11:20
  • I can not? So far I was using the `getTheme().applyStyle()` method and it worked... And how can I do this programatically? The only thing I want is to be able to choose font size in preference activity, that's all. – Tomask Dec 18 '15 at 20:58
0

I faced a similar situation while developing using Kotlin: In order to solve this issue, copy the app the content in drawable-24 to drawable. This is done to support older Android devices.

Boken
  • 4,825
  • 10
  • 32
  • 42