久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

全面解析布局(Grid & Canvas &StackPanel &Wrappanel)

 賈朋亮博客 2011-05-15
寫這篇文章前,,特意在百度搜索了一下,,發(fā)現(xiàn)目前網(wǎng)上介紹布局的文章不多,質量也不是很 高,。拿grid和canvas來講,,這兩個布局容器還是有許多小細節(jié)值得講的,如果你不了解的話,,開發(fā)中經(jīng)常會遇到一些讓人匪夷所思的事情,。學習 silverlight xaml的過程可以分為布局,樣式,,模板,,資源,動畫,,行為,,綁定等幾個知識點。我個人覺得布局是最難熟練掌握的,。

   布局,,既是基礎中的基礎,也是難點中的難點:

  1,、無法復用:模板,,樣式,上手雖難,,但因為控件的基本結構是不變的,,當你學會為button定義樣式后,以后都不會在為button的樣式發(fā)愁,,但是布局不同,。幾乎沒有一個項目的布局是完全一樣的。

  2,、標準不一:表面上看起來一摸一樣的布局,,可能實現(xiàn)的細節(jié)完全不同,。大多數(shù)情況下而你很難用一個標準去規(guī)范或者界定,,什么時候,,應怎樣做。

  3,、布局不是一堆控件的堆疊,,而是合理的組織,但如何合理的組織,,這個經(jīng)驗需要從眾多項目中磨練才能具備,。

  4、隨著需求的變化,,最容易產(chǎn)生變動的就是布局,。

  5、你沒辦法為布局去寫注釋,,所以一個層次很深很復雜的布局,,維護成本就特別高。比如讓你修改一個一年以前你寫的項目,,還要要徹底改變布局結構的時候,,即使是我自己寫的,我也很難看懂,。

  6,、客戶對silverlight期待很高,希望界面能夠創(chuàng)新,,不走尋常路,,這樣你就可能遇到一些非常規(guī)的布局,他們奇特,,狂野,,而從使用的角 度講,還必須要健壯,,有一定的適應性,。比如一個異型,鏤空,,半透明,,帶陰影的窗體設計,也必須能正確的適應瀏覽器寬高的變化,,能夠完整顯示所有信息,,描述 信息能夠正確的換行等等。我遇到過的最夸張的需求,,客戶有一臺只支持1024*768分辨率的投影機,,和一個分辨率4000:1000(具體數(shù)字記不清楚 了) 這種寬高比超級特殊的LED墻。他希望你的軟件既可以在1024*768下完全顯示,又要在LED下可以充滿全屏且不變形,,而且距離LED十米開發(fā)也要能 看清楚你界面上的每一個字,。

  7、每次修改布局,,都會對他周圍甚至整體產(chǎn)生影響,,必須非常全面的觀察和測試。

  8,、設計布局前還要充分考慮動畫設計,。

  9、還有一些特殊情況,,你無法在blend中看到設計視圖,。這個時候只能用一行一行看代碼,在腦子里還原程序的輪廓,。

   什么是好的布局,?根據(jù)我個人的經(jīng)驗,在滿足設計需求的前提下,,一個好的布局,,還需要考慮以下一些方面,

  1,、結構簡單

  2,、分層清晰

  3、層次不要太深

  3,、相對獨立

  4,、低耦合

  5、自適應性強

  6,、使動畫實現(xiàn)更簡單

  上面幾點不分先后和優(yōu)先級,,你需要根據(jù)項目的實際需求和設計以及開發(fā)周期,權衡他們的比重。

  

  詳解Grid   

   Grid 的最大特點是他可以向四個方向(HorizontalAlignment,VerticalAlignment)填充Usercontrol,。同時,他的 子元素也可以向四個方向填充他們自己,。Grid中所有的子元素都是用margin進行相對定位的(這個相對指相對于父容器Grid)。

  有幾種情況需要特殊注意:

