1. 程式人生 > >duilib各種佈局的作用,相對佈局與絕對佈局的的意義與用法

duilib各種佈局的作用,相對佈局與絕對佈局的的意義與用法

轉載請說明原出處,謝謝~~

       我使用duilib快3個月了,總體感覺duilib的使用還是較為簡單的,只是剛入門時可能有些摸不清頭腦。今天寫一篇關於duilib的入門日誌,大致說一下duilib中的各個佈局的作用,以及很關鍵的相對佈局與絕對佈局的意義與用法。希望可以幫到使用duilib的新手朋友們。duilib高手就可以直接省略這篇文章了!

      我剛使用duilib的時候非常依賴duilib自帶的設計器,用他可以拖拉控制元件,視覺化的做出自己想要的介面。可是用一段時間就會發現原帶的設計器有很多bug,時不時會崩潰,支援的控制元件數量有限,屬性數量也有限,匯出的程式碼冗餘。當時問了幾個高手,大家建議不要使用設計器而應該自己手寫xml程式碼。起初手寫時感覺特別麻煩,可是用幾天後你會發現手寫要比使用設計器好得多:你可以更加了解duilib,熟悉每個控制元件的各個屬性,對控制元件的控制也更加方便。而如果想稱心如意的脫離設計器去編寫xml檔案,有非常有必要弄明白各個佈局的用法和佈局技巧。我現在可以完全靠手寫xml來做出一個程式的介面,相信用了一段duilib的朋友也是這樣。

     在這裡提醒一下新手朋友,在duilib的根目錄有一個屬性列表.xml的檔案,他包含了絕大多數控制元件的絕大多數屬性的介紹,有不懂的屬性記得時常翻看他,同時不得不說這個檔案包含的屬性的確是不全面的,想要知道最全面的屬性資訊,可以看每個控制元件的原始碼,在SetAttribute函式中可以看到最全面的屬性資訊!

      要想手寫xml,當然必須有一個編寫工具,原則上只要是可以編寫文字的工具都可以,大家根據習慣自己挑選適合的工具,我目前在使用的是sublime這款工具,感覺編寫xml非常方便,使用介面也不錯。

6大布局的作用:

      duilib的Layout目錄專門放置佈局相關的容器控制元件,這6個佈局分別為:Container、VerticalLayout、HorizaontalLayout、TileLayout、TabLayout、ChildLayout。容器之間可以任意相互巢狀,我分別說明他們的用法。

      首先我要說明一下,下面介紹的時候,我都預設認為每個控制元件的float屬性為false,也就是不使用絕對定位,這個屬性會打破各個佈局的作用。

    Container:

     Container佈局是其他所有佈局以及含有容器特性(如CList、CListContainerElement)的控制元件的基類,而實際上開發過程中很少使用這個佈局,只用他來做其他更高階的佈局的基類。因為Container佈局中的所有控制元件都會自動填充滿整個佈局,所有的控制元件都疊到了一起,假如恰好有什麼需求要讓子控制元件都覆蓋起來,而且可以隨著容器的改變而自適應填充的話,Container就是不二之選。而除了這個效果之外,一般我們不使用它。

     VerticalLayout、HorizaontalLayout:

     VerticalLayout與HorizaontalLayout佈局無疑是duilib中最常使用的兩個佈局,巧妙的使用這兩個佈局可以滿足大多數的佈局需求。從單詞的意思上不難看出VerticalLayout是縱向佈局,HorizaontalLayout是橫向佈局。這門兩個直接繼承自Container佈局。

     VerticalLayout佈局會讓他包含的元素都縱向排列開,HorizaontalLayout佈局會讓給他包含的元素都橫向排列開:如圖

                                                           

        我故意沒讓控制元件填滿整個容器,為了說明這兩個佈局不會強行讓子元素的總和去填滿容器,縱向佈局會從上到下根據每個控制元件的高度讓他們排到一起,橫向佈局會從左到右根據每個控制元件的寬度讓他們排到一起。另外可以看到,縱向佈局只關心子元素的高度,而不會強行讓子元素的寬度等於容器的寬度,這點從圖片可以看到,橫向佈局同理也是隻關心子元素的寬度。而這兩個佈局經常會巢狀使用,如下效果:


       可以看到我最外層使用了一個縱向佈局,他包含了橫縱橫三個佈局(分別為紅綠藍顏色),每個橫向佈局裡又分別包含了幾個按鈕。我們在編寫介面時經常用到這個方法!以下是這個佈局效果圖對應的xml程式碼:

