前言
本文可能涉及到一些“專業(yè)”的知識(shí),為了不影響閱讀,可以先閱讀入門篇或者看看我的自制皮膚Glass
如果有按照我的步驟一步一步來(lái),入門篇的最后一定會(huì)出現(xiàn)一個(gè)“bug”,放一張圖回憶回憶:

其實(shí)這不是bug啦,只是基本操作。其原理是客戶端的渲染機(jī)制導(dǎo)致的,這里不做過(guò)多的講解。只需要了解:
最底層(最下面)的控件一定要有背景繪制,實(shí)際上我們的壁紙就是最底層那層繪制。后來(lái)我們加上壁紙的繪制,客戶端就表現(xiàn)正常了,就是這個(gè)原理。
概覽
本文將會(huì)主要講解這些知識(shí)點(diǎn),放張圖壓壓驚:

主要參考官方文檔以及自己的經(jīng)驗(yàn)。
簡(jiǎn)單介紹
layout : 控件該在哪里出現(xiàn)
controls : 控件該干些什么
styles : 控件該長(zhǎng)什么樣
color : 描述樣式中的顏色或某些特定的屬性值
一個(gè)完整的 .layout 文件由上面4部分構(gòu)成,每個(gè)部分都被一對(duì)大括號(hào)包裹。但這4部分都不是必須的,即使一個(gè)部分都沒(méi)有,只要格式正確(如果有下一篇,會(huì)解釋這個(gè)格式),就會(huì)被steam客戶端加載。
詳細(xì)介紹
這里會(huì)對(duì)上面4部分做詳細(xì)介紹,包括說(shuō)明。和相關(guān)屬性的默認(rèn)值、可選值怎么使用可以參考入門篇的styles。
需要注意的是,這些屬性在某些地方可能有特殊用法(比如下載進(jìn)度條),在使用特殊用法的地方,v社開(kāi)發(fā)人員都貼心的留下注釋了,這里我只關(guān)注一般情況。
語(yǔ)法
先了解一下語(yǔ)法,吐槽一下layout文件里邊什么格式都有,強(qiáng)迫癥快要死了。
1.1 符號(hào)不敏感
在變量中對(duì) = 不敏感,下面兩段代碼的效果一樣的,不過(guò)我建議使用 =。
color1="0 0 0 255"
color1 "0 0 0 255" // 有空格代替等號(hào)是允許的
空格不敏感,在空格用作兩個(gè)屬性之間的間隔、變量名和變量值的連接時(shí),1個(gè)空格和100個(gè)空格是一樣的
// 在變量中
// 下面兩種情況效果一樣
color1="0 0 0 255"
color1 = "0 0 0 255"
// 下面兩種情況效果一樣
color1 "0 0 0 255"
color1 "0 0 0 255"
// 在style、control、place、region中,以place為例,其他類似
// 下面兩種情況效果一樣
place{x=50 y=40 width=max} // 在這里對(duì)等號(hào)敏感
place{ x = 50 y = 40 width = max }
換行不敏感,找不到合適的語(yǔ)言來(lái)描述,放代碼自行體會(huì)
// 在style、control、place、region中,以place為例,其他類似
// 下面的情況效果一樣
place{x=50 y=40 width=max}
place{
x=50 y=40 width=max
}
place
{x=50 y=40 width=max}
place
{
x=50 y=40 width=max
}
1.2 樣式
在controls、layout 、styles內(nèi)部使用
button {
textcolor="0 0 0 255"
bgcolor="255 255 255 0"
padding=10
}
其中button是名稱,textcolor和bgcolor是屬性"0 0 0 255"和10是屬性值
2 style
定義一個(gè)樣式,供control、place、region 使用。
button {
textcolor="0 0 0 255"
bgcolor="255 255 255 0"
}
注意:所有的屬性都不是必須的
2.1 字體相關(guān)
| 屬性 | 類型 | 默認(rèn)值 | 預(yù)設(shè)值 | 說(shuō)明 |
|---|---|---|---|---|
| font-family | 字符串 | Tahoma | - | 字體名稱 |
| font-size | 整數(shù) | - | - | 字體大小,單位像素 |
| font-weight | 整數(shù) | 400 | 0~1000 | 字體粗細(xì)。400是標(biāo)準(zhǔn),700是粗體 |
| font-style | 字符串 | normal | normal(正常),italic(斜體),underline(下劃線),strikeout(刪除線),uppercase(大寫),lowercase(小寫),symbol,antialias,dropshadow,outline,rotary,additive | 字體樣式,其中一些可以疊加 |
-
字體樣式:
- normal(正常)
normal(正常)- italic(斜體)
italic(斜體)- underline(下劃線)
underline(下劃線)- strikeout(刪除線)
strikeout(刪除線)- uppercase(大寫)
image.png- lowercase(小寫)
image.png- symbol(未知)
image.png- antialias(未知)
image.png- dropshadow(未知)
image.png- outline(未知)
image.png- rotary(未知)
image.png- additive(未知)
image.png
2.2 顏色相關(guān)
| 屬性 | 類型 | 說(shuō)明 |
|---|---|---|
| bgcolor | 字符串或顏色 | 背景色 |
| textcolor | 字符串顏色 | 文字顏色 |
| selectedtextcolor | 字符串顏色 | 選中文字顏色 |
| selectedbgcolor | 字符串顏色 | 選中文字背景色 |
| shadowtextcolor | 字符串顏色 | 在不同的控件中有不同的意義 |
2.3 布局相關(guān)
| 屬性 | 類型 | 默認(rèn)值 | 說(shuō)明 |
|---|---|---|---|
| padding | 整數(shù) | 0 | 內(nèi)邊距,只是用與類型為Label或Button的control |
| insert | 整數(shù) | "0 0 0 0" | 子控件在控件中如何定位,4個(gè)數(shù)字分別代表距離左、上、右、下的距離,對(duì)bgcolor起作用 |
| minimum-width | 整數(shù) | 0 | 最小寬度,不適用與所有控件 |
| minimum-height | 整數(shù) | 0 | 最小高度,不適用與所有控件 |
- padding(內(nèi)邊距)
padding=30

