一.自定义View的主题和风格样式
前言:
android开发中,不可避免的要设定某一类按钮的按压,点击,聚焦等状态,通常对于这一类问题而言,最原始的方式就是在布局文件中亲自设定,然而对于一个比较大型的项目而言,这种方式造成的可维护性不是很好,因此要尽量做到代码重用。对于一个控件而言,如ToggleButton,RadioButton,CheckBox,滚动条颜色,Button,当点击时状态切换前后样式是不一样的。
介绍:
android项目中通常有3个设置样式的资源文件夹
values
values-11
values-14
这三个对应不同平台的sdk版本的样式,对于android开发中兼容问题而言,要做到“让最新的api运行在最新的android sdk中”,这是非常好的一种行为。
values文件主要用来设置主题样式,权限依据平台细分,也就是说android4.x会最先找values-14再去找values-11最后找values,android2.x最先找values-11最后找values
以上是values的设置问题,通常来说,style.xml一般被使用来设置 window和activity主题与样式,但实际上,style.xml也可以用来设定控件的全局样式。
下面有句名言:
尽量让主题样式和页面风格保持统一,花花绿绿是最丑的风格。
举例子
style.xml-1
<style name="text_red_20_blod">
<item name="android:textStyle">bold</item>
<item name="android:textSize">20.0sp</item>
<item name="android:textColor">@color/red_text_color</item>
</style>
这种的局限性和亲自到布局文件设置的一样,只不过少了许多代码,提高了重用性,可以说只做到了部分全局化。
style.xml-2
<style name="AppTheme" parent="android:Theme.Holo.Light">
<item name="android:textStyle">bold</item>
<item name="android:textSize">20.0sp</item>
<item name="android:textColor">@color/red_text_color</item>
</style>
这种事最全局的,提高了重用性,当然也有他的缺点,这点不可避免,那么在开发中,我们如何选择呢?
style.xml-1 中样式变化最为频繁的View风格,这样做可以避免layout文件中过多的代码累计,就像css样式一样
style.xml-2适用于全局较为统一的View风格,也就是说是一些View的共性的统一,一般来说如ToggleButton,CheckBox,Button等View的状态切换样式在同一项目中总是保持着一直的变化效果。也就是说,当我们使用自定义放入ToggleButton切换状态之后,下次再次使用ToggleButton风格应该和上次风格保持一致才对。
冲突问题,如果在style.xml-2下使用style.xml-1的内容将如何显示,这个问题一句话可以描述:”全局性越低,控制权限越高“,也就是说,style.xml-1控制权限高于style.xml-2,因此如果同时影响某一控件的view风格的样式被设置,那么也就是直接使用 style="@style/xxxx"的权限高于主题权限。
二.自定义Attr风格样式以及读取
获取自定义属性通常是在自定义View内部获取,但在某种方式下,无论自定义View的属性还是主题中样式的属性,均可在外部style中获取。
由于非自定义View的外部获取方式比较复杂,这里暂时略过,后续补充。
1.自定义attr
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<attr name="theme_name" format="string|reference"/>
</resources>
2.设置attr,注意,该Attr必须在是Activity主题中而不是普通的Style中
<resources>
<!-- Activity themes -->
<style name="Theme.Base" parent="android:Theme.Holo.Light" >
<item name="theme_name" >@string/theme_name_1</item>
</style>
</resources>
3.获取,通过xml
<TextView
android:id="@+id/show_tv"
android:layout_width="match_parent"
android:layout_height="200dip"
android:text="?attr/theme_name"
android:background="@android:color/darker_gray" />
4.获取,通过代码
TypedValue outValue = new TypedValue();
getContext().getTheme().resolveAttribute(android.R.attr.selectableItemBackground,outValue, true);
textView.setBackgroundResource(outValue.resourceId);
注意,如果我直接设置数据,则resourceId为0
<resources>
<!-- Activity themes -->
<style name="Theme.Base" parent="android:Theme.Holo.Light" >
<item name="theme_name" >我的主题</item>
</style>
</resources>
这时候我们的数据可以使用TypeValue.string读取
TypedValue outValue = new TypedValue();
getContext().getTheme().resolveAttribute(android.R.attr.selectableItemBackground,outValue, true);
if(outValue.data==TypeValue.TYPE_STRING)
{
textView.setBackgroundResource(outValue.string);
}
5.当然,有时候我们的属性可能是个集合
这时候不能用TypedValue获取,TypeValued只能判断类型,因此我们选择如下方式
5.1在xml中,我们使用 style="?attr/MyStyle"或者style="?android:attr/ActionBarStyle"方式获取集合Style的
5.2在代码中获取,举个栗子,如下:
public int getTabContainerHeight()
{
TypedArray a = mContext.obtainStyledAttributes(null, android.support.v7.appcompat.R.styleable.ActionBar, android.support.v7.appcompat.R.attr.actionBarStyle, 0);
int height = a.getLayoutDimension(android.support.v7.appcompat.R.styleable.ActionBar_height, 0);
Resources r = mContext.getResources();
if(!hasEmbeddedTabs())
height = Math.min(height, r.getDimensionPixelSize(android.support.v7.appcompat.R.dimen.abc_action_bar_stacked_max_height));
a.recycle();
return height;
}
对于View内部获取方式如下
private static Context themifyContext(Context context, AttributeSet attrs, int defStyleAttr)
{
TypedArray a = context.obtainStyledAttributes(attrs, android.support.v7.appcompat.R.styleable.Toolbar, android.support.v7.appcompat.R.attr.ActionBarStyle, 0);
int themeId = a.getResourceId(android.support.v7.appcompat.R.styleable.Toolbar_theme, 0);
if(themeId != 0)
context = new ContextThemeWrapper(context, themeId);
a.recycle();
return context;
}