天天看點

05_了解 XML 使用(布局控制)了解 XML 使用 (布局控制)

了解 XML 使用 (布局控制)

通過上一篇的學習我們可以制作一個簡單的布局了,但是沒有控件的視窗做再好的布局有什麼用呀。趕緊找些素材,我們來做一個标準的 Windows 視窗。并通過這個視窗我們來了解一下布局中一些細微細節的控制。

一個正常的 Windows 視窗應該有一個像樣的标題欄,标題欄左側包含視窗的 Logo 和視窗的名稱,右側有最小化、最大化和關閉按鈕,還有一些視窗可能會有設定啊等等類似的按鈕。我們到網絡上找一些素材,親自動手制作一個視窗。素材我們可以到 Iconfont-阿裡巴巴矢量圖示庫 去自己下載下傳。通過搜尋功能搜尋一個你喜歡的圖檔,比如我搜尋一個 Logo,會出來很多可用的圖形,随便點選一個進去後,可以設定圖形的顔色:

05_了解 XML 使用(布局控制)了解 XML 使用 (布局控制)

我下載下傳了一個 PNG 小圖檔,大小是 18x18 像素,藍色。将圖檔儲存到項目的 theme 檔案夾下。

05_了解 XML 使用(布局控制)了解 XML 使用 (布局控制)

然後我們編輯 main_wnd_frame.xml,删除掉原來的 TileLayout 中所有内容,重新做一個布局,如下所示:

05_了解 XML 使用(布局控制)了解 XML 使用 (布局控制)

通過分析我們可以判斷,最外部應該使用一個垂直布局

VerticalLayout

,因為标題欄和下面視窗内容區域是一個從上到下的垂直布局。而标題欄裡面是從左到右的一個水準布局

VerticalLayout

。至于下方内容區域,我們暫時先不用關心,先把這個标題欄做好,是以我們還是使用一個水準布局。那麼根據思路你可以先不看下面代碼,自己試着寫一個視窗的布局,算是對自己的一個鍛煉。記得标題欄是有固定高度的,可以通過

height

屬性指定

HorizontalLayout

的高度。

<?xml version="1.0" encoding="UTF-8"?>
<Window size="640,480" caption="0,0,0,35">
	<VerticalLayout>
		<!-- 标題欄 -->
		<HorizontalLayout height="35" bkcolor="#FFD6DBE9">
			<Control bkimage="Logo.png" height="18" width="18"/>
			<Label text="duilib tutorial" />
		</HorizontalLayout>
		<!-- 視窗内容區域 -->
		<HorizontalLayout bkcolor="#FF4D6082">
		</HorizontalLayout>
	</VerticalLayout>
</Window>
           

以上代碼運作後,效果如下:

05_了解 XML 使用(布局控制)了解 XML 使用 (布局控制)

可以看到,我們給視窗分割了兩個區域,一個标題欄,一個視窗内容區域,内容區域現在還沒有任何内容。但是标題欄已經增加了一個 Logo。其中标題欄我們用水準布局

HorizontalLayout

來實作,用

height="35"

指定了标題欄的高度,用

bkcolor

屬性指定了标題欄的背景色。接着标題欄内部我們使用

Control

控件包裝的 Logo 圖像,使用

bkimage="Logo.png"

指定了圖檔檔案的位置,并同樣使用

height

width

設定了寬度和高度。這些屬性在 DuiLib 屬性清單.xml 中都是可以找到的。大家可以翻一番。

但是大家可能發現了,Logo 的位置不是很好,他僅僅的挨在視窗的左上角,我們應該調整一下它的位置,讓它居中顯示。不過很不幸 DuiLib 好像并沒有居中功能,想實作居中功能要通過布局來功能來實作,代碼遠遠比指定一個屬性要多的多。我們不通過布局方法實作難道就沒有方法了嗎?

内外邊距

标題欄高度是 35,而 Logo 的高度是 18,我們讓 Logo 圖像的上方和左側分别向下和向右移動 7~9 像素,這樣 Logo 就可以居中顯示了。通過 padding 屬性可以指定容器的外邊距,這裡要注意,不像 Web 前端一樣使用的是