<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<Window size="300,226">
    <VerticalLayout width="300" height="318" bkcolor="#FFFFFFFF">
        <HorizontalLayout width="300" height="65" bkcolor="#FFFF0000">
            <Button text="按鈕測試" width="60" height="35" />
            <Button text="按鈕測試" width="60" height="63" />
            <Button text="按鈕測試" width="60" height="35" />
        </HorizontalLayout>
        <VerticalLayout width="300" height="96" bkcolor="#FF00FF00">
            <Button text="按鈕測試" width="60" height="64" />
            <Button text="按鈕測試" width="60" height="75" />
            <Button text="按鈕測試" width="60" height="64" />
        </VerticalLayout>
        <HorizontalLayout width="300" height="65" bkcolor="#FF0000FF">
            <Button text="按鈕測試" width="60" height="47" />
            <Button text="按鈕測試" width="60" height="64" />
            <Button text="按鈕測試" width="60" height="64" />
        </HorizontalLayout>
    </VerticalLayout>
</Window>

       TileLayout:

       TileLayout佈局是用來做類似360工具箱的效果:


		<Attribute name="columns" default="1" type="INT" comment="列數,如(4)"/>
		<Attribute name="itemsize" default="0,0" type="SIZE" comment="子項固定大小,如(128,128)"/>

       columns和itemsize屬性,這兩個屬性不能一起用,應該只是用其中的一個。使用columns屬性可以來設定每行中包含的列數,他會自動把包含的元素從左到右從上到下按照columns屬性的設定排列起來,他把每行的列數固定死了。而itemsize有兩個欄位,通過我讀原始碼,發現第二個欄位是無效的,我們只要使用第一個欄位就行了,他會設定每個元素所佔的區域,比如容器的寬度是500,給itemsize設定為 100 x 10,那個每行就會容納5個元素,當我們拉伸了窗體讓容器寬度變為700,那麼每行就會自動容納7個元素,這意味著使用這個屬性會讓每行容納的元素個數是自動可變的!這在很多情況下是很有用的屬性。注意itemsize並不是直接設定了子控制元件的大小,而只是限制了子控制元件的最大區域。比如itemsize為100x100,而子控制元件設定為50x50,那麼 最終的子控制元件大小為50x50,而子控制元件的位置會按照100x100來計算。這個希望讀者自己實踐一下來理解這個效果!

     TabLayout:

     TabLayout佈局同樣常用,他就像MFC的選項卡CTabCtrl控制元件,如圖:


      但是在duilib中TabLayout只是下面的佈局介面,而不包含頂端的選項卡按鈕,所以經常用Option控制元件配合他一起使用,使用他時他會把他包含的下一級元素作為一個頁面,所以我們通常在他裡面放入橫縱向佈局來作為一個頁面,在橫縱向佈局裡再規劃每個頁面的外觀。

      這個控制元件的詳細使用方法大家可以看duilib自帶的360demo,我就不贅述了!

      ChildLayout:

      ChildLayout佈局比較少用,因為他的功能可以用其他佈局來代替,他的作用就是從一個xml檔案中載入佈局來嵌入到ChildLayout佈局所在的地方,使用這個佈局一般只需要指定xmlfile屬性來設定xml檔案位置就可以了。他的意義在於可以把繁雜的大量xml程式碼分隔開。比如他和TabLayout佈局結合,讓TabLayout佈局包含5個ChildLayout佈局,而每個ChildLayout佈局分別從5個xml檔案載入自己的佈局檔案,這樣就可以分塊化的編寫佈局程式碼。

      實際上有個比他更好用的標籤,就是Include標籤,Include不屬於佈局,但他的作用在佈局方面非常類似ChildLayout,指定他的Source屬性到某個xml檔案就可以了。相對ChildLayout,Include的優點是可以自動識別自定義控制元件,而ChildLayout不可以!

      在這裡要提一下360Demo的自定義控制元件,這個demo的自定義控制元件做法誤導了很多人,裡面使用了自定義控制元件的方法,把一個xml佈局檔案嵌入到介面裡,這種做法完全沒必要,直接使用Include標籤,一句xml程式碼可以完全代替自定義控制元件。

      這裡給出一個Include的用法:

