我尝试使用默认样式设置自定义(和派生)视图的主题。 我的解决方案基于此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>
我已经看到一些示例声明主题属性引用在declare-styleable之外。但我不明白其中的区别,尤其是名称=&#34; CustomTheme&#34;在引用的stackoverflow发布中。
的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>
抽拉/ 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>
示例布局代码段
<!-- 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)
答案 0 :(得分:0)
好的,我找到了一个解决方案,但没有在默认主题样式中使用引用:
我已将默认主题样式更改为:
<style name="TintedImageButton" parent="Base.Widget.AppCompat.Button.Borderless">
<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">?attr/buttonBackground</item>
<item name="android:scaleType">center</item>
<item name="tint">?attr/buttonTint</item>
</style>
我已将这两个属性添加到我的attr.xml
<declare-styleable name="CustomTheme">
<attr name="tintedImageButtonStyle" format="reference"/>
<attr name="buttonTint" format="reference"/>
<attr name="buttonBackground" format="reference"/>
</declare-styleable>
在我的themes.xml中,我选择了属性的值:
<style name="AppTheme" parent="AppBaseTheme">
<!-- All customizations that are NOT specific to a particular API-level can go here. -->
<item name="tintedImageButtonStyle">@style/TintedImageButton</item>
<item name="buttonTint">@color/button_tint_csl</item>
<item name="buttonBackground">?attr/selectableItemBackgroundBorderless</item>
</style>
语义相同但现在它适用于api&lt; 21也没有失去控制;)