margin

,剛切換過來的朋友可能容易出錯,是以要尤其注意。我們通過指定 padding=“8,8,0,0” 的方式,指定了 Logo 檔案左邊和上邊分别有 4 個像素的邊距,代碼如下:

.....
<Control bkimage="Logo.png" height="18" width="18" padding="8,8,0,0"/>
.....
           

此時再看一下效果基本上是上下居中顯示了,而且左側也與邊緣有了寫距離,看上去好看一些了。要注意,

padding

的 4 個參數順序分别是 左、上、右、下。與 Web 前端 CSS 還不一樣,是以大家千萬不要弄混了。

05_了解 XML 使用(布局控制)了解 XML 使用 (布局控制)

再注意 Logo 和标題文字是不是挨的有點近?那麼我們再給 Logo 指定一個右側的邊距,讓标題“離她遠點”。

.....
<Control bkimage="Logo.png" height="18" width="18" padding="8,8,8,0"/>
.....
           
05_了解 XML 使用(布局控制)了解 XML 使用 (布局控制)

可以看到通過 padding 的設定我們可以實作讓容器具有外邊距效果,同樣有外邊距也會有内邊距,我們設定标題欄容器的内邊距同樣可以實作讓内容居中的方法。内容如下:

<!-- 标題欄 -->
<HorizontalLayout height="35" bkcolor="#FFD6DBE9" inset="8,8,8,0">
	<Control bkimage="Logo.png" height="18" width="18" />
	<Label text="duilib tutorial" height="18" padding="8"/>
</HorizontalLayout>
           

我們使用

inset

屬性給外部的水準布局容器設定了左側、上方、右側分别 8 個像素的内邊距,由于 Label 預設是填滿整個容器的,是以我們要給他設定一個高度,否則會被擠下來,而且我們删除掉了 Logo 的

padding

屬性,Logo 與标題之間的間距也不在了。是以這次換個方式,我們給标題文字指定了一個

padding="8"

的屬性,你會發現,如果我們不需要指定上、右、下的其他幾個屬性,我們僅指定填寫第一個左側的資料就可以了。這樣可以讓代碼比較簡練。效果如下:

05_了解 XML 使用(布局控制)了解 XML 使用 (布局控制)

浮動

除了上面的内外邊距可以實作這個效果以外,我們還可以通過讓控件

浮動起來

的方式,通過指定一個 pos 屬性讓它想在哪裡就在哪裡。但前提是你要通過 float 屬性指定控件是一個浮動的控件。代碼如下:

<!-- 标題欄 -->
<HorizontalLayout height="35" bkcolor="#FFD6DBE9">
	<Control bkimage="logo.png" height="18" width="18" float="true" pos="8,8,26,26" />
	<Label text="duilib tutorial" height="18" float="true" pos="35,8,185,26"/>
</HorizontalLayout>
           

去掉了外部水準布局容器的内邊距後,我們讓

Control

控件和

Label

控件都成為浮動控件,并指定他們的具體坐标。注意 pos 的第三個和第四個參數,他們決定了控件的右上角位置和右下角位置。要算上控件本身的大小,比如例子中的 Label 控件第三個參數 185,是算上了控件左側的 35 + 控件自身寬度的總和,如下圖所示:

05_了解 XML 使用(布局控制)了解 XML 使用 (布局控制)

這種方式雖然能實作功能,但是代碼寫起來繁瑣,不容易維護,要調整一個位置要修改好多地方,非常容易出錯。是以除非必要,還是建議大家少用這個浮動的功能。

接下來我們來把右側的幾個功能按鈕也做一下,我們還是去找一下素材。在 Iconfont-阿裡巴巴矢量圖示庫 搜尋 min、max、close 等關鍵字就可以搜尋到相關素材。在找素材的時候大家請注意,由于我們按鈕需要三種狀态的圖檔,一個是普通樣式的,一個是滑鼠懸浮狀态的圖檔,一個是滑鼠按下時的效果,三種效果我們都要找,為了差別不同效果,我使用了不同的顔色。你們也可以根據自己的需要設定不同的顔色,我分别給普通、懸浮狀态和按下狀态的圖檔命名為