假如紫框?yàn)槎x的控件,綠框+紫框就是實(shí)際顯然效果的效果,當(dāng)然顏色還是原來(lái)定義的顏色,這里只是方便區(qū)分
padding-left=30
padding-top=30
padding-right=30
padding-bottom=30
這段代碼和上面那段可以達(dá)到一樣的效果
- insert
insert="30 30 30 30"

假如綠框是定義的控件,紫框就是加上上面代碼后的效果,顯示不全的部分會(huì)被隱藏
insert-left=30
insert-top=30
insert-right=30
insert-bottom=30
這段代碼和上面那段可以達(dá)到一樣的效果
2.4 image
用圖片替代文字,使用于Label和Button控件(控件類型屬于control部分內(nèi)容)
image="graphics/broadcast/icon_close_default"
值為一個(gè)圖片的相對(duì)于皮膚文件夾根目錄的相對(duì)位置,不要帶文件后綴。當(dāng)然這里的圖片指的是tag格式的圖片
2.5 render、render_bg(渲染)
這兩個(gè)屬性都是用于渲染的,前者在控件繪制之后開(kāi)始繪制,后者在控件繪制之前開(kāi)始繪制,說(shuō)的通俗一點(diǎn)就是前者是繪制遮罩,后者是繪制背景。
做個(gè)比喻方便理解,bgcolor是你的皮膚顏色,render_bg是衣服顏色,textcolor衣服上字的顏色,render是圍裙的顏色。
- 注意: render_bg在bgcolor繪制之后繪制,這意味著bgcolor的效果可能被覆蓋。
每一個(gè)完整的渲染由一組渲染指令完成(一條指令也能完成一個(gè)完整的渲染),每條渲染指令可以指定一種渲染方式,包括fill、image、image_tiled、image_scale、image_proportional、gradient、gradient_horizontal、dashedrect。
無(wú)論哪種方式渲染都需要至少4個(gè)參數(shù),這4個(gè)參數(shù)實(shí)際上是2個(gè)坐標(biāo),以控件占據(jù)的區(qū)域?yàn)闇?zhǔn) (x0,y0)表示左上角,(x1,y1)表示右下角,假設(shè)一個(gè)控件占據(jù)的區(qū)域長(zhǎng)100,寬70,那么有:
// ==兩邊代碼指定的區(qū)域相同
(x0, y0)==(x1-100, y0-70)
(x1, y1)==(x0+100, y0+70)
(x0+20, y0+30)==(x1-80, y1-40)
描述坐標(biāo)參數(shù)時(shí)需要遵從先上后下,先左后右的原則:
// 前兩個(gè)參數(shù)為第一個(gè)點(diǎn),后兩個(gè)參數(shù)為第二個(gè)點(diǎn)
0="fill(x0, y0, x0, y0+10, red)" // 正確,先上后下
0="fill(x0, y0+10, x0, y0, red)" // 錯(cuò)誤,先下后上
0="fill(x0, y0, x0+10, y0, red)" // 正確,先左后右
0="fill(x0+10, y0, x0, y0, red)" // 錯(cuò)誤,先右后左
這要求我們?cè)诖_定渲染區(qū)域是要選取左上角和右下角來(lái)確定渲染區(qū)域,且需要先寫左上角在寫右下角。
觀察上面的指令,每條指令前面都有一個(gè)數(shù)字先看下官方解釋:
The numbers on each line are just an artifact of our common parsing library; it doesn't matter what you put there, and it can all be the same.
大概意思是:每條指令上的數(shù)字只是我們公共解析庫(kù)中的一部分;他們并不重要,甚至完全一樣也沒(méi)問(wèn)題。
- 注意:這里我特意引用了官方文檔,其原因是我在制作皮膚的過(guò)程中發(fā)現(xiàn):在某些控件中,將渲染指令中的數(shù)字使用一樣的,會(huì)導(dǎo)致渲染效果達(dá)不到預(yù)期。當(dāng)我將數(shù)字替換為成不一樣的之后。渲染和我預(yù)期的一樣。
現(xiàn)在來(lái)詳細(xì)解釋下這些渲染方式:
- 注意:前4個(gè)坐標(biāo)參數(shù)為必須,下表中就不在列舉
2.5.1 fill(填充)
必要參數(shù)
一個(gè)顏色,必須是一個(gè)定義好的顏色變量-
例子
0="fill(x0, y0, x0+10, y0, red)" 說(shuō)明
單色填充所選區(qū)域
2.5.2 dashedrect(虛線框)
必要參數(shù)
一個(gè)顏色,必須是一個(gè)定義好的顏色變量-
例子
0="dashedrect(x0, y0, x0+10, y0, red)" 說(shuō)明
繪制具有指定顏色的虛線矩形
2.5.3 gradient_horizontal(縱向漸變填充)
必要參數(shù)
使用兩個(gè)顏色漸變填充指定區(qū)域,漸變有上到下,第一個(gè)顏色為開(kāi)始漸變,第一個(gè)為結(jié)束漸變顏色-
例子
0="gradient_horizontal(x0, y0, x0+10, y0, red, blue)" 說(shuō)明
漸變填充區(qū)域,方向從上到下
2.5.4 gradient_horizontal(橫向漸變填充)
必要參數(shù)
使用兩個(gè)顏色漸變填充指定區(qū)域,漸變有上到下,第一個(gè)顏色為開(kāi)始漸變,第一個(gè)為結(jié)束漸變顏色-
例子
0="gradient_horizontal(x0, y0, x0+10, y0, red, blue)" 說(shuō)明
漸變填充區(qū)域,方向從左到右
2.5.5 image(圖片)
必要參數(shù)
一個(gè)圖片的相對(duì)于皮膚文件夾根目錄的相對(duì)位置,不要帶文件后綴。當(dāng)然這里的圖片指的是tag格式的圖片,與image屬性一樣-
例子
0="image(x0, y0, x0+10, y0, graphics/broadcast/icon_close_default)" 說(shuō)明
使用圖片渲染指定區(qū)域,需要注意的是,如果圖片的尺寸不渲染區(qū)域要大,可能圖片會(huì)超出指定的渲染區(qū)域
2.5.6 image_tiled(圖片,拓展)
必要參數(shù)
同上-
例子
0="image_tiled(x0, y0, x0+10, y0, graphics/broadcast/icon_close_default)" 說(shuō)明
從指定區(qū)域的左上角開(kāi)始,重復(fù)渲染該圖片,直到鋪滿整個(gè)區(qū)域。
假設(shè)你現(xiàn)在新建一個(gè)文本文檔,你的指定你的記事本區(qū)域?yàn)殇秩緟^(qū)域,數(shù)字1為渲染的圖片,使用使用此渲染方式就是不停的按1,直到整個(gè)文檔全是1
2.5.7 image_scale(圖片,縮放,不等比例)
必要參數(shù)
同上-
例子
0="image_scale(x0, y0, x0+10, y0, graphics/broadcast/icon_close_default)" 說(shuō)明
縮放圖片,鋪滿整個(gè)區(qū)域,圖片可能會(huì)變形
2.5.8 image_proportional
必要參數(shù)
同上-
例子
0="image_proportional(x0, y0, x0+10, y0, graphics/broadcast/icon_close_default)" 說(shuō)明
縮放圖片,鋪滿整個(gè)區(qū)域,會(huì)等比例縮放,圖片不會(huì)變形
3 control
control在controls區(qū)域內(nèi)被定義,它賦予控件樣式和具體作用
- 注意: 這control部分內(nèi)容并沒(méi)有文檔作為支撐,絕大部分內(nèi)容靠我自己腦補(bǔ)的,所以此部分巨大多數(shù)情況下我不建議去調(diào)整。
// 一個(gè)樣式
fileimage {
controlname="ImagePanel"
image=resource/icon_file
zpos=1
style="fileimagestyle"
}
其中fileimage為該控件的名稱,用在其他地方引用這個(gè)控件,{}內(nèi)的為該控件的屬性
3.1 屬性
屬性|類型|預(yù)設(shè)值|說(shuō)明
-|-|-|-|-
controlname|string|Label、URLLabel、ImagePanel、Button、CheckButton、RadioButton|控件類型
style|string|-|styles中定義的樣式
恩,沒(méi)了(逃)
其他的屬性,根據(jù)屬性名大概能猜出來(lái)什么意思,但在實(shí)際使用中,有時(shí)有用,有時(shí)又沒(méi)有用,索性就不說(shuō)了。
control一般都不去動(dòng)他,只是用來(lái)確定控件使用的style的。
4 layout
4.1 說(shuō)明
這里的layout并非指.layout文件,而是.layout文件中的layout區(qū)域,這個(gè)區(qū)域是用來(lái)確定控件的在客戶端上位置的。
在這個(gè)區(qū)域中有兩種確定控件位置的方式:region和place,前者多用于指定包含多個(gè)控件的一個(gè)區(qū)域,后者則用來(lái)單獨(dú)指定某個(gè)控件的位置,當(dāng)然前者用來(lái)單獨(dú)指定一個(gè)區(qū)域也是完全沒(méi)有問(wèn)題的。
place和region命令有很多參數(shù),其中絕大部分都是通用的,并且這些參數(shù)全是可選的。
4.2 place和region的屬性(參數(shù))簡(jiǎn)要說(shuō)明
| 屬性 | 類型 | 必須 | 默認(rèn)值 | 預(yù)設(shè)值 | 說(shuō)明 |
|---|---|---|---|---|---|
| control | 字符串 | 否 | - | - | 為該區(qū)域指定一個(gè)control,可以一次指定多個(gè)control |
| region | 字符串 | 否 | - | - | 為該區(qū)域指定一個(gè)父容器,并且該區(qū)域的相對(duì)于父級(jí)定位 |
| name | 字符串 | 否 | - | - | 為該區(qū)域指定一個(gè)名稱,方便其他區(qū)域應(yīng)用 |
| x | 整數(shù) | 否 | 0 | - | 相對(duì)于父容器的絕對(duì)定位,原點(diǎn)在父容器的左上角。若沒(méi)有指定父容器為.layout文件指定的區(qū)域 |
| y | 整數(shù) | 否 | 0 | - | 同x,x、y構(gòu)成一個(gè)坐標(biāo)確定該區(qū)域的左上角 |
| width | 整數(shù) | 否 | - | - | 該區(qū)域的寬度,單位像素,父容器參考x |
| height | 整數(shù) | 否 | - | - | 該區(qū)域的高度,單位像素,父容器參考x |
| start | 字符串 | 否 | - | - | 用來(lái)參考定位的其他區(qū)域的名稱 |
| dir | 字符串 | 否 | right | down、right | 相對(duì)于參考區(qū)域的方向 |
| align | 字符串 | 否 | top-left | bottom、top、left、right、top-left、top-right | 該區(qū)域的對(duì)其方式 |
| margin | 整數(shù) | 否 | 0 | - | 該區(qū)域的外邊距(上下左右),單位像素,可以使用margin-left, margin-right, margin-top, margin-bottom的方式指定單獨(dú)每一邊的邊距 |
| padding | 整數(shù) | 否 | 0 | - | 該區(qū)域的內(nèi)邊距(上下左右),單位像素,可以使用padding-left, padding-right, padding-top, padding-bottom的方式指定單獨(dú)每一邊的邊距 |
| spacing | 整數(shù) | 否 | 0 | - | 區(qū)域中控件的間距,單位像素 |
| overflow | 字符串 | 否 | - | allow-horizo??ntal、allow-vertical、allow-both、scroll-horizo??ntal、scroll-vertical、scroll-both | region獨(dú)有,區(qū)域內(nèi)的內(nèi)容超出該區(qū)域后的處理方式,帶有allow及時(shí)內(nèi)容超出,依舊會(huì)顯示,并且不會(huì)改變定義好的樣式,帶有scroll的內(nèi)容超出后會(huì)為該區(qū)域添加一個(gè)滾動(dòng)條 |
4.3 屬性詳細(xì)說(shuō)明
我會(huì)挑出我認(rèn)為不容易理解的屬性,詳細(xì)說(shuō)明一下
4.3.1 region、place
layout {
// 區(qū)域1
region {
name="aRegion"
width=100
height=200
x=50
y=50
}
// 區(qū)域2
place {
region="aRegion"
width=20
height=20
x=50
y=40
}
// 區(qū)域3
region {
region="aRegion"
width=50
height=100
}
// 區(qū)域4
place {
width=130
height=140
}
}
上面的4個(gè)區(qū)域,實(shí)際上不會(huì)有任何顯示。只定義了區(qū)域,沒(méi)有定義要展示的內(nèi)容。
假如每一個(gè)區(qū)域都是有邊框的,他們一定是這樣的:

