Android Theme Style Attr

參考
Attr智哀、Style和Theme詳解
Android 深入理解Android中的自定義屬性
Android 中的Theme和Style使用
總結(jié)一下Android中主題(Theme)的正確玩法
Android Design與Holo Theme詳解
為什么Material Design沒在國產(chǎn)App中流行起來?

我剛開始學(xué)Android的時候乐横,也總對這三個概念很迷惑种吸,不知道什么是屬性凶朗,什么是風(fēng)格赘那,什么是主題亚铁,它們之間又有什么關(guān)系评雌?它們在Android框架中又充當(dāng)什么角色树枫?又如何自己去定義?但隨著學(xué)習(xí)的深入景东,越發(fā)覺得這三塊內(nèi)容真是Android框架的一大神器砂轻,有時你不用改動代碼,只要換一個theme斤吐,應(yīng)用馬上煥發(fā)青春搔涝。而且也嘗試用所學(xué)內(nèi)容去寫自己的theme,不但可以讓自己的布局文件更加清晰明了和措,而且還讓自己的代碼具有更高的擴(kuò)展性庄呈,真是好處多多,希望對這塊還不了解的童鞋多多研習(xí)派阱。

一诬留、概念說明

Attr:屬性,風(fēng)格樣式的最小單元贫母;
Style:風(fēng)格故响,它是一系列Attr的集合用以定義一個View的樣式,比如height颁独、width彩届、padding等;
Theme:主題誓酒,它與Style作用一樣樟蠕,不同于Style作用于個一個單獨(dú)View贮聂,而它是作用于Activity上或是整個應(yīng)用。

TIPS:框架使用Attr的順序是:View中的Style會優(yōu)先于Activity中的Theme寨辩,Activity中的Theme會優(yōu)先于Application中的Theme吓懈,所以說你可以定義整個應(yīng)用的總體風(fēng)格,但局部風(fēng)格你也可以做出自己的調(diào)整靡狞。

二耻警、Attr的定義
創(chuàng)建一個簡單的TextView布局

其中l(wèi)ayout_width對應(yīng)到框架中的attr信息如下:

<declare-styleable name="ViewGroup_Layout">
    <attr name="layout_width" format="dimension">
        <enum name="fill_parent" value="-1" />
        <enum name="match_parent" value="-1" />
        <enum name="wrap_content" value="-2" />
    </attr>
    ...
</declare-styleable>

從上可以看到layout_width可以使用三個枚舉值,并且其中fill_parent和match_parent的value值都為-1甸怕。做過Android開發(fā)的童鞋肯定知道甘穿,從2.2開始Android框架就推薦用match_parent代替fill_parent,而以上代碼正實(shí)現(xiàn)了兼容梢杭,因?yàn)樗鼈儗?yīng)的值都為-1温兼。

以上的textStyle的屬性信息在源碼中如下:

<attr name="textStyle">
    <flag name="normal" value="0" />
    <flag name="bold" value="1" />
    <flag name="italic" value="2" />
</attr>

它也對應(yīng)了三個值,但這里卻使用了flag標(biāo)簽武契。細(xì)心的童鞋可能已經(jīng)明白了flag與enum的差別募判,flag表示這幾個值可以做或運(yùn)算,比如上面的textStyle咒唆,你可以疊加使用届垫,如用bold|italic表示既加粗也變成斜體,而enum只能讓你選擇其中一個值全释。

看完上例后装处,我們來試著自己自定義一個自己的屬性,在values目錄下創(chuàng)建一個attrs.xml文件恨溜,在<resources>元素里面首先申明一個自己的<declare-styleable>表示一個屬性組,再在里面加上屬性就行找前。如下我們定義一個DogStyle的屬性組糟袁,其中有三個屬性一個是dogSex,一個是dogName躺盛,dogName的格式我們設(shè)置為string项戴,最后一個是dogColor,這樣一個屬于我們自己的屬性就定義成功了槽惫。

attrs.xml