1,、當我們沒有HorizontalAlignment和VerticalAlignment的默認值就是"Stretch",,換句話說如果我們這樣 寫<Rectangle Fill="#FF701313"/>,雖然沒有提到明確指定HorizontalAlignment和VerticalAlignment,,但此 時Rectangle的水平和垂直的填充方式默認就是Stretch,。

  2,、請不要忽略margin的細微差別。如下面兩張圖片中,,這個矩形的寬度,,對齊方式都是左對齊,上下填充對齊,,唯一的區(qū)別是margin.right的值一個為88,,另一個為0,。

    

    

  可如果你此時改變這個矩形父容器的大小,,就可以看出兩者的區(qū)別。其中第一個永遠和他父容器的右邊保持88的間距,。

        

 

   Grid的一個另外一個特點就如他名字一樣,,你可以在grid中根據(jù)自己的需要定義多個行和列來構成你需要的網(wǎng)格。

         

  <Grid x:Name="LayoutRoot" Background="White">  
    <Grid.ColumnDefinitions>
       <ColumnDefinition Width="*"/>
       <ColumnDefinition Width="210"/>
       <ColumnDefinition Width="Auto" MinWidth="244"/>
    </Grid.ColumnDefinitions>
   </Grid>

   

  上面的圖中是一個最基本的Grid,,他分為三列,。每一列的寬度都不同,請注意圖中的三個圖標,,他們分別代表了三種定義列寬度的方式,。

   稱為"Star",對應第一行綠色代碼,, <ColumnDefinition Width="*"/> ,,一顆*在本例中代表的第一列的寬度為LayoutRoot的實際寬度 減去 210 再減去 244后剩下的全部寬度。同時因為LayoutRoot默認是跟隨瀏覽器大小而改變的,,所以第一列的*代表的寬度總是不固定的,。另外你還以得知star在“Star-Pixel-auto“中優(yōu)先級最低,他總是最后計算得來的,。

      稱為"Pixel",, 對應第二行綠色代碼,<ColumnDefinition Width="210"/>,,這個是最好理解的,,第二列的寬度永遠都是210像素。永恒不變,。

   稱為"Auto",, 對應第三行綠色代碼、<ColumnDefinition Width="Auto" MinWidth="244"/>,,第三列的寬度為自動,,同時因為我們指定了另外一個屬性,最小寬度MinWidth="244",,所以得到了如上圖中看到的效果,。假如我們刪掉MinWidth="244",這行代碼,,在當前情況下,我們沒有在第三列放任何控件,,那么第三列的寬度為0,。而當我們在第三列放入一個或多個元素時,這一列的寬度由這一列所包含子元素中,,自身寬度加margin.left和margin.right的總和最大的哪個元素來決定,。

  如下圖所示

  

    

  

    

  第三列的此時的寬度是受灰色矩形影響的而不是紅色圓形,因為灰色矩形的寬度為100 + 40(margin.left) + 40(margin.right),,所以第三列此時的寬度是180,,而紅色圓形是居中對齊的,同時它的寬度只有60,,遠遠小于矩形,,所以他不會影響第三列的寬度。但如果我們此時設置他的margin.right為200,,由于60+200>100+40+40,,那么第三列的寬度會變成260。

   

  下面我們做幾個簡單的算術題來鞏固一下剛才學的知識:

  第一題,,下面代碼定義的列,,每一列的寬度是多少?

    

   答案:寬度100,,分為5列,,每一列的寬度為20。

  第二題,,下面代碼定義的列,,每一列的寬度是多少?

    

  答案,,第一列寬度為2*,,換句話說此時寬度100的Grid,我們首先要將它分為6分,,第一列站2分,,其列各占一份,因為會出現(xiàn)除不盡的情況,,所以5列的寬度依次為33,17,17,17,16,。(注意:grid會自動根據(jù)某種規(guī)律對除不盡進行四舍五入,所以最后一列寬度是16)

 

  第三題,下面代碼定義的列,,每一列的寬度是多少,?

    

  答案,一個寬度為100的Gird,,他的第三列寬度為pixel =50, 而其他的為"star",,所以所有為"Star"的列平分100-50后剩下的寬度,,也就是50/4。所以5列的寬度依次是13,12,50,13,12,。

  第四題,,下面代碼定義的列,每一列的寬度是多少,?

    

  答案,,當出現(xiàn)三種標記混合時,請首先區(qū)分出他們的優(yōu)先級,,pixel > auto > star, 所以我們可以得知,所有定義為star的列的寬度的總和為 100-30-auto,,即70-auto. 我們再假設我們不在第二列(width=auto)放任何元素,那么第二列寬度就是0,,所以所有定義為star的列的寬度的總和為70,。然后我們再來計算 一下,,上面代碼中出現(xiàn)了多少次"star", 1*和*寫法不同,,但效果完全一樣,都記做1個"Star",,所以我們可以得到1+2+3+4+1+1+1一共13顆star,。那么每顆"Star"的寬 度為70/13約為5.384...。所以寬度為100的 Grid,,9列的寬度依次為5,0,11,30,16,22,5,6,5,。

  關于Grid中的位置動畫:Gird中所有的元素定位都是用margin屬性,而這個margin屬性是Object類 型,,silverlight 中 ObjectAnimation是不會自動插值的,,如果你對margin做向左移動的來改變子元素的位置,會得到一個意外的不流暢的動畫(子元素從A點直 接跳到B點),。當然也有解決辦法,,如果你一定要在Gird中位移某個元素,可以使用CompositeTransform的屬性來做動 畫,,CompositeTransform的屬性不是object類型,,所以動畫支持自動插值。

  但如果你非要對margin做動畫,,而且還要流暢顯示的話,,就要自定義一個double類型的依賴屬性,然后專門針對這個屬性寫一個動畫,,當這 個屬性改變時,,在他的屬性改變事件里將它與子元素的margin.left關聯(lián)。這樣也可以實現(xiàn)流暢的動畫,。但這種做法效率很低,,不建議大量使用,。

   Canvas詳解:

   Canvas 直譯為畫布,他的最大特點是,,Canvas中所有子元素定位的方式都是用過Canvas.Left和Canvas.top來進行的(我們可以把 Canvas.left理解為x,,Canvas.top理解為y)所以Canvas中的子元素永遠是相對于Canvas的起點,也就是(0,0點)進行絕 對定位,。不管Canvas的寬高今后變成無窮大,,還是0,他的子元素永遠不會改變位置,。

  Canvas的另一個特點是,,在Canvas中的所有子元素,指定對齊方式(HorizontalAlignment,,VerticalAlignment)不會產(chǎn)生任何作用,。

   另外,在Canvas中也是可以使用margin的(感謝kklldog網(wǎng)友指正),。

 

  Stackpanel詳解:   

  關于StackPanel有兩個特點,,第一是子元素的排列方式永遠是流式的(從左到右,或者從上到下),,這點我就不多介紹了,。

  第二個特點十分特殊,就是Stackpanel具有 截斷 的特性:

  如何理解截斷特性:

  我們可以把截斷理解為是stackpanel內(nèi)部的一個bool變量,。默認為false,當滿足某條件時,,自動變成true;

  當截斷=false時我們能做出如下圖所示的效果:

    

  圖中 Stackpanel的背景色為黑色,他里面放了一個Canvas,,Canvas中放了一個紅色的矩形,,此時只需要設置Canvas.left屬性,就可 以讓紅色的矩形移動到黑色stackpanel之外,。在做一些特效動畫時,,可能需要出現(xiàn)子元素移動到父容器之外的效果,此時你可以使用Canvas的這個 特性,。

  除此之外,,在StackPanel" 截斷=false "時,其實直接改變Stackpanel中子元素的CompositeTransform也可以達到這個效果,,無需在每個元素的外面都包裹一層Canvas,。如下圖所示:

    

  這兩種移動出StackPanel方法各有利弊,特點分明,??梢愿鶕?jù)開發(fā)中的實際情況來權衡到底使用哪種方法?!?/p>

   何時會發(fā)生截斷,?截斷會有哪些影響,?

    當StackPanel水平排列子元素時,所有子元素的寬度總和大于StackPanel寬度時,,會發(fā)生截斷,。

        當StackPanel垂直排列子元素時,所有子元素的高度總和大于StackPanel高度時,,會發(fā)生截斷,。

  截斷的影響,請看下圖:

     

 

  圖中我們雖然指 定了Stackpanel中子元素的CompositeTransform的TranslateX=176,。但由于StackPanel是垂直排列的,,三 個矩形的高度總和超過的StackPanel的高度,所以此時發(fā)生了截斷,。就如你看到的,,此時你永遠不可能實現(xiàn)子元素移出父容器的效果了。

  

 

   WrapPanel詳解:

   WrapPanel和StackPanel 一樣,,也會發(fā)生“截斷”,,并且截斷的時機是完全相同的。除此之外,,當Wrappanel的Orientation=Horizonta時,,子元素默認先從 左向右排列,,當子元素的寬度總和大于Wrappanel的寬度時,,子元素自動向下?lián)Q行。當Orientation=Vertical時,,子元素默認先從上 到下排列,,當子元素的高度總和大于Wrappanel的高度時,子元素自動向右換行,。

 

 

     制空權詳解:

   在所有的容器中的子元素,,都涉及到制空權問題,如下圖所示:

    

    

   在同一個容器中,,三個大小相同的矩形彼此相互覆蓋,,制空權最高的為什么是綠色?從代 碼中我們可以看出,,因為名為green的矩形是最后一個聲明的,。所以我們可以得出,在同一個容器中,,不指定Canvas.ZIndex的前提下,,所有元素 制空權的優(yōu)先級是由他們在xaml代碼中聲明的順序決定的。由于編譯器解析xaml代碼時是按照自上而下的順序解析,,所以后實例化的對象總會獲得更高的制 空權,。

  圖中左下角紅色框中的按鈕名為"arrange by Z order",,他表示在當前的object and time line窗口中所有元素按照制空權的降序排序,點擊一下這個按鈕后,,所有的元素會按照制空權的降序升序排序,但這不會改變?nèi)魏未a和界面效果,,僅僅是改變了object and time line窗口中元素的顯示順序。

  在任何容器中(無論grid,canvas,stackpanel,wrappanel等等),,你都可以通過Canvas.ZIndex來重新定制制空權,。例如:

    按照上面代碼來重新定制制空權后,紅色矩形會獲得最高的制空權,,綠色最低,。Canvas.Zindex的是int32類型,所以他的取值可以是負數(shù),。