<Include source="Login\ScrollBar.xml" count="1" />


      其中source屬性指定xml檔案的路徑,count指定解析的次數。

絕對佈局的意義與用法:

       在知道了6大布局的用法之後,知道了各種樣式的介面外觀的大致佈局方法,而這還遠不夠讓我們寫出漂亮的佈局外觀,只有配合相對佈局與絕對佈局才可以更好的控制介面的元素。值得一提的是,我這裡說的相對佈局和絕對佈局並不是一個容器或者控制元件,這只是一種技巧和使用方法,用在容器佈局所包含的控制元件上,常用到橫縱向佈局中。

      我先來介紹絕對佈局,籠統上說絕對佈局和相對佈局其實只有一個差別,也就是我在前面提到的float屬性,容器中包含的控制元件float屬性為真就是絕對佈局,為假就是相對佈局。不要小看這一個屬性,他帶來的效果可以天壤之別!

      給控制元件的float屬性設為真後,就使用了絕對佈局,故名意思,絕對佈局就是讓控制元件的座標絕對化,這樣這個控制元件就不受他的容器的束縛而可以自己隨意設定自己的位置!比如在橫縱向佈局中給他們包含的子控制元件設定float屬性,這個控制元件就不會被自動橫縱向排列。而我的建議是,能不用絕對佈局就別用絕對佈局!原因有三個:

      1)絕對佈局破壞了各個容器的特性,而不受容器的束縛。

      2)絕對佈局讓控制元件的座標固定,不利於控制元件自動調節位置。

      3)後面提到的相對佈局幾乎可以完成絕對佈局的所有特性。

     那麼為什麼要用絕對佈局,因為他的一個功能是相對佈局無法完成的,就是讓控制元件或者佈局重疊或者相交!有的時候我們必須這樣做來讓控制元件組合起來達到一些效果。我可以明確的說,我在做仿酷狗播放器的過程中,整個xml佈局程式碼只用了2個絕對佈局,一個是編寫搜尋欄仿酷狗音樂播放器開發日誌二——搜尋欄的編寫,一個是編寫電臺控制元件。如圖:


       另外一個非常經典的使用絕對佈局的例子就是我前幾天寫的用duilib製作仿QQ2013動態背景登入器,這些例子都是因為要讓控制元件重疊起來組合出新的控制元件才使用了絕對佈局,如果不讓控制元件重疊或者沒有特殊需求,最好別用絕對佈局。

        雖然不建議使用,但我也得說一下絕對佈局相關的屬性和使用技巧。

        1)把float屬性設定為真。

        2)設定pos屬性,這個屬性在float為真時才有效,他包含四個欄位,分別以為了控制元件的左上右下下個座標的位置,但是建議只指定前兩個欄位來設定控制元件的左上角的座標,控制元件的寬度用width和height屬性來控制,這樣做的好處是避免了計算右下角座標的繁瑣!以後修改的時候也很清晰!

        舉出一個例子:

<Label name="MusicName" float="true" pos="100,100" width="26" height="22" textcolor="#FF505050" endellipsis="true" />

        這裡設定了一個Label控制元件,左上角放到100,100的座標上,控制元件高22,寬26

        不得不提一個很有用的屬性,那就是relativepos屬性,屬性列表沒有列出這個屬性,這是我自己總結的

<Attribute name="relativepos" default="0,0,0,0" type="RECT" comment="設定相對移動,float為真時,分別表示橫縱向位移值,橫縱向縮放值,移動單位建議50或100"/>

        用了這個屬性,就可以讓控制元件擁有相對佈局的一部分特性,那就是根據容器的大小,自己可以調整位置和大小!這個特點我在仿酷狗音樂播放器開發日誌二——搜尋欄的編寫用到了,是為了讓搜尋按鈕可以自己移動。這個屬性的前兩個欄位表示橫縱向的位移值,後兩個欄位表示縮放值,具體效果大家應該自己實踐一下!另外這個屬性預設是有嚴重bug的,就是窗體最小化再恢復後有這個屬性的控制元件會自動無規律偏移,這個bug我修復了,詳見仿酷狗音樂播放器開發日誌二——搜尋欄的編寫

        這樣就介紹完了絕對佈局,然後就是整片文章的最重要部分,相對佈局!

