1.[Andriod]之Andriod布局 VS WinPhone布局

0.写在前面的话

近来被HTML+CSS的布局折腾的死去活来,眼巴巴的看着CSS3中的flex,grid等更便捷更高效的的布局方式无法在项目中应用,心里那叫一个窝火啊,去你妹的兼容性,,,

最近体验下Android开发,第一件事就是翻翻看安卓提供的布局方式方便不,因为笔者现在是做WP的,于是乎有了这篇比较两个平台提供的一些基础的布局方式的博文。

另外,安装完Android Studio后,在Android的SDK的目录下有一个docs的文件夹,这里面提供的有离线的官方文档。

Android应用在当前元素上的布局属性均以layout_开头,大家可以结合离线的官方文档(布局属性的介绍在sdk\docs\reference\android\widget\***.LayoutParams.html文件有详细说明)在IDE中多多尝试各种的以layout_开头的属性。

1.两平台布局方式概览

Android常用的基本布局元素:LinearLayout,FrameLayout,AbsoluteLayout,RelativeLayout,TableLayout,GridLayout。

Windows Phone常用的基本布局元素:StackPanel、Canvas、Grid,WrapPanel;

罗列完毕,下面根据相似的布局一一对比。

2.LinearLayout VS StackPanel

别看这两位名字差异很大,堆积面板也好,线性布局也好,其实都是干的一件事,水平或者垂直排列子元素。

  • Android-LinearLayout:使用android:orientation属性来控制子元素排列方向,子元素还以使用android:layout_weight属性来控制自身的拉伸权重。
  • WinPhone-StackPanel:使用Orientation属性控制子元素的排列方向。

先来一个StackPanel的DEMO:

 1 <StackPanel  Orientation="Horizontal"
 2                 Background="#f00">
 3     <Button Content="水平排放的按钮1" />
 4     <Button Content="水平排放的按钮2" />
 5 </StackPanel>
 6 
 7 <StackPanel  Orientation="Vertical"
 8                 Background="#00f">
 9     <Button Content="垂直排放的按钮1" />
10     <Button Content="垂直排放的按钮2"
11             HorizontalAlignment="Right" />
12 </StackPanel>

再来一个LinearLayout的DEMO(顺带了解到一个格式化代码的快捷键"Ctrl+Alt+L"):

 1 <LinearLayout
 2     android:layout_width="match_parent"
 3     android:layout_height="wrap_content"
 4     android:background="#ff0000"
 5     android:orientation="horizontal">
 6 
 7     <Button
 8         android:layout_width="wrap_content"
 9         android:layout_height="wrap_content"
10         android:text="水平排放的按钮1" />
11 
12     <Button
13         android:layout_width="wrap_content"
14         android:layout_height="wrap_content"
15         android:text="水平排放的按钮2" />
16 
17 </LinearLayout>
18 
19 <LinearLayout
20     android:layout_width="match_parent"
21     android:layout_height="wrap_content"
22     android:background="#0000ff"
23     android:orientation="vertical">
24 
25     <Button
26         android:layout_width="wrap_content"
27         android:layout_height="wrap_content"
28         android:text="垂直排放的按钮1" />
29 
30     <Button
31         android:layout_width="wrap_content"
32         android:layout_height="wrap_content"
33         android:layout_gravity="bottom|right"
34         android:text="垂直排放的按钮2" />
35 </LinearLayout>

代码虽然不同,但是效果是一样一样的(左边WP右边安卓)...

看看LinearLayout的子元素应用android:layout_weight属性后是怎样的表现:

 1 <LinearLayout
 2     android:layout_width="match_parent"
 3     android:layout_height="wrap_content"
 4     android:background="#ff0000"
 5     android:orientation="horizontal">
 6     <Button
 7         android:layout_width="wrap_content"
 8         android:layout_height="wrap_content"
 9         android:layout_weight="1"
10         android:text="水平排放的按钮1" />
11     <Button
12         android:layout_width="wrap_content"
13         android:layout_height="wrap_content"
14         android:layout_weight="2"
15         android:text="水平排放的按钮2" />
16 </LinearLayout>