<Grid x:Name="LayoutRoot" Background="White">
<Rectangle x:Name="red" Canvas.ZIndex="3" Fill="#FF701313" Stroke="Black" Margin="55,83,0,81" Width="417" HorizontalAlignment="Left"/>
<Rectangle x:Name="blue" Canvas.ZIndex="2" Fill="#FF1F93FF" Stroke="Black" Margin="135,83,0,81" Width="417" HorizontalAlignment="Left"/>
<Rectangle x:Name="green" Canvas.ZIndex="1" Fill="#FF00A37A" Stroke="Black" Margin="215,83,0,81" Width="417" HorizontalAlignment="Left"/>
</Grid>

   下面我們再來做一道題來檢查一下大家的學習情況,。

    

  如上圖所示,我們有五個矩形,,分別為藍(zindex50),,黃(zindex80),綠(zindex120),,黑(zindex20),,紅(zindex-100),那么他們的制空權優(yōu)先級是如何的呢,?

  答案 是:black>green>yello>blue>red ,。得到這個結果的依據(jù)是,首先LayoutRoot的第一級子元素是firstGird,secondGrid和Red,。他們之間的制空權關系是 SecondGrid>FirstGrid>Red,(因為red的zindex=-100),,所以secondGrid的制空權最高。而在 這個基礎上,,雖然green的zindex為120遠遠大于black的zindex,,可由于secondGrid的制空權高于firstGird,所以 black依然會覆蓋blue yello green,。

