【发布时间】:2015-09-14 16:45:28
【问题描述】:
我尝试使用默认样式为自定义(和派生)视图设置主题。 我的解决方案基于此 answer 但仅适用于 api >= 21 并且会在所有早期版本上崩溃。 我正在将 AppCompat appcompat-v7 与新的 AppCompatActivity 基类一起使用。
我的自定义视图:
public class TintableImageButton extends ImageButton {
private ColorStateList tint;
public TintableImageButton(Context context) {
this(context, null);
}
public TintableImageButton(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.tintedImageButtonStyle);
}
public TintableImageButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public TintableImageButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs, defStyleAttr);
}
private void init(Context context, AttributeSet attrs, int defStyle) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TintableImageButton, defStyle, 0);
tint = a.getColorStateList(R.styleable.TintableImageButton_tint);
a.recycle();
}
....
}
不使用 tintedImageButtonStyle 的自定义视图有效(在 stackoverflow 上也可以找到)。
attr.xml
<resources>
<declare-styleable name="TintableImageButton">
<attr name="tint" format="reference|color" />
</declare-styleable>
<declare-styleable name="CustomTheme">
<attr name="tintedImageButtonStyle" format="reference"/>
</declare-styleable>
</resources>
我已经看到了一些在可声明样式之外声明主题属性引用的示例。但我不明白其中的区别,尤其是在引用的 stackoverflow 帖子中 name="CustomTheme" 的含义。
themes.xml
<resources>
<style name="Base.Theme.ElectroBoxApp" parent="Theme.AppCompat.Light.NoActionBar">
....
</style>
<style name="AppBaseTheme" parent="Base.Theme.ElectroBoxApp">
....
</style>
<style name="AppTheme" parent="AppBaseTheme">
<item name="tintedImageButtonStyle">@style/TintedImageButton</item>
</style>
</resources>
styles.xml
<resources>
<style name="TintedImageButton" parent="Base.Widget.AppCompat.Button">
<item name="android:minWidth">48dp</item>
<item name="android:paddingLeft">4dp</item>
<item name="android:paddingRight">4dp</item>
<item name="android:clickable">true</item>
<item name="android:background">@drawable/btn_default_background</item>
<item name="android:scaleType">center</item>
<item name="tint">@color/button_tint_csl</item>
</style>
</resources>
drawable/btn_default_background.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?attr/selectableItemBackgroundBorderless"/>
<item android:top="4dp" android:left="4dp" android:bottom="4dp" android:right="4dp">
<shape android:shape="oval">
<size android:height="30dp" android:width="30dp"/>
<solid android:color="?attr/colorAccent"/>
</shape>
</item>
</layer-list>
AndroidManifest.xml
....
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="23"/>
<application android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:name=".AppController"
android:theme="@style/AppTheme">
....
</application>
示例布局 sn-p
<!-- line 31 is below -->
<de.NullZero.ManiDroid.presentation.views.TintableImageButton
android:id="@+id/btnPlaylist"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:src="@drawable/ic_library_music_white_24dp"
/>
在 Lollipop 上,它按预期工作,但在 kitkat 及下方使用这样的按钮填充布局时会崩溃。
09-14 12:06:57.800 1939-1962/de.NullZero.ManiDroid E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: de.NullZero.ManiDroid, PID: 1939
java.lang.RuntimeException: Unable to start activity ComponentInfo{de.NullZero.ManiDroid/de.NullZero.ManiDroid.presentation.ManiDroidAppActivity}: android.view.InflateException: Binary XML file line #31: Error inflating class de.NullZero.ManiDroid.presentation.views.TintableImageButton
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2195)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245)
at android.app.ActivityThread.access$800(ActivityThread.java:135)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5017)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
at dalvik.system.NativeStart.main(Native Method)
Caused by: android.view.InflateException: Binary XML file line #31: Error inflating class de.NullZero.ManiDroid.presentation.views.TintableImageButton
at android.view.LayoutInflater.createView(LayoutInflater.java:621)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:697)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:756)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:759)
at android.view.LayoutInflater.inflate(LayoutInflater.java:492)
at android.view.LayoutInflater.inflate(LayoutInflater.java:397)
at android.view.LayoutInflater.inflate(LayoutInflater.java:353)
at de.NullZero.ManiDroid.presentation.fragments.MiniPlayerFragment.onCreateView(MiniPlayerFragment.java:70)
at android.support.v4.app.Fragment.performCreateView(Fragment.java:1789)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:924)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1116)
at android.support.v4.app.FragmentManagerImpl.addFragment(FragmentManager.java:1218)
at android.support.v4.app.FragmentManagerImpl.onCreateView(FragmentManager.java:2170)
at android.support.v4.app.FragmentActivity.onCreateView(FragmentActivity.java:300)
at android.support.v7.app.AppCompatDelegateImplV7.callActivityOnCreateView(AppCompatDelegateImplV7.java:842)
at android.support.v7.app.AppCompatDelegateImplV11.callActivityOnCreateView(AppCompatDelegateImplV11.java:34)
at android.support.v7.app.AppCompatDelegateImplV7.onCreateView(AppCompatDelegateImplV7.java:830)
at android.support.v4.view.LayoutInflaterCompatHC$FactoryWrapperHC.onCreateView(LayoutInflaterCompatHC.java:44)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:685)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:756)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:759)
at android.view.LayoutInflater.inflate(LayoutInflater.java:492)
at android.view.LayoutInflater.inflate(LayoutInflater.java:397)
at android.view.LayoutInflater.inflate(LayoutInflater.java:353)
at android.support.v7.app.AppCompatDelegateImplV7.setContentView(AppCompatDelegateImplV7.java:249)
at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:106)
at de.NullZero.lib.navdrawer.AbstractNavDrawerActivity.onCreate(AbstractNavDrawerActivity.java:43)
at de.NullZero.ManiDroid.presentation.ManiDroidAppActivity.onCreate(ManiDroidAppActivity.java:75)
at android.app.Activity.performCreate(Activity.java:5231)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2159)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245)
at android.app.ActivityThread.access$800(ActivityThread.java:135)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5017)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Constructor.constructNative(Native Method)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at android.view.LayoutInflater.createView(LayoutInflater.java:595)
【问题讨论】:
-
在 values-21/themes.xml 下的文件夹中使用棒棒糖特定的样式属性,这样它就不会在棒棒糖之前的设备上崩溃
-
您的可绘制对象/颜色状态列表中是否引用了样式中的颜色?
-
这不是 CSL,而是我默认的 TintedImageButton 样式中的背景定义。如果我将其注释掉,它将从 kitkat 开始。但我不知道为什么?我会将我的@drawable/btn_default_background 添加到我的帖子中。
-
@dtx12 kann 您解释了在默认样式中使用引用有什么问题,例如我的示例中对 ?attr/colorAccent 和 ?attr/selectableItemBackgroundBorderless 的引用?
-
棒棒糖之前不支持,你不能在pre-L的drawable中引用属性中的颜色。
标签: android android-view android-theme android-styles