效果如下(起初我以为是按照1+2等于3,第一个元素占1/3,第二个元素占2/3,结果却并非如此。其中缘由读者自行品味“权重”二字吧):

3.FrameLayout&AbsoluteLayout VS Canvas

在官方文档布局介绍文档中已经不见FrameLayout和AbsoluteLayout这两位了,估计是在安卓如此丰富的设备分辨率下以及很少有场景能用到这两种布局方式了。

  • Android-FrameLayout:以FrameLayout的左上角为基准起始位置,第一个子元素在第一层,第二个子元素在第二层,,,依次类推,就像千层饼一样。
  • Android-AbsoluteLayout:以AbsoluteLayout的左上角为基准起始位置([0,0]点),子元素利用二维坐标系android:layout_x和android:layout_y(距离[0,0]点的偏移量)进行布局;如果后面的子元素区域和前面的子元素区域重合,则也会像FrameLayout的子元素一样遮盖住前面的子元素。
  • WinPhone-Canvas:布局行为上等同于FrameLayout和AbsoluteLayout的结合体,为子元素提供Canvas.Left,Canvas.Top和Canvas.ZIndex三个附加属性来控制子元素在当前Canvas中的绝对位置和层级。

 先上一个Canvas的DEMO:

 1 <Canvas>
 2     <Border Canvas.Left="60"
 3             Canvas.Top="60"
 4             Canvas.ZIndex="1"
 5             Height="80"
 6             Width="80"
 7             Background="#FFF" />
 8     <Border Height="200"
 9             Width="200"
10             Background="#F00" />
11     <Border Canvas.Left="20"
12             Canvas.Top="20"
13             Height="160"
14             Width="160"
15             Background="#0F0" />
16     <Border Canvas.Left="40"
17             Canvas.Top="40"
18             Height="120"
19             Width="120"
20             Background="#00F" />
21 </Canvas>

在来一个FrameLayout和AbsoluteLayout的DEMO:

 1 <FrameLayout
 2     android:layout_width="wrap_content"
 3     android:layout_height="wrap_content">
 4     <LinearLayout
 5         android:layout_width="200dp"
 6         android:layout_height="200dp"
 7         android:background="#ff0000" />
 8     <LinearLayout
 9         android:layout_width="160dp"
10         android:layout_height="160dp"
11         android:layout_gravity="center"
12         android:background="#00ff00" />
13     <LinearLayout
14         android:layout_width="120dp"
15         android:layout_height="120dp"
16         android:layout_gravity="center"
17         android:background="#0000ff" />
18     <LinearLayout
19         android:layout_width="80dp"
20         android:layout_height="80dp"
21         android:layout_gravity="center"
22         android:background="#ffffff" />
23 </FrameLayout>
24 <AbsoluteLayout
25     android:layout_width="wrap_content"
26     android:layout_height="wrap_content">
27     <LinearLayout
28         android:layout_width="200dp"
29         android:layout_height="200dp"
30         android:background="#ff0000" />
31     <LinearLayout
32         android:layout_width="160dp"
33         android:layout_height="160dp"
34         android:layout_gravity="center"
35         android:layout_x="20dp"
36         android:layout_y="20dp"
37         android:background="#00ff00" />
38     <LinearLayout
39         android:layout_width="120dp"
40         android:layout_height="120dp"
41         android:layout_gravity="center"
42         android:layout_x="40dp"
43         android:layout_y="40dp"
44         android:background="#0000ff" />
45     <LinearLayout
46         android:layout_width="80dp"
47         android:layout_height="80dp"
48         android:layout_gravity="center"
49         android:layout_x="60dp"
50         android:layout_y="60dp"
51         android:background="#ffffff" />
52 </AbsoluteLayout>

看看效果图吧(左WP,右上FrameLayout,右下AbsoluteLayout),也是一样一样的...

