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
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>