Android用户界面框架采用MVC(Model-View-Controller)模型,
处理用户输入的控制器(Controller)
显示图像的视图(View)
保存数据和代码的模型(Model)
Android用户界面框架按照"先进先出"的规则从队列中获取时间
单线程用户界面
界面控件
包括定制控件和系统控件
常见的系统控件
TextView,EditText
Button,ImageButton
Checkbox,RadioButton
Spinner
ListView
TabHost
wrap_content表示宽度只能够包含所显示的字符串
fill_content表示宽度将等于父控件的宽度
findViewById()函数能够通过ID引用界面上的任何控件
@+id/RadioGroup01 @标识后面的字符串是ID资源,加号(+)表示需要建立新资源名称,斜杠(/)后面的字符串是新资源的名称
不是新资源,不需要添加加号,要这样表示:
@android:id/RadioGroup01
TextView textView = (TextView)findViewById(R.id.TextView01);
EditText editText = (EditText)findViewById(R.id.EditText01);
textView.setText("用户名:");
editText.setText("Rajan");
注册点击事件
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
textView.setText("Button按钮");
}
});
将多个按钮注册同一个点击事件的监听器上
Button.OnClickListener buttonListener = new Button.OnClickListener(){
@Override
public void onClick(View v) {
switch(v.getId()){
case R.id.Button01:
textView.setText("Button按钮");
return;
case R.id.ImageButton01:
textView.setText("ImageButton按钮");
return;
}
}};
button.setOnClickListener(buttonListener);
imageButton.setOnClickListener(buttonListener);
RadioButton是多选框,如何实现多选选项呢
<RadioGroup android:id="@+id/RadioGroup01"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<RadioButton android:id="@+id/RadioButton01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="RadioButton01" >
</RadioButton>
<RadioButton android:id="@+id/RadioButton02"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="RadioButton02" >
</RadioButton>
</RadioGroup>
Spinner下拉菜单
让数据和组件绑定用到了适配器
Spinner spinner = (Spinner) findViewById(R.id.Spinner01);
List<String> list = new ArrayList<String>();
list .add("Spinner子项1");
list .add("Spinner子项2");
list .add("Spinner子项3");
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, list );
//simple_spinner_dropdown_item是Android内置的浮动菜单的显示方式
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
//adapter.setDropDownViewResource(android.R.layout.simple_spinner_item);
spinner.setAdapter(adapter);
关于组件的设置事件
setText
setAdapter
setOnClickListener
setOnItemClickListener
关于适配器的设置事件
setDropDownViewResource
AdapterView.OnItemClickListener()
ListView 用于垂直显示的列表控件
final TextView textView = (TextView)findViewById(R.id.TextView01);
ListView listView = (ListView)findViewById(R.id.ListView01);
List<String> list = new ArrayList<String>();
list .add("ListView子项1");
list .add("ListView子项2");
list .add("ListView子项3");
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, list );
listView.setAdapter(adapter);
给ListView子项设置点击事件监听器
AdapterView.OnItemClickListener listViewListener = new AdapterView.OnItemClickListener(){
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
String msg = "父View:"+arg0.toString()+"\n"+"子View:"+arg1.toString()+"\n"+"位置:"+String.valueOf(arg2)+",ID:"+String.valueOf(arg3);
textView.setText(msg);
}};
listView.setOnItemClickListener(listViewListener);
}
TabHost
Tab标签页是界面设计中经常使用的界面控件,实现多个分页之间的切换
Inflate将一个layout.xml布局文件变为一个View对象(ui界面)
方式一:
@SuppressWarnings("deprecation")
public class TabDemoActivity extends TabActivity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TabHost tabHost = getTabHost();
LayoutInflater.from(this).inflate(R.layout.tab1, tabHost.getTabContentView(),true);
LayoutInflater.from(this).inflate(R.layout.tab2, tabHost.getTabContentView(),true);
LayoutInflater.from(this).inflate(R.layout.tab3, tabHost.getTabContentView(),true);
tabHost.addTab(tabHost.newTabSpec("TAB1").
setIndicator("线性布局").setContent(R.id.layout01));
tabHost.addTab(tabHost.newTabSpec("TAB2").
setIndicator("绝对布局").setContent(R.id.layout02));
tabHost.addTab(tabHost.newTabSpec("TAB3").
setIndicator("相对布局").setContent(R.id.layout03));
}
}
方式二:
@SuppressWarnings("deprecation")
public class TabDemo2Activity extends TabActivity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TabHost tabHost = getTabHost();
tabHost.addTab(tabHost.newTabSpec("TAB1").
setIndicator("线性布局").setContent(new Intent().setClass(this, Tab1Activity.class)));
tabHost.addTab(tabHost.newTabSpec("TAB2").
setIndicator("绝对布局").setContent(new Intent().setClass(this, Tab2Activity.class)));
tabHost.addTab(tabHost.newTabSpec("TAB3").
setIndicator("相对布局").setContent(new Intent().setClass(this, Tab3Activity.class)));
}
}
同时在xml的设置也要
<TabWidget
android:id="@android:id/tabs"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="5dp" />
在AnroidManifest.xml文件中也要添加
<activity android:name=".Tab1Activity" />
<activity android:name=".Tab2Activity" />
<activity android:name=".Tab3Activity" />
界面布局
- 线性布局
<LinearLayout> </LinearLayout> - 框架布局
最简单的界面布局,存放一个元素的空白空间,子元素的位置只能放置在空白空间的左上角
<FrameLayout> </FrameLayout> 表格布局
表格布局支持嵌套
添加一个表格布局,无需修改布局的属性值,Id属性为TableLayout01、Layout_width、Layout_height属性都为wrap_content
<TableLayout> </TableLayout><TableLayout android:id="@+id/TableLayout01" android:layout_width="fill_parent" android:layout_height="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android"> <TableRow android:id="@+id/TableRow01" android:layout_width="wrap_content" android:layout_height="wrap_content"> <TextView android:id="@+id/label" android:layout_height="wrap_content" android:layout_width="160dip" android:gravity="right" android:text="用户名:" android:padding="3dip" > </TextView> <EditText android:id="@+id/entry" android:layout_height="wrap_content" android:layout_width="160dip" android:padding="3dip" > </EditText> </TableRow> <TableRow android:id="@+id/TableRow02" android:layout_width="wrap_content" android:layout_height="wrap_content"> <Button android:id="@+id/ok" android:layout_height="wrap_content" android:padding="3dip" android:text="确认"> </Button> <Button android:id="@+id/Button02" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="3dip" android:text="取消"> </Button> </TableRow> </TableLayout>
android:padding表示与其他元素的间隔距离
- 相对布局
layout_below 在···的下方
layout_toLeftOf 在···的左边
layout_alignTop 与···在相同的水平位置
<RelativeLayout android:id="@+id/RelativeLayout01"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
<TextView android:id="@+id/label"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:text="用户名:">
</TextView>
<EditText android:id="@+id/entry"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:layout_below="@id/label">
</EditText>
<Button android:id="@+id/cancel"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginLeft="10dip"
android:layout_below="@id/entry"
android:text="取消" >
</Button>
<Button android:id="@+id/ok"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_toLeftOf="@id/cancel"
android:layout_alignTop="@id/cancel"
android:text="确认">
</Button>
</RelativeLayout>
绝对布局
通过指定界面元素的坐标位置,来确定用户界面的整体布局
layout_x
layout_y<AbsoluteLayout android:id="@+id/absolutelayout01" android:layout_width="fill_parent" android:layout_height="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android"> <TextView android:id="@+id/label" android:layout_x="40dip" android:layout_y="40dip" android:layout_height="wrap_content" android:layout_width="wrap_content" android:text="用户名:"> </TextView> <EditText android:id="@+id/entry" android:layout_x="40dip" android:layout_y="60dip" android:layout_height="wrap_content" android:layout_width="150dip"> </EditText> <Button android:id="@+id/ok" android:layout_width="70dip" android:layout_height="wrap_content" android:layout_x="40dip" android:layout_y="120dip" android:text="确认"> </Button> <Button android:id="@+id/cancel" android:layout_width="70dip" android:layout_height="wrap_content" android:layout_x="120dip" android:layout_y="120dip" android:text="取消" > </Button> </AbsoluteLayout>
网格布局
对比css
android:ems
使 TextView 正好有这么多 em 宽,最终的宽度就变成了,传入的ems*行高<GridLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:useDefaultMargins="true" android:columnCount="4" > <TextView android:layout_columnSpan="4" android:layout_gravity="center_horizontal" android:text="这是关于GroidLayout的示例" android:textSize="20dip" /> <TextView android:text="用户名:" android:layout_gravity="right" /> <EditText android:ems="8" android:layout_columnSpan="2"/> <TextView android:text="密码:" android:layout_column="0" android:layout_gravity="right"/> <EditText android:ems="8" android:layout_columnSpan="2" /> <Button android:text="清空输入" android:layout_column="1" android:layout_gravity="fill_horizontal"/> <Button android:text="下一步" android:layout_column="2" android:layout_gravity="fill_horizontal"/> </GridLayout>
菜单
选项菜单
在Android4.0以后选项菜单只出现浮动菜单
Activity初始化先调用onCreateOptionsMenu()函数初始化自身的菜单系统,操纵栏的初始化代码也在其中public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.main_menu, menu);//R.menu.main_menu即main_menu.xml文件 return true; }
onOptionsItemSelected函数在每次用户点击菜单子项时都会被调用
@Override
public boolean onOptionsItemSelected(MenuItem item) {
TextView label = (TextView)findViewById(R.id.label);
switch (item.getItemId()) {
case R.id.main_menu_0:
label.setText("打印,菜单ID:" + item.getItemId());
return true;
case R.id.main_menu_1:
label.setText("新建,菜单ID:" + item.getItemId());
return true;
case R.id.main_menu_2:
label.setText("邮件,菜单ID:" + item.getItemId());
return true;
case R.id.main_menu_3:
label.setText("设置,菜单ID:" + item.getItemId());
return true;
case R.id.main_menu_4:
label.setText("订阅,菜单ID:" + item.getItemId());
return true;
default:
return false;
}
}
除了使用XML文件的菜单资源,还可以在代码中动态生成菜单
- 在代码中定义菜单ID
- 在onCreateOptionsMenu()函数中添加选项菜单,并设置菜单的标题和图标等信息,第一个参数是需要显示的快捷菜单,第二个参数是用户点击的界面元素,第三个参数是所选择界面元素的额外信息
add()函数第一个参数是组id,第二个参数是子项id,每个菜单的唯一标识,第三个参数是菜单子项在选项菜单中的排序顺序,第四个菜单是菜单子项的选项标题
final static int MENU_00 = Menu.FIRST; final static int MENU_01 = Menu.FIRST+1; final static int MENU_02 = Menu.FIRST+2; final static int MENU_03 = Menu.FIRST+3; final static int MENU_04 = Menu.FIRST+4; @Override public boolean onCreateOptionsMenu(Menu menu) { menu.add(0,MENU_00,0,"打印").setIcon(R.drawable.pic0); menu.add(0,MENU_01,1,"新建").setIcon(R.drawable.pic1); menu.add(0,MENU_02,2,"邮件").setIcon(R.drawable.pic2); menu.add(0,MENU_03,3,"设置").setIcon(R.drawable.pic3); menu.add(0,MENU_04,4,"订阅").setIcon(R.drawable.pic4); return true; }
子菜单
也就是二级菜单
用xml文件描述菜单结构<menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/main_menu_0" android:icon="@drawable/pic0" android:title="设置" > <menu> <item android:id="@+id/sub_menu_0_0" android:icon="@drawable/pic4" android:title="打印" /> </menu> </item> <item android:id="@+id/main_menu_1" android:icon="@drawable/pic1" android:title="新建" > <menu> <item android:id="@+id/sub_menu_1_0" android:icon="@drawable/pic2" android:title="邮件" /> <item android:id="@+id/sub_menu_1_1" android:icon="@drawable/pic3" android:title="订阅" /> </menu> </item> </menu>
通过代码实现子菜单
addSubMenu()的四个参数含义
- 组id
- 菜单项的id
- 显示排序
菜单显示标题
final static int MENU_00 = Menu.FIRST; final static int MENU_01 = Menu.FIRST+1; final static int SUB_MENU_00_01 = Menu.FIRST+2; final static int SUB_MENU_01_00 = Menu.FIRST+3; final static int SUB_MENU_01_01 = Menu.FIRST+4; @Override public boolean onCreateOptionsMenu(Menu menu) { SubMenu sub1 = (SubMenu) menu.addSubMenu(0,MENU_00,0,"设置") .setHeaderIcon(R.drawable.pic3); sub1.add(0,SUB_MENU_00_01 ,0,"打印").setIcon(R.drawable.pic0); SubMenu sub2 = (SubMenu) menu.addSubMenu(0,MENU_01,1,"新建") .setHeaderIcon(R.drawable.pic1); sub2.add(0,SUB_MENU_01_00 ,0,"邮件").setIcon(R.drawable.pic2); sub2.add(0,SUB_MENU_01_01 ,0,"订阅").setIcon(R.drawable.pic4); return true; }
- 快捷菜单
onCreateContextMenu() 在快捷菜单中添加菜单子项和子菜单
onContextItemSelected()相应菜单选择事件
重载onCreateContextMenu()函数初始化菜单项,函数参数解释如下:
- 需要显示的快捷菜单
- 用户点击的界面元素
所选择界面元素的额外信息
/** Called when the activity is first created. */ final static int CONTEXT_MENU_1 = Menu.FIRST; final static int CONTEXT_MENU_2 = Menu.FIRST+1; final static int CONTEXT_MENU_3 = Menu.FIRST+2; TextView LabelView = null; @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo){ menu.setHeaderTitle("快捷菜单标题"); menu.add(0, CONTEXT_MENU_1, 0,"菜单子项1"); menu.add(0, CONTEXT_MENU_2, 1,"菜单子项2"); menu.add(0, CONTEXT_MENU_3, 2,"菜单子项3"); }
重载onContextItemSelected()函数响应菜单选择事件
@Override
public boolean onContextItemSelected(MenuItem item){
switch(item.getItemId()){
case CONTEXT_MENU_1:
LabelView.setText("菜单子项1");
return true;
case CONTEXT_MENU_2:
LabelView.setText("菜单子项2");
return true;
case CONTEXT_MENU_3:
LabelView.setText("菜单子项3");
return true;
}
return false;
}
使用registerForContextMenu(),将快捷菜单注册到某个控件上去
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
LabelView = (TextView)findViewById(R.id.label);
registerForContextMenu(LabelView);
}
操纵栏与Fragment
隐藏Activity的操纵栏
<activity android:theme="@android:style/Theme.Holo.NoActionBar">
或者直接在java代码中添加
ActionBar actionBar=getActionBar();
actionBar.hide();
将选项菜单的菜单项标识为操纵栏中只需在xml文件中添加android:showAsAction="ifRoom|withText"
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/main_menu_0"
android:icon="@drawable/pic0"
android:title="打印"
android:showAsAction="ifRoom|withText"/>
</menu>
在操纵栏上点击某一图标跳转到相应的布局
例如在操纵栏上添加菜单项,点击这个菜单项,出现文字输入功能
添加代码android:actionLayout="@layout/printview",其中printview是printview.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/main_menu_0"
android:icon="@drawable/pic0"
android:title="打印"
android:showAsAction="ifRoom|withText"
android:actionLayout="@layout/printview"/>
</menu>
Fragment
使用Fragment可以将两部分功能合并到同一个Activity中实现
每个Fragment都有自己的布局和生命周期回调函数,同一个Fragment可以放置到多个不同的Activity中
创建Fragment需要继承Fragment的基类,且实现onCreate(),onCreateView(),onPause()生命周期回调函数
如何在一个Activity中同时加载两个Fragment?
首先在main.xml增加两个fragment组件
<fragment android:name ="edu.hrbeu.FragmentDemo.AFragment"
android:id="@+id/fragment_a"
android:layout_weight="1"
android:layout_width="0px"
android:layout_height="match_parent" />
<fragment android:name ="edu.hrbeu.FragmentDemo.BFragment"
android:id="@+id/fragment_b"
android:layout_weight="1"
android:layout_width="0px"
android:layout_height="match_parent" />
在主函数中加载这个main.xml
public class FragmentDemoActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);//!!!
}
}
通过main.xml找到Fragment实现类,调用onCreateView()函数绘制界面元素
LayoutInflater主要是用于加载布局的
public class AFragment extends Fragment{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.frag_a, container, false);
}
}
Tab导航栏
使用操作栏和Fragment实现Tab导航栏
public class FragmentTabActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final ActionBar bar = getActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
bar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);//第一个参数表示显示,第二个参数表示不显示
bar.addTab(bar.newTab()
.setText("Fragment A")
.setTabListener(new TabListener<AFragment>(
this, "fa",AFragment.class)));
bar.addTab(bar.newTab()
.setText("Fragment B")
.setTabListener(new TabListener<BFragment>(
this, "fb", BFragment.class)));
if (savedInstanceState != null) {
bar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0));
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("tab", getActionBar().getSelectedNavigationIndex());
}
public static class TabListener<T extends Fragment> implements ActionBar.TabListener {
private final Activity mActivity;
private final String mTag;
private final Class<T> mClass;
private final Bundle mArgs;
private Fragment mFragment;
public TabListener(Activity activity, String tag, Class<T> clz) {
this(activity, tag, clz, null);
}
public TabListener(Activity activity, String tag, Class<T> clz, Bundle args) {
mActivity = activity;
mTag = tag;
mClass = clz;
mArgs = args;
mFragment = mActivity.getFragmentManager().findFragmentByTag(mTag);
if (mFragment != null && !mFragment.isDetached()) {
FragmentTransaction ft = mActivity.getFragmentManager().beginTransaction();
ft.detach(mFragment);
ft.commit();
}
}
public void onTabSelected(Tab tab, FragmentTransaction ft) {
if (mFragment == null) {
mFragment = Fragment.instantiate(mActivity, mClass.getName(), mArgs);
ft.add(android.R.id.content, mFragment, mTag);
} else {
ft.attach(mFragment);
}
}
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
if (mFragment != null) {
ft.detach(mFragment);
}
}
public void onTabReselected(Tab tab, FragmentTransaction ft) {
Toast.makeText(mActivity, "Reselected!", Toast.LENGTH_SHORT).show();
}
}
}
界面事件
onKey()
onTouch()
ACTION_DOWN、ACTION_UP、ACTION_MOVE 是这样被获取的(event.getAction())
常见问题
- 抽象类
在C++中,含有纯虚拟函数的类称为抽象类,它不能生成对象;
在java中,含有抽象方法的类称为抽象类,同样不能生成对象。
定义的接口的方法全是抽象的方法,要显示声明,用关键字abstruct
一个类只要有抽象的方法,就说明他是抽象类,抽象类可以包括非抽象类的方法 - 接口
在Java中,只有实现了接口的所有方法,才算实现了这个方法
3.
答案: 这三个方法安卓自动调用的,实现了对应的接口,将其实例化(就是让类由抽象变具体的过程),安卓就会根据用户的点击事件调用起对应的方法
4.
答案:这个this指的是当前TabListener的TabListener函数,对应于super是父类的对应函数,因为这是要实现接口,就要把接口下的所有方法给实现。
需要掌握的知识点
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。