4.RelativeLayout VS WrapPanel

  • Android-RelativeLayout:相对布局可以让子元素控制与父容器(RelativeLayout)的相对位置、控制与其他兄弟子元素的相对位置,常用的Layout属性为(均应用在子元素身上):
    • android:layout_centerHrizontal  ture|false :在父容器中水平居中
    • android:layout_centerVertical ture|false:在父容器中垂直居中
    • android:layout_centerInparent ture|false:在父容器中水平且垂直完全居中
    • 上述3个属性控制子元素的居中问题。
    • android:layout_alignParentBottom ture|false:停靠在父容器的底部
    • android:layout_alignParentLeft ture|false:停靠在父容器的左部
    • android:layout_alignParentRight ture|false:停靠在父容器的右部
    • android:layout_alignParentTop ture|false:停靠在父容器的顶部
    • 以上4个属性控制子元素是在父容器的上下左右方向上的对齐问题。
    • android:layout_below @+id/xxid:在指定兄弟元素的下边
    • android:layout_above @+id/xxid:在指定兄弟元素的的上边
    • android:layout_toLeftOf @+id/xxid:在指定兄弟元素的左边
    • android:layout_toRightOf @+id/xxid:在指定兄弟元素的右边
    • 以上4个属性控制子元素相对与指定兄弟元素的位置。
    • android:layout_alignTop @+id/xxid:与指定兄弟元素的上边对齐
    • android:layout_alignLeft @+id/xxid:与指定兄弟元素的左边对齐
    • android:layout_alignBottom @+id/xxid:与指定兄弟元素的下边对齐
    • android:layout_alignRight @+id/xxid:与指定兄弟元素的右边对齐
    • 以上4个属性控制子元素相对与指定兄弟元素的对齐方式。
    • android:layout_marginBottom xxdp:距离某元素的下边距
    • android:layout_marginLeft xxdp:距离某元素左边距
    • android:layout_marginRight xxdp:距离某元素右边距
    • android:layout_marginTop xxdp:距离某元素上边距
    • 以上4个属性控制子元素相对于其他元素的相对外边距,注意:如果当前元素没有指定其相对的兄弟元素,则相对于父容器RelativeLayout。
  • WinPhone-WrapPanel:我把WinPhone中这个布局容器称为可换行的StackPanel,也具有Orientation属性来控制子元素的排列方向,同时增加了ItemHeight和ItemWidth属性来控制元素的有效宽高,如果不设置这两个属性则以子元素的实际宽高来排序。和Android的RelativeLayout没什么相似之处(WrapPanel功能也弱了好多),和LinerLayout倒是有点相似。

先看一看WrapPanel的DEMO吧:

 1 <toolkit:WrapPanel Orientation="Horizontal"
 2                     ItemHeight="200"
 3                     ItemWidth="200">
 4     <Rectangle Width="100"
 5                 Height="200"
 6                 Fill="#F00"
 7                 HorizontalAlignment="Left" />
 8     <Rectangle Width="200"
 9                 Height="200"
10                 Fill="#0F0" />
11     <Rectangle Width="200"
12                 Height="100"
13                 Fill="#00F"
14                 VerticalAlignment="Bottom" />
15 </toolkit:WrapPanel>

效果如下(如果不设置ItemHeight和ItemWidth,则3个元素会紧挨着,蓝色的还是在第二行,因为第一行装不下,这就是Wrap提供的功能):

看下强大灵活的RelativeLayout的DEMO:

 1 <RelativeLayout
 2     android:layout_width="match_parent"
 3     android:layout_height="140dp"
 4     android:background="#F00"
 5     android:layout_marginBottom="2dp">
 6     <Button
 7         android:layout_width="wrap_content"
 8         android:layout_height="40dp"
 9         android:background="#00F"
