Android UI布局
原文地址:Android UI布局作者:尼采的鹅毛笔
android.view.View 是widget基类
android.view.Viewgroup 是布局的基类
菜单 Menu、MenuItem
文本 TextView
输入框 EditText
输入法 InputMethod
活动方法 MovementMethod
按钮 Button
单选按钮 RadioButton
复选框 Checkbox
滚动视图ScrollView
ListView
元件名稱説明
FrameLayout 單一物件的容器
AbsoluteLayout 以絕對座標排版的容器
LinearLayout 線性(水平或垂直) 排版的容器
RelativeLayout 以相對座標(相對於父元件或兄弟元件) 排版的容器
TableLayout 以表格方式排版的容器
---------------------------------
Android UI布局
1、Activity
Android 应用程序基本功能单元
本身没有任何屏幕存在
2、View 和Viewgroup
表示在Android 平台上的基本用户界面单元
3、Views
android.view.View
? 为指定的屏幕矩形区域存储布局和内容
? 处理尺寸和布局,绘制,焦点改变,翻屏,按键、手势
? widget基类
文本 TextView
输入框 EditText
输入法 InputMethod
活动方法 MovementMethod
按钮 Button
单选按钮 RadioButton
复选框 Checkbox
滚动视图ScrollView
4、Viewgroups
android.view.Viewgroup
? 包含并管理下级系列的Views和其他Viewgroup
? 布局的基类
5、UI树状结构
Android中的Activity
? 定义使用一个view和iewgroup的树状节点
setContentView()方法
? 被Activity调用来把树状节点连接到屏幕渲染
6、LayoutParams (布局参数)
每一个viewgroup类使用一个继承于ViewGroup.LayoutParams的嵌套类
? 包含定义了子节点View的尺寸和位置的属性类型
7、普通布局对象
1 FrameLayout
最简单的布局对象
在屏幕上故意保留的空白空间,你可以之后填充一个单独的对象
例如:一个你要更换的图片
所有子元素都钉到屏幕的左上角
不能为子元素指定位置
2 LinearLayout
在一个方向上(垂直或水平)对齐所有子元
? 所有子元素一个跟一个地堆放
一个垂直列表每行将只有一个子元素(无论它们有多宽)
一个水平列表只是一列的高度(最高子元素的高度来填充)
3 AbsoluteLayout
使子元素能够指明确切的X / Y坐标显示在屏幕上
? (0,0)是左上角
? 当你下移或右移时,坐标值增加
允许元素重叠(但是不推荐)
注意:
? 一般建议不使用AbsoluteLayout除非你有很好的理由来使用它
? 因为它相当严格并且在不同的设备显示中不能很好地工作
4 RelativeLayout
让子元素指定它们相对于其他元素的位置(通过ID来指定)或相对于父布局对象
5 AndroidManifest.xml中修改程序布局的Theme主题
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="zyf.GridViewTest"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon"
android:theme="@android:style/Theme.Light"
android:label="@string/app_name">
<activity android:name=".GridViewTest"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category
android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-sdk android:minSdkVersion="2" />
</manifest>
----------------------------------------------------------
android样式和主题
android中的样式和CSS样式作用相似,都是用于为界面元素定义显示风格,它是一个包含一个或者多个view控件属性的集合。如:需要定义字体的颜色和大小。
在CSS中是这样定义的:
<style>
.itcast{COLOR:#0000CC;font-size:18px;}
</style>
可以像这样使用上面的css样式:<div class="itcast">传智播客</div>
在Android中可以这样定义样式:
在res/values/styles.xml文件中添加以下内容
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name=“itcast”> <!-- 为样式定义一个全局唯一的名字-->
<item name="android:textSize">18px</item> <!-- name属性为样式要用在的View控件持有的属性 -->
<item name="android:textColor">#0000CC</item>
</style>
</resources>
在layout文件中可以像下面这样使用上面的android样式:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" ....>
<TextView style="@style/itcast"
..... />
</LinearLayout>
<style>元素中有一个parent属性。这个属性可以让当前样式继承一个父样式,当前样式可以继承到父样式的值。当然,如果父样式的值不符合你的需求,你也可以对它进行修改,如下:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="itcast">
<item name="android:textSize">18px</item> <!-- name属性为样式要用在的View控件持有的属性 -->
<item name="android:textColor">#0000CC</item>
</style>
<style name="subitcast" parent="@style/itcast">
<item name="android:textColor">#FF0000</item>
</style>
</resources>
android中主题也是用于为应用定义显示风格,它的定义和样式的定义相同,如下:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name=“itcastTheme">
<item name=“android:windowNoTitle”>true</item> <!– 没标题 ?
<item name=“android:windowFullscreen”>?android:windowNoTitle</item> <!– 全屏显示 ?
</style>
</resources>
上面“?android:windowNoTitle”中的问号用于引用在当前主题中定义过的资源的值。下面代码显示在AndroidManifest.xml中如何为应用设置上面定义的主题:
<application android:icon="@drawable/icon" android:label="@string/app_name"
android:theme="@style/itcastTheme">
......
</application>
除了可以在AndroidManifest.xml中设置主题,同样也可以在代码中设置主题,如下:
setTheme(R.style.itcastTheme);
尽管在定义上,样式和主题基本相同,但是它们使用的地方不同。样式用在单独的View,如:EditText、TextView等;主题通过AndroidManifest.xml中的<application>和<activity>用在整个应用或者某个 Activity,主题对整个应用或某个Activity存在全局性影响。如果一个应用使用了主题,同时应用下的view也使用了样式,那么当主题与样式属性发生冲突时,样式的优先级高于主题。
另外android系统也定义了一些主题,例如:<activity android:theme=“@android:style/Theme.Dialog”>,该主题可以让Activity看起来像一个对话框,如果需要查阅这些主题,可以在文档的reference?android-->R.style 中查看。
--------------------------------------------------
Android中的显示单位
ox (pixels)像素
一般HVGA代表320x480像素,这个用的比较多。
dip或dp (device independent pixels)设备独立像素
这个和设备硬件有关,一般为了支持WVGA、HVGA和QVGA 推荐使用这个,不依赖像素。
sp (scaled pixels — best for text size)比例像素
主要处理字体的大小,可以根据系统的字体自适应。
下面几个不太常用:
in (inches)英寸
mm (millimeters)毫米
pt (points)点,1/72英寸
为了适应不同分辨率,不同的像素密度,推荐使用dip ,文字使用sp。
----------------------------------------------------------
1 单选框(RadioButton)
要完成单选框显示,我们需要使用到RadioGroup和RadioButton(单选框),RadioGroup用于对单选框进行分组,相同组内的单选框只有一个单选框能被选中。(例子代码请见下方备注栏)
RadioGroup.check(R.id.dotNet);将id名为dotNet的单选框设置成选中状态。
(RadioButton) findViewById(radioGroup.getCheckedRadioButtonId());//获取被选中的单选框。
RadioButton.getText();//获取单选框的值
调用setOnCheckedChangeListener()方法,处理单选框被选择事件,把RadioGroup.OnCheckedChangeListener实例作为参数传入
界面设计:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<RadioGroup android:id="@+id/radioGroup"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<RadioButton android:id="@+id/java"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="java" />
<RadioButton android:id="@+id/dotNet"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="dotNet" />
<RadioButton android:id="@+id/php"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="PHP" />
</RadioGroup>
</LinearLayout>
处理程序:
public void onCreate(Bundle savedInstanceState) {
......
RadioGroup radioGroup = (RadioGroup) findViewById(R.id.radioGroup);
radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
public void onCheckedChanged(RadioGroup group, int checkedId) {
RadioButton radioButton = (RadioButton) findViewById(checkedId);
Log.i(TAG, String.valueOf(radioButton.getText()));
}
});
}
2 多选框(CheckBox)
每个多选框都是独立的,可以通过迭代所有多选框,然后根据其状态是否被选中再获取其值。
CheckBox.setChecked(true);//设置成选中状态。
CheckBox.getText();//获取多选框的值
调用setOnCheckedChangeListener()方法,处理多选框被选择事件,把CompoundButton.OnCheckedChangeListener实例作为参数传入
界面设计:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="fill_parent">
<CheckBox android:id="@+id/checkboxjava"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="java" />
<CheckBox android:id="@+id/checkboxdotNet"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="dotNet" />
<CheckBox android:id="@+id/checkboxphp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="PHP" />
<Button android:id="@+id/checkboxButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="获取值" />
</LinearLayout>
代码处理:
public class CheckBoxActivity extends Activity {
private static final String TAG = "CheckBoxActivity";
private List<CheckBox> checkboxs = new ArrayList<CheckBox>();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.checkbox);
checkboxs.add((CheckBox) findViewById(R.id.checkboxdotNet));
checkboxs.add((CheckBox) findViewById(R.id.checkboxjava));
checkboxs.add((CheckBox) findViewById(R.id.checkboxphp));
checkboxs.get(1).setChecked(true);//设置成选中状态
for(CheckBox box : checkboxs){
box.setOnCheckedChangeListener(listener);
}
Button button = (Button)findViewById(R.id.checkboxButton);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
List<String> values = new ArrayList<String>();
for(CheckBox box : checkboxs){
if(box.isChecked()){
values.add(box.getText().toString());
}
}
Toast.makeText(CheckBoxActivity.this, values.toString(), 1).show();
}
});
}
CompoundButton.OnCheckedChangeListener listener = new CompoundButton.OnCheckedChangeListener() { @Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
CheckBox checkBox = (CheckBox) buttonView;
Log.i(TAG, "isChecked="+ isChecked +",value="+ checkBox.getText());//输出单选框的值
}
};
}
3 下拉列表框(Spinner)
Spinner.getItemAtPosition(Spinner.getSelectedItemPosition());获取下拉列表框的值
调用setOnItemSelectedListener()方法,处理下拉列表框被选择事件,把AdapterView.OnItemSelectedListener实例作为参数传入
界面设计:
<?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="wrap_content">
<Spinner android:id="@+id/spinner"
android:layout_height="wrap_content"
android:layout_width="fill_parent"/>
</LinearLayout>
代码处理:
public class SpinnerActivity extends Activity {
private static final String TAG = "SpinnerActivity";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.spinner);
//第二个参数为下拉列表框每一项的界面样式,该界面样式由Android系统提供,当然您也可以自定义
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
adapter.add("java");
adapter.add("dotNet");
adapter.add("php");
Spinner spinner = (Spinner) findViewById(R.id.spinner);
spinner.setAdapter(adapter);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) {
Spinner spinner = (Spinner)adapterView;
String itemContent = (String)adapterView.getItemAtPosition(position);
}
@Override
public void onNothingSelected(AdapterView<?> view) {
Log.i(TAG, view.getClass().getName());
}
});
}
}
4 下拉列表框—采用javabean作为Adapter元素
很多时候显示在下拉列表框的值并不是希望得到的值,如果要做一个联系人下拉列表框,列表框列出的是联系人的姓名,因为姓名有可能相同,所以我们希望得到的值应该为该联系人的id,要实现这种需求我们需要自定义Adapter,当然自定义Adapter需要我们编写一小段代码,如果我们不想编写Adapter,又能实现我们的需求,那是最好不过的了。通过观察ArrayAdapter中getView(int position, View convertView, ViewGroup parent)的内部代码发现,如果为ArrayAdapter指定的实际泛型参数类型没有实现CharSequence(字符串)接口,将会调用该类型对象的toString()向下拉列表框输出显示值。利用这个特点我们可以重写javaBean的toString()向下拉列表框提供显示值。
界面设计:
<?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="wrap_content">
<Spinner android:id="@+id/spinner"
android:layout_height="wrap_content"
android:layout_width="fill_parent"/>
</LinearLayout>
代码处理:
public class SpinnerActivity extends Activity {
private static final String TAG = "SpinnerActivity";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.spinner);
ArrayAdapter<Person> adapter = new ArrayAdapter<Person>(this, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
adapter.add(new Person(12, "李明"));
adapter.add(new Person(100, "李明"));
adapter.add(new Person(62, "张天"));
Spinner spinner = (Spinner) findViewById(R.id.spinner);
spinner.setAdapter(adapter);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) {
Spinner spinner = (Spinner)adapterView;
Person person = (Person)adapterView.getItemAtPosition(position);
}
@Override
public void onNothingSelected(AdapterView<?> view) {
Log.i(TAG, view.getClass().getName());
}
});
}
}
Person.java:
public class Person {
private Integer id;
private String name;
public Person(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
}
5 下拉列表框--自定义选项界面样式
Spinner.getItemAtPosition(Spinner.getSelectedItemPosition());获取下拉列表框的值
调用setOnItemSelectedListener()方法,处理下拉列表框被选择事件,把AdapterView.OnItemSelectedListener实例作为参数传入
主界面设计:
<?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="wrap_content">
<Spinner android:id="@+id/spinner"
android:layout_height="wrap_content"
android:layout_width="fill_parent"/>
</LinearLayout>
下拉列表框每一项的界面样式:stylespinner.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/contentTextView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#F4FDFF"
/>
代码处理:
public class SpinnerActivity extends Activity {
private static final String TAG = "SpinnerActivity";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.spinner);
//第二个参数为layout文件在R文件的id,第三个参数为TextView在layout文件的id
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.stylespinner, R.id.contentTextView);
adapter.add("java");
adapter.add("dotNet");
adapter.add("php");
Spinner spinner = (Spinner) findViewById(R.id.spinner);
spinner.setAdapter(adapter);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) {
Spinner spinner = (Spinner)adapterView;
String itemContent = (String)adapterView.getItemAtPosition(position);
}
@Override
public void onNothingSelected(AdapterView<?> view) {
Log.i(TAG, view.getClass().getName());
}
});
}
}
6 拖动条(SeekBar)
SeekBar.getProgress()获取拖动条当前值
调用setOnSeekBarChangeListener()方法,处理拖动条值变化事件,把SeekBar.OnSeekBarChangeListener实例作为参数传入
主界面设计:
<?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">
<SeekBar
android:id="@+id/seekBar"
android:layout_height="wrap_content"
android:layout_width="fill_parent"/>
<Button android:id="@+id/seekBarButton"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="获取值"
/>
</LinearLayout>
代码处理:
public class SeekBarActivity extends Activity {
private SeekBar seekBar;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.seekbar);
seekBar = (SeekBar) findViewById(R.id.seekBar);
seekBar.setMax(100);//设置最大刻度
seekBar.setProgress(30);//设置当前刻度
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {
Log.v("onProgressChanged()", String.valueOf(progress) + ", " + String.valueOf(fromTouch));
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {//开始拖动
Log.v("onStartTrackingTouch()", String.valueOf(seekBar.getProgress()));
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {//结束拖动
Log.v("onStopTrackingTouch()", String.valueOf(seekBar.getProgress()));
}
});
Button button = (Button)this.findViewById(R.id.seekBarButton);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(SeekBarActivity.this, String.valueOf(seekBar.getProgress()), 1).show();
}
});
}
}
7 菜单(Menu)
重写Activity的onCreateOptionsMenu(Menu menu)方法,该方法用于创建选项菜单,在用户按下手机的“Menu”按钮时就会显示创建好的菜单,在onCreateOptionsMenu(Menu menu)方法内部可以调用Menu.add()方法实现菜单的添加。
重写Activity的onMenuItemSelected()方法,该方法用于处理菜单被选择事件
public class MenuActivity extends Activity {
private static final String TAG = "MenuActivity";
private static final int MENU_ADD = Menu.FIRST;
private static final int MENU_UPDATE = Menu.FIRST + 1;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.menu);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(Menu.NONE, MENU_ADD, Menu.NONE, "添加");
menu.add(Menu.NONE, MENU_UPDATE, Menu.NONE, "更新");
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
switch (item.getItemId()) {
case MENU_ADD:
Log.i(TAG, "add was selected");
return true;
case MENU_UPDATE:
Log.i(TAG, "update was selected");
return true;
default:
return super.onMenuItemSelected(featureId, item);
}
}
}