btn_*_normal.png

btn_*_hovered.png

btn_*_pushed.png

,如下圖:

05_了解 XML 使用(布局控制)了解 XML 使用 (布局控制)

由于實在沒有找到還原視窗的合适圖檔,是以臨時找個了帶了兩個箭頭的圖檔頂替了(論身邊有個視覺是多麼美妙的事情),4 種按鈕預設隻顯示最小化、最大化和關閉,還原按鈕隻有在最大化的情況下才顯示,是以預設我們讓他不顯示,最終代碼如下:

<?xml version="1.0" encoding="UTF-8"?>
<Window size="640,480" caption="0,0,0,35">
	<VerticalLayout>
		<!-- 标題欄 -->
		<HorizontalLayout height="35" bkcolor="#FFD6DBE9" inset="8,8,8,0">
			<Control bkimage="logo.png" height="18" width="18" />
			<Label text="duilib tutorial" height="18" padding="8"/>
			<HorizontalLayout childpadding="3" width="60">
				<Button height="18" width="18" normalimage="btn_min_normal.png" hotimage="btn_min_hovered.png" pushedimage="btn_min_pushed.png" />
				<Button height="18" width="18" normalimage="btn_max_normal.png" hotimage="btn_max_hovered.png" pushedimage="btn_max_pushed.png" />
				<Button height="18" width="18" normalimage="btn_restore_normal.png" hotimage="btn_restore_hovered.png" pushedimage="btn_restore_pushed.png" visible="false"/>
				<Button height="18" width="18" normalimage="btn_close_normal.png" hotimage="btn_close_hovered.png" pushedimage="btn_close_pushed.png" />
			</HorizontalLayout>
		</HorizontalLayout>
		<!-- 視窗内容區域 -->
		<HorizontalLayout bkcolor="#FF4D6082">
		</HorizontalLayout>
	</VerticalLayout>
</Window>
           
  • 使用

    childpadding

    屬性指定了右側三個按鈕水準布局的子控件左右間距(如果是垂直布局那麼就是上下間距)
  • 使用

    normalimage

    屬性設定控件的預設圖檔樣式
  • 使用

    hotimage

    屬性設定控件的滑鼠懸浮狀态圖檔
  • 使用

    pushedimage

    屬性設定滑鼠按下狀态圖檔
  • 使用

    visible

    屬性設定還原控件的預設顯示狀态(見還原按鈕的最後一個屬性)

重新運作一下程式,我們可以看到三個按鈕已經在右上角了。

05_了解 XML 使用(布局控制)了解 XML 使用 (布局控制)

當我們滑鼠按下關閉按鈕時,顔色會變為紅色

05_了解 XML 使用(布局控制)了解 XML 使用 (布局控制)

占位符

因為我們給右側三個按鈕的水準布局容器設定了固定寬度,并且他們左邊的 Label 控件是預設拉伸占滿整個容器的狀态,是以三個按鈕的容器預設就被 “擠” 到最右側去了。如果左邊我們也設定了一個預設寬度的容器,右側關閉按鈕也被設定為固定寬度。那麼布局就不是這樣了,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<Window size="640,480" caption="0,0,0,35">
	<VerticalLayout>
		<!-- 标題欄 -->
		<HorizontalLayout height="35" bkcolor="#FFD6DBE9" inset="8,8,8,0">
			<HorizontalLayout width="185">
				<Control bkimage="logo.png" height="18" width="18" />
				<Label text="duilib tutorial" height="18" padding="8"/>
			</HorizontalLayout>
			<HorizontalLayout childpadding="3" width="60">
				<Button height="18" width="18" normalimage="btn_min_normal.png" hotimage="btn_min_hovered.png" pushedimage="btn_min_pushed.png" />
				<Button height="18" width="18" normalimage="btn_max_normal.png" hotimage="btn_max_hovered.png" pushedimage="btn_max_pushed.png" />
				<Button height="18" width="18" normalimage="btn_restore_normal.png" hotimage="btn_restore_hovered.png" pushedimage="btn_restore_pushed.png" visible="false"/>
				<Button height="18" width="18" normalimage="btn_close_normal.png" hotimage="btn_close_hovered.png" pushedimage="btn_close_pushed.png" />
			</HorizontalLayout>
		</HorizontalLayout>
		<!-- 視窗内容區域 -->
		<HorizontalLayout bkcolor="#FF4D6082">
		</HorizontalLayout>
	</VerticalLayout>
</Window>
           
05_了解 XML 使用(布局控制)了解 XML 使用 (布局控制)

此時如果想讓三個按鈕靠右顯示,我們可以使用 占位符

<?xml version="1.0" encoding="UTF-8"?>
<Window size="640,480" caption="0,0,0,35">
	<VerticalLayout>
		<!-- 标題欄 -->
		<HorizontalLayout height="35" bkcolor="#FFD6DBE9" inset="8,8,8,0">
			<HorizontalLayout width="185">
				<Control bkimage="logo.png" height="18" width="18" />
				<Label text="duilib tutorial" height="18" padding="8"/>
			</HorizontalLayout>
			<Control />
			<HorizontalLayout childpadding="3" width="60">
				<Button height="18" width="18" normalimage="btn_min_normal.png" hotimage="btn_min_hovered.png" pushedimage="btn_min_pushed.png" />
				<Button height="18" width="18" normalimage="btn_max_normal.png" hotimage="btn_max_hovered.png" pushedimage="btn_max_pushed.png" />
				<Button height="18" width="18" normalimage="btn_restore_normal.png" hotimage="btn_restore_hovered.png" pushedimage="btn_restore_pushed.png" visible="false"/>
				<Button height="18" width="18" normalimage="btn_close_normal.png" hotimage="btn_close_hovered.png" pushedimage="btn_close_pushed.png" />
			</HorizontalLayout>
		</HorizontalLayout>
		<!-- 視窗内容區域 -->
		<HorizontalLayout bkcolor="#FF4D6082">
		</HorizontalLayout>
	</VerticalLayout>
</Window>
           
05_了解 XML 使用(布局控制)了解 XML 使用 (布局控制)

同樣的代碼我們隻是在兩個水準布局中間增加了一個空的 Control 控件,它會根據父容器的寬度無限拉伸,由于兩側的兩個水準布局容器已經設定了固定寬度,那麼它會 “野蠻” 的把剩下所有控件都占掉。這就是所謂的 占位符。如果你需要實作一個緊貼頂部和緊貼底部的容器,那麼你可以使用垂直布局方式,中間同樣增加一個占位符來實作需求。

到這裡我們已經基本上把所有布局相關的内容都說的差不多了,如果還有更重要的内容我會一點點在補充。大家發現,除了之前我們建構視窗時寫了一部分代碼,剩下的内容都是我們通過 XML 來實作的,并沒有敲一行多餘的代碼。這就是 DuiLib,界面和業務有很大的分離性。接下來我們該看看怎麼響應按鈕的點選事件了。

預設樣式

DuiLib 在 XML 文法中提供了一些預設樣式功能,我們可以給指定控件預設一些預設的樣式,當建立這種控件的時候,預設樣式就會在其上面展現。比如我們希望所有按鈕都有一個邊框。那麼可以像下面這樣來編寫 XML