10         android:text="水平居中"
11         android:layout_centerHorizontal="true" />
12     <Button
13         android:layout_width="wrap_content"
14         android:layout_height="40dp"
15         android:background="#00F"
16         android:text="垂直居中"
17         android:layout_centerVertical="true" />
18     <Button
19         android:layout_width="wrap_content"
20         android:layout_height="40dp"
21         android:background="#00F"
22         android:text="水平且垂直居中"
23         android:layout_centerInParent="true" />
24 </RelativeLayout>
25 
26 <RelativeLayout
27     android:layout_width="match_parent"
28     android:layout_height="140dp"
29     android:background="#F00"
30     android:layout_marginBottom="2dp">
31     <Button
32         android:layout_width="wrap_content"
33         android:layout_height="40dp"
34         android:background="#00F"
35         android:text="停靠在父容器左上角"
36         android:layout_alignParentLeft="true"
37         android:layout_alignParentTop="true"/>
38     <Button
39         android:layout_width="wrap_content"
40         android:layout_height="40dp"
41         android:background="#00F"
42         android:text="停靠在父容器右上角"
43         android:layout_alignParentRight="true"
44         android:layout_alignParentTop="true"/>
45     <Button
46         android:layout_width="wrap_content"
47         android:layout_height="40dp"
48         android:background="#00F"
49         android:text="停靠在父容器右下角"
50         android:layout_alignParentRight="true"
51         android:layout_alignParentBottom="true" />
52     <Button
53         android:layout_width="wrap_content"
54         android:layout_height="40dp"
55         android:background="#00F"
56         android:text="停靠在父容器左下角"
57         android:layout_alignParentLeft="true"
58         android:layout_alignParentBottom="true" />
59 </RelativeLayout>
60     
61 <RelativeLayout
62     android:layout_width="match_parent"
63     android:layout_height="wrap_content"
64     android:background="#F00"
65     android:layout_marginBottom="2dp">
66     <Button
67         android:id="@+id/btn1"
68         android:layout_width="120dp"
69         android:layout_height="120dp"
70         android:background="#00F"
71         android:text="第一个元素"
72         android:layout_centerInParent="true" />
73     <TextView
74         android:layout_height="wrap_content"
75         android:layout_width="match_parent"
76         android:text="在第一个元素右边且和起一个元素上边对齐"
77         android:layout_toRightOf="@+id/btn1"
78         android:layout_alignTop="@+id/btn1"/>
79     <TextView
80         android:layout_height="wrap_content"
81         android:layout_width="match_parent"
82         android:text="在第一个元素左边且和起一个元素下边对齐"
83         android:layout_toLeftOf="@+id/btn1"
84         android:layout_alignBottom="@+id/btn1"/>
85 </RelativeLayout>

效果图如下(其实RealtiveLayout还允许子元素设置更多的属性来控制相对布局,我在上面列的只是几个比较常见的,有兴趣的可以翻阅一下官方的文档(sdk/docs/reference/android/widget/RelativeLayout.LayoutParams.html)或者在IDE中实验一下其他的布局属性):

5.TableLayout&GridLayout VS Grid

TableLayout也不再官方的推荐之列了,取而代之的是API Level14(Android4.0)中新增的GridLayout布局。

  • Android-TableLayout:表哥布局,行:一行一个TableRow对象或者一个View对象;列:一个子元素为一列;TableLayout通过android:collapseColumns控制隐藏的列、通过android:stretchColumns控制列的拉伸、通过android:shrinkColumns控制列的收缩,但是无法设置固定的行数和列数(行数和列数按行列上出现的最大子元素数量为准);子元素可以通过android:layout_colum属性控制自己排在第几列、通过android:layout_span控制自己可以横跨几列,但是无法实现跨行显示。
  • Android-GridLayout:针对上述的TableLayout存在的问题,Google在API Level14(Android4.0)中引入可新的布局容器GridLayout。GridLayout通过android:orientation设置子元素是水平还是垂直排序,通过android:rowCount控制行数,通过android:columnCount控制列数;子元素可以通android:layout_row设置所在行、  通过android:layout_column设置所在列、通过android:layout_rowSpan设置跨几行、 通过android:layout_columnSpan设置跨几列。
  • WinPhone-Grid:Grid是WinPhone开发中最常用的布局容器,可以通过设置行数、列数以及行列的宽高(可以是固定值或者比例值或者自动根据子元素来确定),子元素通过附加属性Grid.Row、Grid.Column、Grid.RowSpan和Grid.ColumnSpan设置子元素的所在的行、列、跨的行数和跨的列数。

看一下Gird的DEMO:

 1 <Grid>
 2     <Grid.RowDefinitions>
 3         <RowDefinition Height="120" />
 4         <RowDefinition Height="120" />
 5         <RowDefinition Height="120" />
 6         <RowDefinition Height="120" />
 7         <RowDefinition Height="120" />
 8     </Grid.RowDefinitions>
 9     <Grid.ColumnDefinitions>
10         <ColumnDefinition Width="1*" />
11         <ColumnDefinition Width="1*" />
12         <ColumnDefinition Width="1*" />
13         <ColumnDefinition Width="1*" />
14     </Grid.ColumnDefinitions>
15     <Button Content="7"
16             Width="100"
17             Height="100"
18             Margin="0" />
19     <Button  Grid.Column="1"
20                 Content="8"
21                 Width="100"
22                 Height="100" />
23     <Button  Grid.Column="2"
24                 Content="8"
25                 Width="100"
26                 Height="100" />
27     <Button  Grid.Column="3"
28                 Content="/"
29                 Width="100"
30                 Height="100" />
31     <Button Grid.Row="1"
32             Content="4"
33             Width="100"
34             Height="100"
35             Margin="0" />
36     <Button Grid.Row="1"
37             Grid.Column="1"
38             Content="5"
39             Width="100"
40             Height="100" />
41     <Button Grid.Row="1"
42             Grid.Column="2"
43             Content="6"
44             Width="100"
45             Height="100" />
46     <Button Grid.Row="1"
47             Grid.Column="3"
48             Content="*"
49             Width="100"
50             Height="100" />
51     <Button Grid.Row="2"
52             Content="1"
53             Width="100"
54             Height="100"
55             Margin="0" />
56     <Button Grid.Row="2"
57             Grid.Column="1"
58             Content="2"
59             Width="100"
60             Height="100" />
61     <Button Grid.Row="2"
62             Grid.Column="2"
63             Content="3"
64             Width="100"
65             Height="100" />
66     <Button Grid.Row="2"
67             Grid.Column="3"
68             Content="-"
69             Width="100"
70             Height="100" />
71     <Button Grid.Row="3"
72             Grid.ColumnSpan="2"
73             Content="0"
74             Width="220"
75             Height="100"
76             Margin="0" />
77     <Button Grid.Row="3"
78             Grid.Column="2"
79             Content="."
80             Width="100"
81             Height="100" />
82     <Button Grid.Row="3"
83             Grid.Column="3"
84             Grid.RowSpan="2"
85             Content="+"
86             Width="100"
87             Height="220" />
88     <Button Grid.Row="4"
89             Grid.ColumnSpan="3"
90             Content="="
91             Width="340"
92             Height="100" />
93 </Grid>

效果如下:

在看一个GridLayout的DEMO:

 1 <GridLayout
 2     android:layout_width="wrap_content"
 3     android:layout_height="wrap_content"
 4     android:columnCount="4"
 5     android:orientation="horizontal"
 6     android:rowCount="5">
 7     <Button android:text="7" />
 8     <Button android:text="8" />
 9     <Button android:text="9" />
10     <Button android:text="/" />
11     <Button android:text="4" />
12     <Button android:text="5" />
13     <Button android:text="6" />
14     <Button android:text="×" />
15     <Button android:text="1" />
16     <Button android:text="2" />
17     <Button android:text="3" />
18     <Button android:text="-" />
19     <Button
20         android:layout_columnSpan="2"
21         android:layout_gravity="fill"
22         android:text="0" />
23     <Button android:text="." />
24     <Button
25         android:layout_gravity="fill"
26         android:layout_rowSpan="2"
27         android:text="+" />
28     <Button
29         android:layout_columnSpan="3"
30         android:layout_gravity="fill"
31         android:text="=" />
32 </GridLayout>

效果图如下(和WP的Grid效果一样,但是GridLayout的子元素的行列可以不显示指定,GridLayout会根据行列数的设置和子元素所在的顺序自动确定它的行列,xml编码比较简洁):

由于TableLayout不能跨行,则布局上述的界面就要结合其他的布局容器才能完成了(而且用上了一些固定的宽高值,不推荐这样做):

 1 <TableLayout
 2     android:layout_width="wrap_content"
 3     android:layout_height="wrap_content">
 4     <TableRow>
 5         <Button android:text="1" />
 6         <Button android:text="2" />
 7         <Button android:text="3" />
 8         <Button android:text="-" />
 9     </TableRow>