相對佈局的意義與用法:

       我把相對佈局的介紹放到最後,因為它很重要!

       在容器內部使用控制元件或者容器時,float屬性設定為flase(duilib預設為false)就是相對佈局了。這是我非常推薦使用的,前面我也說了我在寫仿酷狗的整個佈局中,上百個控制元件中我只給兩個控制元件使用了絕對佈局,其餘都是相對佈局。他的優點如下:

        1)佈局和控制元件是可以根據窗體的大小改變而自動調整位置的,這點很重要

        2)不需要絕對佈局那樣麻煩的計算各個控制元件的位置

        3)在容器中調整前一個控制元件的位置,後面的控制元件都會自動調整座標

      其實總得來說使用相對佈局意義就是使用佈局控制元件的自動排列特性!

      使用了相對佈局後,就不用設定float屬性和pos屬性,一般只設置甚至不設定width和height屬性。這點很重要,如果你的控制元件或者佈局的大小是固定的,那麼就設定width和height屬性,如果想讓控制元件或者佈局根據窗體的大小而自動調整大小和位置,就不設定這兩個屬性。如果只設置了一個屬性,比如width設定為100,而height不設定,那麼他的高度是自動調整的而寬度是固定的。父容器會自動安排他包含的元素,讓含有width和height屬性的控制元件佔據相應的大小,把剩下的空間都分配給沒有設定wieth和height屬性的容器或者控制元件裡。看下面一個例子:

<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<Window size="300,300">
    <VerticalLayout name="Father">
        <HorizontalLayout name="Sub1" height="50" >
        </HorizontalLayout>


        <VerticalLayout name="Sub2">
        </VerticalLayout>


        <HorizontalLayout name="Sub3" height="50" >
        </HorizontalLayout>
    </VerticalLayout>
</Window>

      可以看到窗體的大小為300x300,而最外層的是一個名為Fahter的縱向容器,包含三個子容器。而Father沒有指定width和height,所以當我改變了窗體的大小時,Father會自動調整自己的大小到和窗體大小相同,而三個子容器我都眉頭指定width屬性,所以三個子容器的寬度和Father是一樣,也就是他們的寬度都是和窗體寬度一樣,並且會自動調整。Sub1和Sub3的高度設定為50,所以他們的高度就固定了,而Sbu2的高度也沒有指定,那他會自動佔據了除了Sub1和Sub2的所有空間!其實這個例子的佈局是非常常見的介面佈局例子,比如說酷狗,sub1和sub3分別表示標題欄和狀態列,sub2為程式的主介面:


       關於酷狗的更加詳細的佈局分析可以看我前面寫的部落格仿酷狗音樂播放器開發日誌——整體框架分析,幾乎每開發酷狗的一部分,我都會把佈局分析一下寫出來。

      把這些知識綜合起來,現在就可以寫出一個自動調整大小的大致佈局了,但是還沒法精確控制每個控制元件的位置。

      利用上面介紹的自動佔位的特性,我這裡舉一個標題欄編寫的例子:

<HorizontalLayout name="background" height="30" bkimage="file='UI\BKImage\4.jpg' source='0,0,1000,30'" ><!-- 標題欄 -->
        <Label text="面板與視窗調整——Redrain播放器" textcolor="#FFFFFFFF" textpadding="5,0,0,0" font="1" autocalcwidth="false" width="300"/>
	<Control />
	<Button name="closebtn" width="23" height="18" padding="0,6,0,0" normalimage="UI\title\close_normal.png" hotimage="UI\title\close_hover.png" pushedimage="UI\title\close_down.png" />                     
</HorizontalLayout>

       這個例子是我的仿酷狗播放器的換膚窗體的標題欄。他的外層是一個橫向佈局,高度為30,寬度隨窗體調整。讓標題文字居於左側,關閉按鈕在最右側,如果讓窗體調整寬度後文字和關閉按鈕自動調整位置,就需要把中間的空位佔滿。這時我們就需要一個佔位控制元件,不給他設定width和height屬性,這樣子他就會自動佔據剩餘的空間!就達到了相對佈局的自動調整位置的效果。這個使用方法是相對佈局裡非常常用的!而這個佔位控制元件在沒有什麼其他要求時建議像我給出的例子那樣,使用Control控制元件,因為他是所有控制元件和容器的祖先基類,程式碼和屬性相對是最少的,這樣有利於提高程式的效率!

       在充分理解了佔位的技巧後,再配合一些微調屬性,就可以完美控制各個控制元件了,這幾個微調屬性分別是inset、padding、childpadding,這幾個屬性的介紹如下:

