Android --- (6),界面布局。横竖屏切换。

时间:2012/11/19

教材:Beginning.Android.4.Application.Development

环境:eclipse


1.安卓用户界面的构建。

--活动通过用户界面和用户进行交互,活动本身不提供界面,而是用Views和ViewGroups来画出用户界面。

(1)屏幕组件的设置。

一个活动的交互界面由各种的小组件组成---Button,TextView等等。在安卓里,用XML语言来定义UI界面,而UI界面的XML文件通常都在res/layout目录中。例如:
<?xml version=”1.0” encoding=”utf-8”?>
<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”
android:layout_width=”fill_parent”
android:layout_height=”fill_parent”
android:orientation=”vertical” >
<TextView
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:text=”@string/hello” />
</LinearLayout>
在活动对应的java文件里面,用onCreate来载入UI界面,在onCreate方法中用setContentView来载入对应的xml文件
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
在编译时期。界面的xml文件会对应的GUI类。

(2)Views和ViewGroups

一个活动包含views和viewgroups,views是在屏幕上面的装饰品,例如button,label,textbox等等,views都是从android.view.View派生出来。
一个或者多个views可以用ViewGroups来分组,ViewGroups(自身也是一个view)提供了一个layout让用户可以指定views的顺序和分布。ViewGroups从android.view.ViewGroups派生。
Android支持一下几种layout
1.LinearLayout
2.AbsoluteLayout
3.TableLayout
4.RelativeLayout
5.FrameLayout
6.ScrollView
接下来讨论下各种layout的细节。

2.LinearLayout布局。

(1)LinearLayout--将views做单行或者单列排列,其中的child view要么被垂直的排布,要么被水平的排布。例如如下代码:
<?xml version=”1.0” encoding=”utf-8”?>
<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”
android:layout_width=”fill_parent”
android:layout_height=”fill_parent”
android:orientation=”vertical” >
<TextView
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:text=”@string/hello” />
</LinearLayout>

在这个xml文件中,布局被设置成linearlayout,而且里面有一个textview控件。每个view或者ViewGroups都有相同的几个属性:
layout_width-->指定了views或者ViewGroups的宽度。
layout_height-->指定views或者ViewGroups的高度
layout_marginTop-->指定了views或者ViewGroups上方的空位。
layout_marginBottom-->指定下方的空位。
layout_marginRight-->指定了右边的空位。
layout_marginLeft-->左边空位。
layout_gravity-->指定了layout的childviews如何排布
layout_weight-->指定了layout额外的空间(extra space)是多少。
layout_x-->指定了views或者ViewGroups的坐标X
layout_y-->指定了坐标y。
--以上某些坐标仅仅使用于某些layout,例如layout_weight和layout_gravity就只适用于一个在LinearLayout里面的view。
<TextView
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:text=”@string/hello” />

以上代码说明了该控件的宽度应该和父控件的宽度一致(android:layout_width="fill_parent"),如果不想这样设置,请设置成wrap_content,这样就仅仅会包围住内容。下面代码指定了控件的宽度:
<TextView
android:layout_width=”100dp”
android:layout_height=”wrap_content”
android:text=”@string/hello” />
<Button
android:layout_width=”160dp”
android:layout_height=”wrap_content”
android:text=”Button”
android:onClick=”onClick” />

有关各种单位,贴出说明如下:
When specifying the size of an element on an Android UI, you should be aware of
the following units of measurement:
dp — Density-independent pixel. 1 dp is equivalent to one pixel on a 160 dpi
screen. This is the recommended unit of measurement when specifying the
dimension of views in your layout. The 160 dpi screen is the baseline density
assumed by Android. You can specify either “dp” or “dip” when referring to a
density-independent pixel.
sp — Scale-independent pixel. This is similar to dp and is recommended for
specifying font sizes.
pt — Point. A point is defi ned to be 1/72 of an inch, based on the physical
screen size.
px — Pixel. Corresponds to actual pixels on the screen. Using this unit is not
recommended, as your UI may not render correctly on devices with a different
screen resolution.