先看區(qū)域1(黑框):
- 定義了一個(gè)名稱為aRegion的矩形區(qū)域,矩形區(qū)域的長(zhǎng)為100像素,高為200像素
- 沒(méi)有指定region屬性,默認(rèn)父容器為.layout控制的區(qū)域
- 指定x、y,所以從(50,50)出開(kāi)始渲染
區(qū)域2(綠框):
- 定義一個(gè)20 x 20的區(qū)域
- 指定aRegion為父容器
- 指定從(50,40)開(kāi)始渲染,對(duì)于.layout文件就是從(100,90)開(kāi)始渲染
區(qū)域3(紅框):
- 定義一個(gè)50 x 100的區(qū)域
- 指定aRegion為父容器
- 指定從(0,0)開(kāi)始渲染,對(duì)于.layout文件就是從(50,50)開(kāi)始渲染
先看區(qū)域4(紫框):
- 定義一個(gè)130 x 140的區(qū)域
- 沒(méi)有指定region屬性,默認(rèn)父容器為.layout控制的區(qū)域
- 指定x、y,所以從(50,50)出開(kāi)始渲染
4.3.2 control
// 指定單個(gè)control
place {
control=DetailsBorder
y=1
x=1
width=max
height=max
}
// 指定多個(gè)control
// 使用逗號(hào)隔開(kāi)
place {
control=welcomedetails,rentaldetails,turnnotifications,friendsdetails,achievementsdetails,dlcdetails,clouddetails,communityfilesdetails,newsdetails,nonsteamdetails,screenshotsdetails
region=detailsbody
spacing=30
dir=down
width=max
margin-left=25
}
指定一個(gè)或者多個(gè)control使用這個(gè)區(qū)域
dir
place {
control=welcomedetails,rentaldetails,turnnotifications,friendsdetails,achievementsdetails,dlcdetails,clouddetails,communityfilesdetails,newsdetails,nonsteamdetails,screenshotsdetails
region=detailsbody
spacing=30
dir=down
width=max
margin-left=25
}
在指定多個(gè)control時(shí)使用dir來(lái)指定這些control的排列方式,right水平向右,down垂直向下
spacing
place {
control=welcomedetails,rentaldetails,turnnotifications,friendsdetails,achievementsdetails,dlcdetails,clouddetails,communityfilesdetails,newsdetails,nonsteamdetails,screenshotsdetails
region=detailsbody
spacing=30
dir=down
width=max
margin-left=25
}
在指定多個(gè)control時(shí)使用dir來(lái)指定這些control之間的間隔,單位像素,水平向右
4.3.3 margin(外邊距)
layout {
place {
width=100
height=100
x=10
y=40
margin=30
}
}
圖:

