一、 Android Layout
在一个Android应用程序中,用户界面通过View和ViewGroup对象构建。Android中有很多种View和ViewGroup,他们都继承自View类。View对象是Android平台上表示用户界面的基本单元。Android中的UI设计采用XML文件,XML含大量的内嵌标签,对对象属性和行为作出定义。
UI 布局共有五类:
线性布局 - Linear Layout: 派生自ViewGroup, 控件按顺序排列成一行或一列
相对布局 - Relative Layout:派生自ViewGroup, 控件根据父容器或其他控件的相对位置进行摆放的布局
表格布局 - Table Layout:派生自LinearLayout,显示表格
绝对布局 - AbsoluteLayout:派生自ViewGroup, 对内嵌的控件指定位置摆放(已在API 3中弃用)
框架布局 – FrameLayout:派生自ViewGroup, 最简单的一个布局,可以说成是层布局方式。后续元素,将覆盖之前的元素。
其中LinearLayout和Relative Layout使用最多。
二、重要属性
android:id: 控件ID,新增ID:"@+id/identity", 已定义:"@id"
1. Linear Layout
android:orientation: 线性布局方向, vertical:垂直, horizontal:水平
android:height:高度,fill_parent/match_parent:填充父器,wrap_content:内容长度,固件定长度:如50dp
android:width:宽度,值同上
android:layout_gravity:控件相对于父容器的显示的位置,left/right/center/top/bottom: 左、右、居中、上、下对齐
android:gravity:控件内容相对于控件显示的位置,值同上
android:layout_weight: 权重,布局内的控件,在高度上(垂直方式)/宽度(水平方式)上可依据权重来计算控作所占的空间大小,此时高度和宽度应设置为"0dp"
android:paddingLeft/Right/Top/Bottom:内边距,控件内容与控件边缘的边距
android:layout_marginLeft/Right/Top/Bottom:外边距,控作与父容器的边距
2. RelativeLayout
第一类:属性值为true或false
android:layout_centerHrizontal 水平居中
android:layout_centerVertical 垂直居中
android:layout_centerInparent 相对于父元素完全居中
android:layout_alignParentBottom 贴紧父元素的下边缘
android:layout_alignParentLeft 贴紧父元素的左边缘
android:layout_alignParentRight 贴紧父元素的右边缘
android:layout_alignParentTop 贴紧父元素的上边缘
android:layout_alignWithParentIfMissing 如果对应的兄弟元素找不到的话就以父元素做参照物
第二类:属性值必须为id的引用名“@id/id-name”
android:layout_below 在某元素的下方
android:layout_above 在某元素的的上方
android:layout_toLeftOf 在某元素的左边
android:layout_toRightOf 在某元素的右边
android:layout_alignTop 本元素的上边缘和某元素的的上边缘对齐
android:layout_alignLeft 本元素的左边缘和某元素的的左边缘对齐
android:layout_alignBottom 本元素的下边缘和某元素的的下边缘对齐
android:layout_alignRight 本元素的右边缘和某元素的的右边缘对齐
第三类:属性值为具体的像素值,如30dip,40px
android:layout_marginBottom 离某元素底边缘的距离
android:layout_marginLeft 离某元素左边缘的距离
android:layout_marginRight 离某元素右边缘的距离
android:layout_marginTop 离某元素上边缘的距离
3. Table Layout
TableLayout和我们平时在网页上见到的Table有所不同,TableLayout没有边框的,它是由多个TableRow对象组成,每个TableRow可以有0个或多个单元格,每个单元格就是一个View。这些TableRow,单元格不能设置layout_width,宽度默认是fill_parent的,只有高度layout_height可以自定义,默认是wrap_content。
4. FrameLayout
为了在一个容器中某一位置显示单一控件。
android:foreground:设置该帧布局容器的前景图像
android:foregroundGravity:设置前景图像显示的位置
三、举例
使用Action Bar的TAB导航,新建时最后一步,Navigation Type选择“Fixed Buttons + Swipe", 分别显示LinearLayout, RelativeLayout和FrameLayout的Fragment。
主界面的布局,只有一个viewPager, activity_main.xml:
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" />
LinearLayout的布局,显示Linus的图片简介,linear_layout.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<!-- 定义姓名 -->
<TextView
android:id="@+id/full_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="12pt"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:text="Linus Benedict Torvalds" />
<!-- 水平布局显示照片和基本信息 -->
<!-- weight用于图片和基本信息所占宽度的比重 -->
<LinearLayout
android:orientation="horizontal"
android:layout_marginBottom="5dp"
android:layout_weight="5"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:id="@+id/photo"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="fill_vertical"
android:layout_marginLeft="15dp"
android:layout_marginTop="10dp"
android:layout_weight="2"
android:src="@drawable/linus_torvalds" />
<TableLayout
android:layout_weight="3"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center"
android:stretchColumns="0,1,2,3,4"
android:layout_marginLeft="2dp"
android:layout_marginTop="10dp">
<TableRow
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Name:" />
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Linus Torvalds" />
</TableRow>
<TableRow
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Gender:" />
<TextView
android:id="@+id/gender"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Male" />
</TableRow>
<TableRow
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Age:" />
<TextView
android:id="@+id/age"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="45" />
</TableRow>
<TableRow
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Birthday:" />
<TextView
android:id="@+id/birthday"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="December 28, 1969" />
</TableRow>
<TableRow
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Location:" />
<TextView
android:id="@+id/location"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="United States" />
</TableRow>
</TableLayout>
</LinearLayout>
</LinearLayout>
RelativeLayout模拟WIFI通讯,relative_layout.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="@+id/prompt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginTop="10dp"
android:text="请输入IP地址和端口号:" />
<EditText
android:id="@+id/ip_addr"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@id/prompt"
android:layout_below="@id/prompt"
android:hint="ip address"
android:inputType="text"
android:singleLine="true"
android:ems="10" >
<requestFocus />
</EditText>
<EditText
android:id="@+id/ip_port"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginRight="5dp"
android:layout_toRightOf="@+id/ip_addr"
android:layout_alignBottom="@+id/ip_addr"
android:hint=" port "
android:singleLine="true"
android:inputType="number"
android:ems="5">
</EditText>
<Button
android:id="@+id/connect"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignRight="@+id/ip_port"
android:layout_below="@+id/ip_port"
android:text="Connect" />
<Button
android:id="@+id/cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/connect"
android:layout_toLeftOf="@+id/connect"
android:text="Cancel" />
<!-- 在正中心位置显示进度条 -->
<ProgressBar
android:id="@+id/progress"
style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
/>
<TextView
android:id="@+id/status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/progress"
android:layout_centerHorizontal="true"
android:textSize="12pt"
android:text="status" />
</RelativeLayout>
FrameLayout显示两张图片的重叠, frame_layout.xml:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:id="@+id/background"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/background" />
<!-- 小鸟将会覆盖背景显示 -->
<ImageView
android:id="@+id/bird"
android:layout_width="121dp"
android:layout_height="86dp"
android:layout_gravity="center"
android:src="@drawable/bird" />
</FrameLayout>
main activity,显示TAB,MainActivity.java:
package com.lulin;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import android.app.ActionBar;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.Menu;
public class MainActivity extends FragmentActivity implements
ActionBar.TabListener {
/**
* The {@link android.support.v4.view.PagerAdapter} that will provide
* fragments for each of the sections. We use a
* {@link android.support.v4.app.FragmentPagerAdapter} derivative, which
* will keep every loaded fragment in memory. If this becomes too memory
* intensive, it may be best to switch to a
* {@link android.support.v4.app.FragmentStatePagerAdapter}.
*/
SectionsPagerAdapter mSectionsPagerAdapter;
List<Fragment> mFragments = new ArrayList<Fragment>();
List<String> mTitles = new ArrayList<String>();
/**
* The {@link ViewPager} that will host the section contents.
*/
ViewPager mViewPager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTitles.add(new String("Linear"));
mTitles.add(new String("Relative"));
mTitles.add(new String("Frame"));
mFragments.add(new LinearFragment());
mFragments.add(new RelativeFragment());
mFragments.add(new FrameFragment());
// Set up the action bar.
final ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Create the adapter that will return a fragment for each of the three
// primary sections of the app.
mSectionsPagerAdapter = new SectionsPagerAdapter(
getSupportFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
// When swiping between different sections, select the corresponding
// tab. We can also use ActionBar.Tab#select() to do this if we have
// a reference to the Tab.
mViewPager
.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
actionBar.setSelectedNavigationItem(position);
}
});
// For each of the sections in the app, add a tab to the action bar.
for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
// Create a tab with text corresponding to the page title defined by
// the adapter. Also specify this Activity object, which implements
// the TabListener interface, as the callback (listener) for when
// this tab is selected.
actionBar.addTab(actionBar.newTab()
.setText(mSectionsPagerAdapter.getPageTitle(i))
.setTabListener(this));
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public void onTabSelected(ActionBar.Tab tab,
FragmentTransaction fragmentTransaction) {
// When the given tab is selected, switch to the corresponding page in
// the ViewPager.
mViewPager.setCurrentItem(tab.getPosition());
}
@Override
public void onTabUnselected(ActionBar.Tab tab,
FragmentTransaction fragmentTransaction) {
}
@Override
public void onTabReselected(ActionBar.Tab tab,
FragmentTransaction fragmentTransaction) {
}
/**
* A {@link FragmentPagerAdapter} that returns a fragment corresponding to
* one of the sections/tabs/pages.
*/
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
return mFragments.get(position);
}
@Override
public int getCount() {
// Show 3 total pages.
return mFragments.size();
}
@Override
public CharSequence getPageTitle(int position) {
return mTitles.get(position);
}
}
}
package com.lulin;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class LinearFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
View view = inflater.inflate(R.layout.linear_layout, null);
return view;
}
}
RelativeFragment.java:
package com.lulin;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class RelativeFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.relative_layout, null);
return view;
}
}
FrameFragment.java:
package com.lulin;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class FrameFragment extends Fragment{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
View view = inflater.inflate(R.layout.frame_layout, null);
return view;
}
}
效果: