近来被HTML+CSS的布局折腾的死去活来,眼巴巴的看着CSS3中的flex,grid等更便捷更高效的的布局方式无法在项目中应用,心里那叫一个窝火啊,去你妹的兼容性,,,
最近体验下Android开发,第一件事就是翻翻看安卓提供的布局方式方便不,因为笔者现在是做WP的,于是乎有了这篇比较两个平台提供的一些基础的布局方式的博文。
另外,安装完Android Studio后,在Android的SDK的目录下有一个docs的文件夹,这里面提供的有离线的官方文档。
Android应用在当前元素上的布局属性均以layout_开头,大家可以结合离线的官方文档(布局属性的介绍在sdk\docs\reference\android\widget\***.LayoutParams.html文件有详细说明)在IDE中多多尝试各种的以layout_开头的属性。
Android常用的基本布局元素:LinearLayout,FrameLayout,AbsoluteLayout,RelativeLayout,TableLayout,GridLayout。
Windows Phone常用的基本布局元素:StackPanel、Canvas、Grid,WrapPanel;
罗列完毕,下面根据相似的布局一一对比。
别看这两位名字差异很大,堆积面板也好,线性布局也好,其实都是干的一件事,水平或者垂直排列子元素。
先来一个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,结果却并非如此。其中缘由读者自行品味“权重”二字吧):
在官方文档布局介绍文档中已经不见FrameLayout和AbsoluteLayout这两位了,估计是在安卓如此丰富的设备分辨率下以及很少有场景能用到这两种布局方式了。
先上一个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),也是一样一样的...
先看一看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中实验一下其他的布局属性):
TableLayout也不再官方的推荐之列了,取而代之的是API Level14(Android4.0)中新增的GridLayout布局。
看一下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>
效果如下:
Android的布局容器设计明显偏重于提供自适应的能力,即使是需要设置固定宽高的地方也已dp代替px为单位,或许是安卓众多的设备分辨率所逼迫的吧;
WinPhone的布局容器是从WPF再到Silverlight一路阉割来的,提供的布局方便性灵活性弱了不少,另外它也是不以px为布局单位的,xaml的手写体验比Android的布局xml要好一些。
IOS开发了解一些,它的布局是另外一个极端,严重依赖于像素,设备少嘛,就那几个分辨率,也完全不可能去手写xib文件,,,以前研究IOS开发的时候简直头疼的要死,很多情况还要用OC代码来做布局,呵呵哒;
总的来说,Android提供的布局容器比WinPhone要方便许多,功能和灵活性也能多一些,手写布局xml也完全可行(得益于Android Studio的智能提示做的还挺不错)。
由于笔者刚刚接触Android,文中难免会有不当或者错误之处,欢迎看官们指正。