推荐使用dp作为单位,有助于在不同的屏幕密度上将UI显示在正确的位置上,因为dp会根据屏幕dpi不同而调节,故在不同的屏幕上表现良好。这里贴出来如何转换dp和px:
The formula for converting dp to px (pixels) is as follows:
Actual pixels = dp * (dpi / 160), where dpi is either 120, 160, 240, or 320.
Therefore, in the case of the Button on a 235 dpi screen, its actual width is 160
* (240/160) = 240 px. When run on the 180 dpi emulator (regarded as a 160 dpi
device), its actual pixel is now 160 * (160/160) = 160 px. In this case, one dp is
equivalent to one px.
(2)控件走向。垂直or水平。
在LinearLayout中,控件排布是由android:orientation=""来控制的,默认是vertical(水平),也可以设置成horizontal(垂直)。贴两个对比图:
<?xml version=”1.0” encoding=”utf-8”?>
<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”
android:layout_width=”fill_parent”
android:layout_height=”fill_parent”
android:orientation=”vertical” >
<TextView
android:layout_width=”100dp”
android:layout_height=”wrap_content”
android:text=”@string/hello” />
<Button
android:layout_width=”160dp”
android:layout_height=”wrap_content”
android:text=”Button”
android:onClick=”onClick” />
</LinearLayout>
(图左)。
<?xml version=”1.0” encoding=”utf-8”?>
<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”
android:layout_width=”fill_parent”
android:layout_height=”fill_parent”
android:orientation=”horizontal” >
<TextView
android:layout_width=”100dp”
android:layout_height=”wrap_content”
android:text=”@string/hello” />
<Button
android:layout_width=”160dp”
android:layout_height=”wrap_content”
android:text=”Button”
android:onClick=”onClick” />
</LinearLayout>
(图右)。



(3)在LinearLayout中,可以望子组件中添加layout_weight和layout_gravity 属性。代码:

--
<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”
android:layout_width=”fill_parent”
android:layout_height=”fill_parent”
android:orientation=”vertical” >
<Button
android:layout_width=”160dp”
android:layout_height=”wrap_content”
android:text=”Button”
android:layout_gravity=”left”
android:layout_weight=”1” />
<Button
android:layout_width=”160dp”
android:layout_height=”wrap_content”
android:text=”Button”
android:layout_gravity=”center”
android:layout_weight=”2” />
<Button
android:layout_width=”160dp”
android:layout_height=”wrap_content”
android:text=”Button”
android:layout_gravity=”right”
android:layout_weight=”3” />
</LinearLayout>
layout_weight决定了这几个控件分布屏幕垂直方向的高度,分别是1/(1+2+3)*100%,2/(1+2+3)*100%,3/(1+2+3)*100%。layout_gravity决定了每个控件在屏幕上的排布位置,贴个图:
由于是垂直排布,故每个button占据一行。每一个的位置在每行中都在layout_gravity决定。那如果排布是水平的,则如下:

3.AbsoluteLayout

--允许用绝对位置来控制组件的位置。例如:
<AbsoluteLayout
android:layout_width=”fill_parent”
android:layout_height=”fill_parent”
xmlns:android=”http://schemas.android.com/apk/res/android” >
<Button
android:layout_width=”188dp”
android:layout_height=”wrap_content”
android:text=”Button”
android:layout_x=”126px”
android:layout_y=”361px” />
<Button
android:layout_width=”113dp”
android:layout_height=”wrap_content”
android:text=”Button”
android:layout_x=”12px”
android:layout_y=”361px” />
</AbsoluteLayout>
例子中每个控件都用layout_x和layout_y来定义控件(以左上角为准)。不过在不同的屏幕上,这个布局可能会导致控件重叠等不愉快的现象,不建议使用。

4.TableLayout

-- 将组件用row和column来控制,用<TableRow>元素来指定每一行的组件。每一行可以添加多个组件,每个放入的组件都看作一个单元格,而列的宽度由最大宽度的控件决定。
<TableLayout
xmlns:android=”http://schemas.android.com/apk/res/android”
android:layout_height=”fill_parent”
android:layout_width=”fill_parent” >
<TableRow>
<TextView
android:text=”User Name:”
android:width =”120dp”
/>
<EditText
android:id=”@+id/txtUserName”
android:width=”200dp” />
</TableRow>
<TableRow>
<TextView
android:text=”Password:”
/>
<EditText
android:id=”@+id/txtPassword”
android:password=”true”
/>
</TableRow>
<TableRow>
<TextView />
<CheckBox android:id=”@+id/chkRememberPassword”
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:text=”Remember Password”
/>
</TableRow>
<TableRow>
<Button
android:id=”@+id/buttonSignIn”
android:text=”Log In” />
</TableRow>
</TableLayout>
如图:

5.RelativeLayout

--将views以相关联的方法来排布。如下:
<?xml version=”1.0” encoding=”utf-8”?>
<RelativeLayout
android:id=”@+id/RLayout”
android:layout_width=”fill_parent”
android:layout_height=”fill_parent”
xmlns:android=”http://schemas.android.com/apk/res/android” >
<TextView
android:id=”@+id/lblComments”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”Comments”
android:layout_alignParentTop=”true”
android:layout_alignParentLeft=”true” />
<EditText
android:id=”@+id/txtComments”
android:layout_width=”fill_parent”
android:layout_height=”170px”
android:textSize=”18sp”
android:layout_alignLeft=”@+id/lblComments”
android:layout_below=”@+id/lblComments”
android:layout_centerHorizontal=”true” />
<Button
android:id=”@+id/btnSave”
android:layout_width=”125px”
android:layout_height=”wrap_content”
android:text=”Save”
android:layout_below=”@+id/txtComments”
android:layout_alignRight=”@+id/txtComments” />
<Button
android:id=”@+id/btnCancel”
android:layout_width=”124px”
android:layout_height=”wrap_content”
android:text=”Cancel”
android:layout_below=”@+id/txtComments”
android:layout_alignLeft=”@+id/txtComments” />
</RelativeLayout>
在RelativeLayout中,每个子控件都能用属性来控制其对于其他控件的相对位置。
layout_alignParentTop
layout_alignParentLeft
layout_alignLeft
layout_alignRight
layout_below
  layout_centerHorizontal
以上这些属性的值都是参考控件的ID,于是指定了这些属性的控件就会以该ID控件为基准来排布。如下:

6.FrameLayout

--framelayout常用来作为占位符,为以后在其他layout中添加图片或者其他控件占据空间,而动态添加的控件总是位于framelayout的左上角,如下代码:
<?xml version=”1.0” encoding=”utf-8”?>
<RelativeLayout
android:id=”@+id/RLayout”
android:layout_width=”fill_parent”
android:layout_height=”fill_parent”
xmlns:android=”http://schemas.android.com/apk/res/android” >
<TextView
android:id=”@+id/lblComments”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”Hello, Android!”
android:layout_alignParentTop=”true”
android:layout_alignParentLeft=”true” />
<FrameLayout
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_alignLeft=”@+id/lblComments”
android:layout_below=”@+id/lblComments”
android:layout_centerHorizontal=”true” >
<ImageView
android:src = “@drawable/droid”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content” />
</FrameLayout>
</RelativeLayout>
其中framelayout镶嵌在一个RelativeLayout中
如果在framelayout中再添加任何其他组件,其都会位于左上角(于安卓机器人重叠)。可以往framelayout中添加多个views,不过新添加的view总会在旧添加的view之上,就如栈一样。

7.ScrollView

--允许用户添加多个views,通过滚动的方式来使窗体可以占据多余屏幕的空间。而ScrollView只能包含一个view或者viewGroup,通常使用的是LinearLayout。代码:
<ScrollView
android:layout_width=”fill_parent”
android:layout_height=”fill_parent”
xmlns:android=”http://schemas.android.com/apk/res/android” >
<LinearLayout
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:orientation=”vertical” >
<Button
android:id=”@+id/button1”
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:text=”Button 1” />
<Button
android:id=”@+id/button2”
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:text=”Button 2” />
<Button
android:id=”@+id/button3”
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:text=”Button 3” />
<EditText
android:id=”@+id/txt”
android:layout_width=”fill_parent”
android:layout_height=”600dp” />
<Button
android:id=”@+id/button4”
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:text=”Button 4” />
<Button
android:id=”@+id/button5”
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:text=”Button 5” />
</LinearLayout>
</ScrollView>
这里向ScrollView里面的LinearLayout添加多个button和textView(600dp)。于是用户就可以上下滚动来,但是由于textview是自动获得关注的,所以需要将关注点返回到整个LinearLayout上,于是添加了:
<LinearLayout
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:orientation=”vertical”
android:focusable=”true”
android:focusableInTouchMode=”true” >
这样就可以是整个LinearLayout都能看见。



8.适应不同的orientation切换。