10     <TableRow>
11         <LinearLayout
12             android:layout_span="4"
13             android:orientation="horizontal">
14             <LinearLayout
15                 android:layout_width="wrap_content"
16                 android:layout_height="wrap_content"
17                 android:orientation="vertical">
18                 <LinearLayout
19                     android:layout_width="wrap_content"
20                     android:layout_height="wrap_content"
21                     android:orientation="horizontal">
22                     <Button
23                         android:layout_width="176dp"
24                         android:layout_height="wrap_content"
25                         android:text="0" />
26                     <Button
27                         android:layout_width="wrap_content"
28                         android:layout_height="wrap_content"
29                         android:text="." />
30                 </LinearLayout>
31                 <LinearLayout
32                     android:layout_width="wrap_content"
33                     android:layout_height="wrap_content">
34                     <Button
35                         android:layout_width="264dp"
36                         android:layout_height="wrap_content"
37                         android:text="=" />
38                 </LinearLayout>
39             </LinearLayout>
40             <Button
41                 android:layout_width="wrap_content"
42                 android:layout_height="96dp"
43                 android:text="+" />
44         </LinearLayout>
45     </TableRow>
46 </TableLayout>

效果如下:

6.总结

Android的布局容器设计明显偏重于提供自适应的能力,即使是需要设置固定宽高的地方也已dp代替px为单位,或许是安卓众多的设备分辨率所逼迫的吧;

WinPhone的布局容器是从WPF再到Silverlight一路阉割来的,提供的布局方便性灵活性弱了不少,另外它也是不以px为布局单位的,xaml的手写体验比Android的布局xml要好一些。

IOS开发了解一些,它的布局是另外一个极端,严重依赖于像素,设备少嘛,就那几个分辨率,也完全不可能去手写xib文件,,,以前研究IOS开发的时候简直头疼的要死,很多情况还要用OC代码来做布局,呵呵哒;

总的来说,Android提供的布局容器比WinPhone要方便许多,功能和灵活性也能多一些,手写布局xml也完全可行(得益于Android Studio的智能提示做的还挺不错)。

由于笔者刚刚接触Android,文中难免会有不当或者错误之处,欢迎看官们指正。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏ppjun专栏

Android十八章:帧动画

下面我们来说什么是帧动画。小时候有一种书的右下角把每一个动作画好,再快速的翻看,就可以看到一连串的动画了,这就是帧动画。 帧动画只要几张图片就能加载出动画效果...

10210
来自专栏Android知识点总结

Android关于Canvas你所知道的和不知道的一切

Picture相当于先拍一张照片,并且是在别的Canvas上,在别的Canvas上,在别的Canvas上! 重要的话说三遍:当需要的时候在贴在当前的canva...

57420
来自专栏Python爱好者

Python绘制分形树(一)

45980
来自专栏项勇

笔记50 | Android自定义View(一)

31840
来自专栏三十课

【收藏】这么多WEB组件(CSS),攒一个网站够了吧?

总是喜欢简单又精致的东西,美的不繁复也不张扬。这是闷骚程序员的癖好么?闲来无事,把收集到的部分WEB组件整理汇总一下,攒一个逼格高一点的网站够了吧?

450140
来自专栏老马寒门IT

03-移动端开发教程-CSS3新特性(下)

transition的优点在于简单易用,但是它有几个很大的局限。

23600
来自专栏互联网开发者交流社区

css多浏览常见问题

10730
来自专栏Google Dart

AngularDart Material Design 菜单 顶

材质菜单基于MenuModel对象呈现菜单。 此菜单包含material-popup中的material-list和material-button,其文本或图标...

10020
来自专栏知道一点点

八种创建等高列布局【出自w3c】

高度相等列在Web页面设计中永远是一个网页设计师的需求。如果所有列都有相同的背景色,高度相等还是不相等都无关紧要,因为你只要在这些列的父元素中设置一个背景色就可...

14340
来自专栏腾讯NEXT学位

CSS布局解决方案(下)

25870

扫码关注云+社区

领取腾讯云代金券