結果如下圖所示:

    

   補充一點,,不管什么樣的容器,grid,canvas,stackpanel,wrappanel等等他們之間以及他們子元素之間的制空權關系都和上文中介紹的是一摸一樣的,沒有任何區(qū)別,。

 

  總結

     沒有萬金油的布局方法,,簡單的幾個布局可以有千千萬萬種組合,就像7個音符可以組合出無數(shù)中音樂一樣,,希望大家能活學活用,,總結自己的布局流派和風格。

 

   我自己的布局使用習慣

     估 計會有人問這個問題,先聲明我的做法不是標準,,僅僅是一種使用習慣,。我最常用布局的就是Grid,其次是StackPanel(在構建表單的時候我個人更 喜歡用StackPanel嵌套StackPanel的方法,而不是用Grid畫表格,,因為我覺得這樣在Object and timeline視圖里看過去層次非常清晰),,我在一個項目中Canvas和wrappanel使用次數(shù)非常的少,只有當非常明確用途,,而且確定必須使用 Canvas時我才會使用,。另外還有一種情況我會使用Canvas,就是直接從AI文件導入一些矢量圖形時,,往往我會先將這些矢量圖形分組,,分塊,每組都 用Canvas包裹,。好處是Canvas即使改變大小或者形狀,,也不會造成矢量圖形變形。

另外除非要對grid,canvas或者其他靜態(tài)元素做動畫,,行為或者需要在后臺代碼做控制,,否則我不會為他們命名。(靜態(tài)元素通常指logo,花 邊,,裝飾,,大多數(shù)情況下一些grid和canvas也屬于靜態(tài)元素)這樣可以使我在vs中語法提示樹看起來非常干凈,同時編譯后xap文件也會小一些,。

除此之外,,當你從Blend中拖拽一個控件到grid中時,你會發(fā)現(xiàn)他的寬度往往都是相對的,,此時我都會把寬高換成絕對高度,,然后去掉所有自動生成 margin屬性,只有當非常明確需要讓控件呈現(xiàn)相對寬高時,,我才會使用margin。雖然這么做有點累,,但這是一個良好的習慣,,他可以確保你的界面總是 嚴格的按照你的預期呈現(xiàn)各種效果,你甚至可以從這點上輕易區(qū)分出一個界面是由程序員做的還是美工做的,。

“所有真正杰出的設計一旦被設計好,,看起來都是那么的簡單和顯而易見。但是在獲得杰出設計的過程中,,需要付出令人難以置信的努力“-Michael Abrash

    本站是提供個人知識管理的網(wǎng)絡存儲空間,,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導購買等信息,,謹防詐騙。如發(fā)現(xiàn)有害或侵權內(nèi)容,,請點擊一鍵舉報,。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多