format表示了Attr的類型周叮,可取的值有以下類型:

  • color:顏色值,如#000000
  • reference:引用某一資源ID界斜。如@drawable/xxx
  • boolean:布爾值仿耽,true或false
  • dimension:尺寸值,可以為wrap_content各薇、match_parent或是具體大邢詈亍(xx dp)
  • float:浮點(diǎn)型
  • fraction:百分?jǐn)?shù)
  • integer:整型
  • string:字符串類型
  • enum:枚舉類型君躺,各個取值互斥
  • flag:標(biāo)記位,各個取值可用“|”連接

attr的format根據(jù)字面意思也挺容易理解的开缎,這里我解釋下reference的用法。它用在一些可以設(shè)置引用值的情況奕删,比如@drawable/myImage、@color/myColor等伏钠。當(dāng)然format也可以進(jìn)行或運(yùn)算,一般我們定義color類型的屬性時坏怪,也一般會把format寫成format="reference|color"贝润,這樣我們不但可以設(shè)置顏色值铝宵,如#FFFFFF,還可以使用我們自己定義的狗圖片鹏秋,如@drawable/dog_pic尊蚁。

三、style的使用

為每個View重復(fù)地指定字體,顏色等屬性,無疑會增加大量的代碼,而且不利于我們后期項(xiàng)目的維護(hù),所以就引入樣式(Style) 學(xué)過web的都知道,我們可以通過css的選擇器對html中的元素進(jìn)行設(shè)置侣夷;而在UI組件中,我們可以通過style屬性來指定樣式。

style文件需要保存在res/values目錄下琴锭,文件名任意衙传,但是必須是xml文件,sytle文件的根標(biāo)記必須是<resources>蓖捶。如下我們在res/values/styles.xml中定義一個雪納瑞風(fēng)格

<style name="SchnauzerStyle">
    <item name="dogName">雪納瑞</item>
    <item name="dogColor">@drawable/schnauzer</item>
    <item name="dogSex">boy</item>
</style>
<style name="TextView">
  <item name="android:textSize">38sp</item>
  <item name="android:textColor">#128</item>
  <item name="android:shadowRadius">1.0</item>
  <item name="android:background">#035</item>
 </style>

首先我們自定義了一個View命名為DogView俊鱼,然后創(chuàng)建res/layout文件下的activity_main.xml中加入該DogView視圖,并讓該View使用SchnauzerStyle風(fēng)格并闲。代碼如下:

<cn.hadcn.test.DogView
    style="@style/SchnauzerStyle"
    android:layout_height="wrap_content"
    android:layout_width="wrap_content"/>
<TextView
    android:id="@+id/textView1"
    style="@style/TextView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/hello_world" />

也可以在程序中設(shè)置style
text.setTextAppearance(this, R.style.mystyle);

移步到DogView的Java代碼中帝火,我們可以通過theme的obtainStyledAttributes方法來獲得我們剛剛定義的幾個Attr屬性在Style中的內(nèi)容洒宝,如下我們舉一個獲得dogName的例子:

final Resources.Theme theme = context.getTheme();
TypedArray dogArray = theme.obtainStyledAttributes(attrs, 
R.styleable.DogStyle, defStyleAttr, defStyleRes);

String name = dogArray.getString(R.styleable.DogStyle_dogName);
Log.e("dog", "name = " + name);

dogArray.recycle();

以上obtainStyledAttributes有四個入?yún)⒚染皟蓚€比較容易理解,后兩個用作指定默認(rèn)的Style靠瞎,表示如果attrs中沒有你想獲得的屬性求妹,但如果你指定了默認(rèn)Style,它會去從該默認(rèn)的Style里面找你想要的屬性父能。defStyleAttr和defStyleRes功能一樣净神,指定的資源形式不同,前者表示一個默認(rèn)的指向一個style風(fēng)格的attr屬性爱榕,而后者你可以直接傳入一個style風(fēng)格的id坡慌。注意以上定義的Style只能在這個DogView中被使用,如果你想在其他View使用跪者,就需要再在需要使用的View中增加這個Style熄求。這就是先前我們說的Style只能作用于一個View。