圖中紫色為最終渲染結(jié)果,綠色虛線框僅僅為輔助線,margin為外邊距,即外邊的邊距,只影響實(shí)際渲染的位置,不影響內(nèi)容
margin=10
和
maring-left=10
maring-top=10
maring-right=10
maring-bottom=10
效果相同
4.3.4 padding(外邊距)
這部分和style中的margin一樣
4.3.5 start
place {
control="change_user_button"
align=left
height=24
}
place {
control="account_name_label"
start="change_user_button"
dir="right"
height=24
margin-left=-4
}
start用來(lái)給定一個(gè)參考,給出的參考是control不是region,start能和dir聯(lián)合使用,指定dir為right或者down來(lái)讓當(dāng)前布局生成在參考控件的右邊或者下面。
設(shè)備標(biāo)識(shí)符
這個(gè)是用來(lái)做適配的,隨便找一句
ClientTitle:FrameFocus [!$OSX] {
font-family=basefont
font-size=14
font-weight=400
textcolor="label"
bgcolor="none"
inset="12 6 0 0"
}
ClientTitle:FrameFocus [$OSX] {
font-family=basefont
font-size=15
font-weight=400
textcolor="texthover"
bgcolor="none"
inset="0 6 0 0"
}
第一個(gè)適用于非OSX,第二個(gè)適用于OSX,其他的基本看到都能明白
結(jié)語(yǔ)
祝,各位玩的愉快~