--注意当手机orientation切换的时候不同布局的改变。
当手机的orientation转变的时候,Activity的onCreate方法会自动调用。也就是说,在切换orientation的时候,项目的主活动会被销毁再重建。
当orientation切换的时候,如果还是沿用切换前的UI设计的话,可能会在另一种orientation中变得不合适。
总而言之,当orientation转变的时候,掌握两点:
(1)Anchoring(即将UI控件对应于屏幕的四个角。),当orientation转变发生时,控件就会自动靠近屏幕的边,而不会导致浪费很多空间。注意使用一下属性:
layout_alignParentLeft
layout_alignParentRight
layout_alignParentTop
layout_alignParentBottom
layout_centerVertical
layout_centerHorizontal
譬如让一个view放在屏幕的左上方,就设置layout_alignParentLeft和layout_alignParentTop都为true,这样这个view就会别设置在左上角,无论是那种orientation。
注意当
layout_centerVertical
layout_centerHorizontal都设置为true的时候,控件位于垂直的中间和水平的中间,也就是正中。
(2)resizing N repositioning,当然,从新定位各个控件,为两种orientation都设置一个UI那是最好的办法了。
可以为一个活动设置两个xml文件--为两种orientation分别设置UI。当发生orientation转换的时候再按需要分别载入两种UI界面即可。
注意当orientation切换的时候,由于活动先销毁再创建,所以输入且未保存的数据会丢失,注意做好保存。而且当orientation切换时,onPause函数首先被调用,故应该在这个方法中保存当前未保存的信息。
还要注意的是,仅当有ID(设置了android:id)的控件的信息才会自动被保存,当活动被销毁的时候,这些有id的控件的信息会自动的保存和复原当活动再次被创建的时候。
(3)在活动状态改变时保存活动信息。
当活动被recreate的时候,会触动两个方法:
onPause()--一定会触动,当活动被销毁或者移到后台的时候。
onSaveInstanceState()--像上面一样,但是当用户按下back按键的时候这个方法不会被执行(
注意销毁可以是系统内部实现的,不一定是按下back按键,而按下back按键的时候是将整个活动从stack中除去)。
所以,要保存信息,都是在onPause方法中实现,从中可以用database或者文件存储等方法。但如果仅仅想要保存当前的活动状态以便于等下再恢复,那就实现onSaveInstanceState(),因为它提供一个bundle参数可以让你用这个参数来保存当前活动状态。
@Override
public void onSaveInstanceState(Bundle outState) {
//---save whatever you need to persist---
outState.putString(“ID”, “1234567890”);
super.onSaveInstanceState(outState);
}

当一个活动被创建的时候,onCreate方法当然是第一个进行的,而紧接着就会调用onRestoreInstanceState()方法,可以通过bundle对象让你获取之前在onSaveInstanceState()方法中保存的活动状态。
@ Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
//---retrieve the information persisted earlier---
String ID = savedInstanceState.getString(“ID”);
}
注意这种方法仅可以用来存储简单的数据,如果数据再复杂一点的话,就不能了。为此,可以用
onRetainNonConfigurationInstance(),这个方法会在configuration change的时候保存信息。只需要将信息都放在同一个类对象中即可:
@Override
public Object onRetainNonConfigurationInstance() {
//---save whatever you want here; it takes in an Object type---
return(“Some text to preserve”);
}
注意方法中可以用任何object类型的对象来返回,从中提取数据,可以用getLastNonConfigurationInstance()方法:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.d(“StateInfo”, “onCreate”);
String str = (String) getLastNonConfigurationInstance();
}
这两个方法配合起来使用可以很好的暂时保存信息。
(4)检测orientation转变。
--可以用windowManager来检测屏幕的改变。如下代码:
import android.view.Display;
import android.view.WindowManager;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//---get the current display info---
WindowManager wm = getWindowManager();
Display d = wm.getDefaultDisplay();
if (d.getWidth() > d.getHeight()) {
//---landscape mode---
Log.d(“Orientation”, “Landscape mode”);
}
else {
//---portrait mode---
Log.d(“Orientation”, “Portrait mode”);
}
}

getDefaultDIsplay方法返回了一个Display对象,通过获取它的高度和宽度来决定屏幕是在那种状态中。这个方法可以在主活动的onCreate中,判断要载入那个ui界面。
(5)控制活动的orientation。
--可以通过代码来指定当某活动开始时候屏幕的orientation,代码如下:
import android.content.pm.ActivityInfo;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//---change to landscape mode---
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
setRequestOrientation()可以接受一个ActivityInfo来改变屏幕的orientation。
当然,除了以上的方法之外,还可以修改Manifest文件中某个活动的标签,加上android:screenOrientation=“landscape”(或者protrait)来决定当这个活动进行的时候应该用那种Orientation。如下:
<activity
android:label=”@string/app_name”
android:name=”.OrientationsActivity”
android:screenOrientation=”landscape” >
<intent-filter >
<action android:name=”android.intent.action.MAIN” />
<category android:name=”android.intent.category.LAUNCHER” />
</intent-filter>
</activity>
这里指定了活动的Orientation,所以当屏幕的Orientation发生改变的时候,onCreate方法将不会再被嗲用。

总结:当Orientation改变的时候,onCreate会被调用,可以用onRestoreInstanceState()来保存状态信息,而且用getLastNonConfigurationInstance()来读取。除此之外,可以用windowmanager来检测屏幕的Orientation,并在onCreate方法中作相应判断,决定载入哪个ui界面。最后,可以为某个活动指定其Orientation,并不允许改变。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值