tips:
values-v11代表在API 11+的設(shè)備上抡四,用該目錄下的styles.xml代替res/values/styles.xml
values-v14代表在API 14+的設(shè)備上指巡,用該目錄下的styles.xml代替res/values/styles.xml
其中API 11+代表android 3.0 +
其中API 14+代表android 4.0 +

如果需要繼承其他樣式隶垮,可以使用parent屬性來指定。引用其他樣式表勉耀,如果是應(yīng)用系統(tǒng)的,需要用android:style/(其實(shí)只寫android即可至壤,不過為了好看枢纠,最好還是這么寫)打頭,如果是自己定義的樣式晋渺,用style/打頭木西。繼承時也一樣。至于是用"@"還是"?"八千,@符號表明了我們應(yīng)用的資源是前邊定義過的(或者在前一個項(xiàng)目中或者在Android 框架中)叼丑。問號?表明了我們引用的資源的值在當(dāng)前的主題當(dāng)中定義過鸠信。@引用的是之前定義好的資源當(dāng)前項(xiàng)目或者android的framework里星立。而?則是引用的當(dāng)前加載的樣式文件里室奏。意思就是說你在xml里某行定義了一個資源劲装,在下面某行需要引用這個資源時用?即可

四绒怨、Theme的使用

Theme與Style使用同一個元素標(biāo)簽<style>谦疾,區(qū)別在于所包含的屬性不同,并且使用的地方也不一樣六剥。Theme你需要設(shè)置到AndroidManifest.xml的<application>或者<activity>標(biāo)簽下,設(shè)置后疗疟,被設(shè)置的Activity或整個應(yīng)用下所有的View都可以使用該<style>里面的屬性了策彤。

比如在上例中,我們直接把SchnauzerStyle設(shè)置到<activity>標(biāo)簽中叽赊,并把布局文件中DogView元素的style="@style/SchnauzerStyle"欄位刪除必搞,以此來測試下,這個Activity下的所有View是不是可以直接使用theme中聲明的這些屬性塔橡。

<activity
    android:name=".MainActivity"
    android:theme="@style/SchnauzerStyle">
    ...

以上理論上是可行的霜第,不過運(yùn)行后,程序卻出現(xiàn)奔潰泌类,出現(xiàn)以下錯誤提示:

java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.

有些同學(xué)一眼可能就看出,因?yàn)樵谶@里Activity或Application的需要很多屬性才能工作的弹砚,而此處我們只給它傳一個SchnauzerStyle枢希,這當(dāng)然不行苞轿,所以我們需要對這個Style做下處理,讓SchnauzerStyle繼承一個系統(tǒng)主題瑟俭,如下:

<style name="SchnauzerStyle" parent="Theme.AppCompat">
    <item name="dogName">雪納瑞</item>
    <item name="dogColor">@drawable/schnauzer</item>
    <item name="dogSex">boy</item>
</style>

這樣一個雪納瑞主題就誕生了秀睛,而在這個Activity下的所有View都可以用雪納瑞的信息了莲祸。

1.例二:
首先在res/values/themes.xml中定義Theme椭迎。

<resources xmlns:android="http://schemas.android.com/apk/res/android">
    <style name="Theme" parent="android:Theme.Light">
        <item name="android:windowFullscreen">true</item>
        <item name="android:windowTitleSize">60dip</item>
        <item name="android:windowTitleStyle">@style/WindowTitle</item>
        <item name="android:background">#234</item>
    </style>
    <style name="WindowTitle">
        <item name="android:singleLine">true</item>
        <item name="android:shadowColor">#658</item>
        <item name="android:shadowRadius">2.75</item>
    </style>  
</resources>

然后在AndroidManifest.xml中使用剛才定義的主題畜号。只要定義application的android:theme屬性為style/Theme即可允瞧。

<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/Theme" >
    <activity
        android:name="com.example.themedemo.MainActivity"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

或者使用代碼setTheme(R.style.Theme)

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setTheme(R.style.Theme);
        setContentView(R.layout.activity_main);
    }

2.主題的來源有三個

  1. 來自Android系統(tǒng)自帶的述暂。加上“android:”,如:android:Theme.Black