<Attribute name="padding" default="0,0,0,0" type="RECT" comment="外邊距,如(2,2,2,2)"/>
<Attribute name="inset" default="0,0,0,0" type="RECT" comment="容器的內邊距,如(2,2,2,2)"/>
<Attribute name="childpadding" default="0" type="DWORD" comment="子控制元件之間的額外距離,如(4)"/>

      在float為假,也就是相對佈局中,這幾個屬性才起效。

      inset屬性

      這是給容器控制元件使用的,使用後他所包含的所有使用相對佈局的元素,都會被限制在設定的範圍內,適合對容器內所用元素進行整體的座標控制。比如在前面提到的做360工具箱時,我們使用TileLayout容器來存放每一個工具,我們首先設定inset屬性,就可以讓所有的工具項限制在一定範圍內,例子如下:

<TileLayout name="listctrl" width="540" height="400" inset="20,20,0,20" childpadding="20" vscrollbar="true" columns="2" bkimage="CustomList\List_bk.png" itemhotimage="CustomList\ListItem_bk_hover.png" itemselectedimage="CustomList\ListItem_bk_hover.png">
</TileLayout>

       通過設定inset屬性,讓所有元素限制在一定範圍內而不用重複設定每個元素的屬性。

      childpadding屬性:

      childpadding屬性設定容器內每個元素之間的間距,這個比較容易理解,上面的例子中也用到了childpadding屬性。這個屬性在不同容器中代表不同意思,在橫向佈局中代表子控制元件之間的橫向間隔,在縱向佈局中代表子控制元件之間的縱向間隔,在TileLayout容器中程式碼行與行之間的間隔!

      padding屬性:

      padding屬性是相對佈局中最常用的屬性!用來設定相對於前一個控制元件的位置,這個屬性的控制元件位置微調的關鍵。一般只用他的前兩個欄位,設定左邊距和上邊距,後兩個欄位是無效的,或者說存在問題(為什麼會有問題?請看原始碼)。不過使用這兩個欄位就夠了。這是我的仿酷狗播放器的狀態的佈局程式碼:

<HorizontalLayout height="30" inset="77,0,0,0" bkimage="UI\statusbar\status_bk.png"><!-- 狀態列 -->
    <Button width="31" height="30" padding="0,0,0,0" normalimage="UI\statusbar\add_normal.png" hotimage="UI\statusbar\add_hover.png" pushedimage="UI\statusbar\add_down.png" />
    <Button width="31" height="30" padding="40,0,0,0" normalimage="UI\statusbar\locate_normal.png" hotimage="UI\statusbar\locate_hover.png" pushedimage="UI\statusbar\locate_down.png" />
    <Button width="31" height="30" padding="40,0,0,0" normalimage="UI\statusbar\search_normal.png" hotimage="UI\statusbar\search_hover.png" pushedimage="UI\statusbar\search_down.png" />
    <Button width="31" height="30" padding="40,0,0,0" normalimage="UI\statusbar\setting_normal.png" hotimage="UI\statusbar\setting_hover.png" pushedimage="UI\statusbar\setting_down.png" />
    <Control />
    <Label text="Redrain仿酷狗音樂盒DirectUI ^_^" textpadding="0,6,0,0" width="30" font="0" />
</HorizontalLayout>

      使用padding屬性,這是底部這四個按鈕的相對位置。如果我想整體讓這四個控制元件向右位移10畫素,那麼我只要設定第一個按鈕的padding屬性為padding="10,0,0,0",就可以了,其他佈局完全不需要修改!

結束語

說到這裡也就把佈局的知識總結得差不多了,對於duilib的新手朋友,建議多看看各個demo的佈局檔案,他們幾乎涵蓋了所有知識點。然後結合我總結的東西自己手動寫幾個佈局程式碼,相信很快就可以熟練編寫介面佈局了。另外我的前面部落格裡經常會分析佈局,大家也可以看看。

     我使用duilib的時間也不算長,水平有限,文章中有什麼錯誤或者描述不清,請留言給我,我會及時糾正!

      Redrain  2014.8.13