<?xml version="1.0" encoding="UTF-8"?>
<Window size="640,480" caption="0,0,0,35">
	<Default name="Button" value="bordersize=&quot;1&quot; bordercolor=&quot;#FF222222&quot;" />
	<VerticalLayout>
		<!-- 标題欄 -->
		<HorizontalLayout height="35" bkcolor="#FFD6DBE9" inset="8,8,8,0">
			<HorizontalLayout width="185">
				<Control bkimage="logo.png" height="18" width="18" />
				<Label text="duilib tutorial" height="18" padding="8"/>
			</HorizontalLayout>
			<Control />
			<HorizontalLayout childpadding="3" width="60">
				<Button name="minbtn" height="18" width="18" normalimage="btn_min_normal.png" hotimage="btn_min_hovered.png" pushedimage="btn_min_pushed.png" />
				<Button name="maxbtn" height="18" width="18" normalimage="btn_max_normal.png" hotimage="btn_max_hovered.png" pushedimage="btn_max_pushed.png" />
				<Button name="restorebtn" height="18" width="18" normalimage="btn_restore_normal.png" hotimage="btn_restore_hovered.png" pushedimage="btn_restore_pushed.png" visible="false"/>
				<Button name="closebtn" height="18" width="18" normalimage="btn_close_normal.png" hotimage="btn_close_hovered.png" pushedimage="btn_close_pushed.png" />
			</HorizontalLayout>
		</HorizontalLayout>
		<!-- 視窗内容區域 -->
		<HorizontalLayout bkcolor="#FF4D6082">
		</HorizontalLayout>
	</VerticalLayout>
</Window>
           

我們增加了一行

<Default name="Button" value="bordersize=&quot;1&quot; bordercolor=&quot;#FF222222&quot;" />
           

設定其 name 屬性為 “Button”,value 屬性為樣式描述,因為是作為 XML 的值來使用,是以雙引号等要做一下轉義。這也操作後,所有按鈕都具備了

"bordersize="1" bordercolor="#FF222222"

兩個屬性。如下所示:

05_了解 XML 使用(布局控制)了解 XML 使用 (布局控制)

全局字型

像預設屬性一樣,全局字型也是可以讓多個控件使用的一個屬性,不過控件可以決定是否使用這個屬性,而上面介紹的預設屬性是強制的。使用方法如下:

<?xml version="1.0" encoding="UTF-8"?>
<Window size="640,480" caption="0,0,0,35">
	<Font shared="true" id="1" name="微軟雅黑" size="18" />
	<VerticalLayout>
		<!-- 标題欄 -->
		<HorizontalLayout height="35" bkcolor="#FFD6DBE9" inset="8,8,8,0">
			<HorizontalLayout width="185">
				<Control bkimage="logo.png" height="18" width="18" />
				<Label text="duilib tutorial" height="18" padding="8" font="1"/>
			</HorizontalLayout>
			<Control />
			<HorizontalLayout childpadding="3" width="60">
				<Button name="minbtn" height="18" width="18" normalimage="btn_min_normal.png" hotimage="btn_min_hovered.png" pushedimage="btn_min_pushed.png" />
				<Button name="maxbtn" height="18" width="18" normalimage="btn_max_normal.png" hotimage="btn_max_hovered.png" pushedimage="btn_max_pushed.png" />
				<Button name="restorebtn" height="18" width="18" normalimage="btn_restore_normal.png" hotimage="btn_restore_hovered.png" pushedimage="btn_restore_pushed.png" visible="false"/>
				<Button name="closebtn" height="18" width="18" normalimage="btn_close_normal.png" hotimage="btn_close_hovered.png" pushedimage="btn_close_pushed.png" />
			</HorizontalLayout>
		</HorizontalLayout>
		<!-- 視窗内容區域 -->
		<HorizontalLayout bkcolor="#FF4D6082">
		</HorizontalLayout>
	</VerticalLayout>
</Window>
           

我們添加了一行

<Font shared="true" id="1" name="微軟雅黑" size="18" />
           

并在标題的 Label 中增加了一個

Font="1"

的屬性,用意就是讓這個 Label 使用 Font 編号為 1 的字型。而 Font 通過 id 屬性指定了編号。這樣再運作程式後,窗體标題就變成了微軟雅黑 18 大小的字型。

05_了解 XML 使用(布局控制)了解 XML 使用 (布局控制)

Font 有如下屬性可以使用

  • name:字型名稱
  • size:字型大小
  • bold:粗體
  • italic:斜體
  • underline:下劃線
  • id:字型的編号
  • shared:是否共享