系統(tǒng)自帶主題:
API 1:
android:Theme 根主題
android:Theme.Black 背景黑色
android:Theme.Light 背景白色
android:Theme.Wallpaper 以桌面墻紙為背景
android:Theme.Translucent 透明背景
android:Theme.Panel 平板風(fēng)格
android:Theme.Dialog 對話框風(fēng)格

API 11:
android:Theme.Holo Holo根主題
android:Theme.Holo.Black Holo黑主題
android:Theme.Holo.Light Holo白主題

API 14:
Theme.DeviceDefault 設(shè)備默認(rèn)根主題
Theme.DeviceDefault.Black 設(shè)備默認(rèn)黑主題
Theme.DeviceDefault.Light 設(shè)備默認(rèn)白主題

API 21: (網(wǎng)上常說的 Android Material Design 就是要用這種主題)
Theme.Material Material根主題
Theme.Material.Light Material白主題
  1. 來自兼容包的(比如v7兼容包)疼蛾。不需要前綴艺配,直接:Theme.AppCompat
兼容包v7中帶的主題:
Theme.AppCompat 兼容主題的根主題
Theme.AppCompat.Black 兼容主題的黑色主題
Theme.AppCompat.Light 兼容主題的白色主題

Theme.AppCompat主題是兼容主題转唉,是什么意思呢?意思就是說如果運(yùn)行程序的手機(jī)API是21則就相當(dāng)于是Material主題麦轰,如果運(yùn)行程序的手機(jī)API是11則就相當(dāng)于是Holo主題砖织,以此類推。

兼容包v7會被Google公司不斷升級:
比如 appcompat-v7-21.0 表示升級到向 API 21 兼容
比如 appcompat-v7-23.2 表示升級到向 API 23 兼容

Android 5.0上指定用Material theme就可以喳坠。參考5.0的文檔即可茂蚓。

5.0之前的老版本,官方提供的途徑是使用appcompat v7-21 support庫晾浴。v7的意思是支持Android v7 (2.1)及以上的老版Android牍白,21是appcompat這個庫的版本。Google在文檔里也經(jīng)常直接叫做appcompat v21狸涌,不要混淆。

  1. 你自己寫一個主題
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末朝捆,一起剝皮案震驚了整個濱河市懒豹,隨后出現(xiàn)的幾起案子脸秽,更是在濱河造成了極大的恐慌记餐,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件巩剖,死亡現(xiàn)場離奇詭異钠怯,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)鞠鲜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進(jìn)店門贤姆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來稳衬,“玉大人,你說我怎么就攤上這事碧信〗重玻” “怎么了?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵呈枉,是天一觀的道長。 經(jīng)常有香客問我酥泞,道長住册,這世上最難降的妖魔是什么瓮具? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任名党,我火速辦了婚禮,結(jié)果婚禮上耳幢,老公的妹妹穿的比我還像新娘欧啤。我一直安慰自己,他們只是感情好店印,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布倒慧。 她就那樣靜靜地躺著纫谅,像睡著了一般。 火紅的嫁衣襯著肌膚如雪付秕。 梳的紋絲不亂的頭發(fā)上询吴,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天,我揣著相機(jī)與錄音口柳,去河邊找鬼有滑。 笑死,一個胖子當(dāng)著我的面吹牛望艺,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播艇劫,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼惩激,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了顷蟀?” 一聲冷哼從身側(cè)響起骡技,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤布朦,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后阁将,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體右遭,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡窘哈,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了图筹。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片让腹。...
    茶點(diǎn)故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡骇窍,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出腹纳,到底是詐尸還是另有隱情,我是刑警寧澤足画,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布淹辞,位于F島的核電站,受9級特大地震影響蔬将,放射性物質(zhì)發(fā)生泄漏攻冷。R本人自食惡果不足惜遍希,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望禁谦。 院中可真熱鬧废封,春花似錦、人聲如沸遥皂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽样悟。三九已至庭猩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間震糖,已是汗流浹背趴腋。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留疏叨,地道東北人蚤蔓。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像单寂,于是被迫代替她去往敵國和親吐辙。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內(nèi)容