4Android用户界面
1. 本章概述
通过本章的学习,掌握Android常用布局管理器的用法,通过综合运用各种布局管理器实现复杂界面的设计。本章详细介绍Android常用组件的知识,并通过实例的实现过程讲解各个组件的使用方法。
2. 本章重点与难点
1) 重点
(1) 常用布局管理器。
(2) 常用UI控件。
(3) 复杂UI控件。
(4) Android资源。
2) 难点
(1) ListView与RecycleView控件的用法。
(2) 图像状态资源的使用。
3. 重难点学习建议
本章主要帮助读者学习并掌握Android中布局管理器的应用,读者在学习中要深入理解各个布局管理器的常用参数。Android应用程序的人机交互界面由许多Android控件组成,这些控件是直接与用户交互的对象,掌握好这些控件对我们在以后的开发中会起到至关重要的作用。多看案例,多思考,多动手实践,从而能够熟练地综合应用各个布局管理器及常用控件搭建出需要实现的界面。本章所涉及的资源文件是读者比较容易忽略的章节,读者往往会感觉学习难度不大,在实际应用中很多时候会因为不注意对资源的使用产生各种各样的错误。学习本章应重点掌握不同资源文件存放的位置、资源的属性、调用的方法等内容。熟练掌握并使用字符串资源、图片资源、值资源、风格与主题资源、动画资源等知识,学好使用资源文件是安卓开发的重中之重。4.1界 面 布 局
界面布局(Layout)是用户界面结构的描述,定义了界面中所有的元素、结构和相互关系。在Android中,每个控件在窗体中都有具体的位置和尺寸,在窗体中摆放各种控件时,很难准确判断控件的具体位置和大小,不过使用Android的布局管理器可以很方便地控制各个控件的位置和大小。Android中的布局是一个容器,在此容器中可放置其他控件,大部分容器控件继承ViewGroup类。在Android应用中,用户界面布局可以使用XML描述。Android Studio提供一套富布局编辑器,开发者可以在其中随意拖曳各类用户界面组件进行布局构建,还可以在多屏幕配置中同时查看多种布局的显示效果。
在Android中,提供了一种非常简单、方便的方法用于控制UI界面。该方法采用XML文件来进行界面布局,从而将布局界面的代码和逻辑控制的代码分离开来,使程序的结构更加清晰、明了。使用XML布局文件控制UI界面可以分为以下两个关键步骤。
(1) 在Android应用的res/layout目录下编写XML布局文件,可以是任何符合Java命名规则的文件名。创建后,R.java会自动收集该布局资源。
(2) 在Activity中使用以下代码加载XML文件中布局的内容。setContentView(R.layout. activity_main);
在上面的代码中,activity_main是XML布局文件的文件名。
通过上面的代码步骤就可轻松实现布局并显示UI界面功能了。
4.1.1线性布局
线性布局(LinearLayout)是布局中最常用的一种布局,它按照垂直或者水平的顺序依次排列子元素,每一个子元素都位于前一个元素之后。如果是垂直排列,那么将是一个N行单列的结构,每一行只会有一个元素,而不论这个元素的宽度为多少;如果是水平排列,那么将是一个单行N列的结构。如果搭建两行两列的结构,通常的方式是先垂直排列两个元素,每一个元素里再包含一个LinearLayout进行水平排列。
LinearLayout属性中的android:orientation属性是设置线性布局方向的,当其值为vertical时,为垂直线性布局,当其值为horizontal时,为水平线性布局。
再来看一下android:layout_gravity 和 android:gravity的使用,这两个属性看起来有些相似,都是设置对齐方式的,那么这两个属性有什么区别呢?其实从名字上就可以看出,android:gravity 是用于指定文字在控件中的对齐方式,而 android:layout_gravity 是用于指定控件在布局中的对齐方式。android:layout_gravity 的可选值和 android:gravity 差不多,但是需要注意,当 LinearLayout 的排列方向是 horizontal 时,只有垂直方向上的对齐方式才会生效,因为此时水平方向上的长度是不固定的,每添加一个控件,水平方向上的长度都会改变,因而无法指定该方向上的对齐方式。同样的道理,当 LinearLayout 的排列方向是 vertical 时,只有水平方向上的对齐方式才会生效。这两个属性的可选值也是相同的,包括: top、bottom、left、right、center_vertical、fill_vertical、center_horizontal、fill_horizontal、center、fill、clip_vertical。而且这些属性是可以多选的,用“|”分开。默认值是: Gravity.LEFT。对这些属性的描述如表4.1所示。表4.1android:layout_gravity和android:gravity属性取值
取值说明top将对象放在其容器的顶部,不改变其大小bottom将对象放在其容器的底部,不改变其大小left将对象放在其容器的左侧,不改变其大小right将对象放在其容器的右侧,不改变其大小center_vertical将对象纵向居中,不改变其大小,垂直对齐方式:垂直方向居中对齐fill_vertical必要的时候增加对象的纵向大小,以完全充满其容器;垂直方向填充center_horizontal将对象横向居中,不改变其大小;水平对齐方式:水平方向居中对齐fill_horizontal必要的时候增加对象的横向大小,以完全充满其容器;水平方向填充center将对象横纵居中,不改变其大小fill必要的时候增加对象的横纵向大小,以完全充满其容器clip_vertical附加选项,用于按照容器的边来剪切对象的顶部和/或底部的内容。剪切基于其纵向对齐设置:顶部对齐时,剪切底部;底部对齐时剪切顶部;除此之外,剪切顶部和底部;垂直方向裁剪clip_horizontal附加选项,用于按照容器的边来剪切对象的左侧和/或右侧的内容。剪切基于其横向对齐设置:左侧对齐时,剪切右侧;右侧对齐时,剪切左侧;除此之外,剪切左侧和右侧;水平方向裁剪【例4.1】android:orientation、android:layout_gravity 和 android:gravity的使用。
运行效果如图4.1所示。
图4.1程序运行效果
程序分析: 例子中在线性容器中放置两个子线性布局容器,如图中上面5个按钮区域和下面5个按钮区域,红色区域线性容器的方向是垂直的,控件的对齐方式是left、center和right。而绿色区域线性容器的方向是水平的,控件的对齐方式是top、center和bottom。
接下来学习LinearLayout的另一个重要属性: android:layout_weight。这个属性允许使用比例的方式来指定控件的大小,它在手机屏幕的适配性方面可以起到非常重要的作用。
【例4.2】使用android:weight完成消息发送界面,包含一个文本编辑框和一个发送按钮。
读者会发现,这里竟然将 EditText 和 Button 的宽度都指定成了0,这样文本编辑框和按钮还能显示出来吗?不用担心,由于使用了 android:layout_weight 属性,此时控件的宽度就不应该再由 android:layout_width 来决定,这里指定成 0 是一种比较规范的写法。
然后在EditText和Button里都将android:layout_weight属性的值指定为1,这表示EditText和Button将在水平方向平分宽度,重新运行程序,会看到如图4.2所示的效果。
图4.2消息发送界面
为什么将android:layout_weight属性的值同时指定为1就会平分屏幕宽度呢?其实原理也很简单,系统会先把LinearLayout下所有控件指定的layout_weight值相加,得到一个总值,然后每个控件所占大小的比例就是用该控件的layout_weight值除以刚才算出的总值。因此,如果想让EditText占据屏幕宽度的3/5,Button占据屏幕宽度的2/5,只需要将EditText的layout_weight改成3,Button的layout_weight改成2就可以了。还可以通过指定部分控件的layout_weight值,来实现更好的效果。
【例4.3】使用android:weight实现按钮放到屏幕底端,剩余空间全部分配给另一个控件。
程序运行效果如图4.3所示。
图4.3程序运行效果
【例4.4】使用android:weight实现两个按钮均分屏幕宽度。
程序运行效果如图4.4所示。
图4.4程序运行效果
4.1.2相对布局
相对布局(RelativeLayout),与线性布局一样,在里面可以放多个控件,但是每个控件的位置都是相对的。可以定义每一个子View与其他子View之间以及与屏幕边界之间的相对位置。RelativeLayout继承于android.widget.ViewGroup,其按照子元素之间的位置关系完成布局,作为Android系统四大布局中最灵活也是最常用的一种布局方式,非常适合于一些比较复杂的界面设计。
注意: 在引用其他子元素之前,引用的ID必须已经存在,否则将出现异常。RelativeLayout按照各子元素之间的位置关系完成布局。在此布局中的子元素里与位置相关的属性将生效。具体的属性介绍如下。
第一类:属性值为true或false。
android:layout_centerHorizontal: 水平居中。
android:layout_centerVertical: 垂直居中。
android:layout_centerInparent: 相对于父元素完全居中。
android:layout_alignParentBottom: 贴紧父元素的下边缘。
android:layout_alignParentLeft: 贴紧父元素的左边缘。
android:layout_alignParentRight: 贴紧父元素的右边缘。
android:layout_alignParentTop: 贴紧父元素的上边缘。
android:layout_alignWithParentIfMissing: 如果对应的兄弟元素找不到就以父元素作参照物。
第二类: 属性值必须为id的引用名“@id/idname”。
android:layout_below: 在某元素的下方。
android:layout_above: 在某元素的上方。
android:layout_toLeftOf: 在某元素的左边。
android:layout_toRightOf: 在某元素的右边。
android:layout_alignTop: 本元素的上边缘和某元素的上边缘对齐。
android:layout_alignLeft: 本元素的左边缘和某元素的左边缘对齐。
android:layout_alignBottom: 本元素的下边缘和某元素的下边缘对齐。
android:layout_alignRight: 本元素的右边缘和某元素的右边缘对齐。
第三类: 属性值为具体的像素值,如40dip,30px。
android:layout_marginBottom: 离某元素底边缘的距离。
android:layout_marginLeft: 离某元素左边缘的距离。
android:layout_marginRight: 离某元素右边缘的距离。
android:layout_marginTop: 离某元素上边缘的距离。
android:gravity属性是用来设置元素的文本内容的显示位置,比如一个按钮上面的文本可以靠左或者靠右显示,如果要设置按钮的文本靠右显示,就编写为android:gravity="right"。
android:layout_gravity是用来设置该元素相对于其父类元素的位置,比如一个按钮显示在线性布局管理器中,如果要设置按钮靠右显示,就编写为android:layout_gravity="right"。
下面通过一个实例来学习相对布局的应用。
【例4.5】相对布局管理器实例。
程序分析: 本案例中使用相对布局管理器,共有8个按钮,B1放在父容器的左上角,B2放在父容器的左下角,B9放在父容器的中心,B6放在父容器的右侧垂直居中,以此类推,设置所有按钮相对父容器的位置。
界面设计效果如图4.5所示。
图4.5相对布局管理器案例运行结果图
4.1.3帧布局
FrameLayout表示帧布局管理器,在帧布局管理器中每加入一个控件都将会创建一个空白的区域,通常称之为一帧,这些帧会根据gravity属性执行自动对齐。默认情况下,帧布局从屏幕的左上角(0,0)坐标点开始布局,多个控件层叠排序,后面的控件覆盖前面的控件。
此布局可以放置多个view,但只有一个view可以显示,通常使用此布局处理在同一位置不同情况下显示不同内容的控件。
在Andriod中,在XML布局文件中定义帧布局管理器可以使用标记,格式为:
下面通过例子来看一下帧布局管理器的应用。
【例4.6】使用帧布局管理器实现通过单击按钮在3个红、绿、蓝的View之间进行切换的效果。
实现步骤如下。
(1) 首先实现界面效果,创建布局文件activity_frame,布局根元素使用垂直方向的线性布局,在根线性布局中再放置一个水平方向的线性容器,在水平线性容器中放置三个按钮,在根线性容器中接着再放一个帧布局,将三个TextView器放置到帧布局中,界面结构如图4.6所示。
图4.6界面布局结构
对应的代码如下。
(2) 在FrameActivity.java文件中加载上面创建的布局文件,添加如下代码,让按钮能够进行事件处理,从而显示帧布局切换的效果。package com.example.booksource;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class FrameActivity extends AppCompatActivity {
class ButtonListener implements View.OnClickListener{
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.frameA:
txtA.setVisibility(View.VISIBLE);
txtB.setVisibility(View.GONE);
txtC.setVisibility(View.GONE);
break;
case R.id.frameB:
txtB.setVisibility(View.VISIBLE);
txtA.setVisibility(View.GONE);
txtC.setVisibility(View.GONE);
break;
case R.id.frameC:
txtC.setVisibility(View.VISIBLE);
txtA.setVisibility(View.GONE);
txtB.setVisibility(View.GONE);
break;
}
}
}
private Button btnA,btnB,btnC;
private TextView txtA,txtB,txtC;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_frame);
btnA=findViewById(R.id.frameA);
btnA.setOnClickListener(new ButtonListener());
btnB=findViewById(R.id.frameB);
btnB.setOnClickListener(new ButtonListener());
btnC=findViewById(R.id.frameC);
btnC.setOnClickListener(new ButtonListener());
txtA=findViewById(R.id.txtA);
txtB=findViewById(R.id.txtB);
txtC=findViewById(R.id.txtC);
}
}
单击FRAMEA按钮,界面如图4.7(a)所示,单击FRAMEB按钮,界面如图4.7(b)所示。
图4.7帧布局管理器案例运行结果
4.1.4网格布局
网格布局(GridLayout)在Android 4.0以上版本中才出现。GridLayout使用虚细线将布局划分为行、列和单元格,也支持一个控件在行、列上都有交错排列。而GridLayout使用方式有些类似LinearLayout,只不过是修改了一下相关的标签而已,所以对于开发者来说,掌握GridLayout还是很容易的。
GridLayout的布局策略简单分为以下三个部分。
首先,它与LinearLayout布局一样,也分为水平和垂直两种方式,默认是水平布局,一个控件挨着一个控件从左到右依次排列,但是通过指定android:columnCount设置列数的属性后,控件会自动换行进行排列。另外,对于GridLayout布局中的子控件,默认按照wrap_content的方式设置其显示,这只需要在GridLayout布局中显式声明即可。
其次,若要指定某控件显示在固定的行或列,只需设置该子控件的android:layout_row和android:layout_column属性即可,但是需要注意: android:layout_row="0"表示从第一行开始,android:layout_column="0"表示从第一列开始,这与编程语言中一维数组的赋值情况类似。
最后,如果需要设置某控件跨越多行或多列,只需将该子控件的android:layout_rowSpan或者layout_columnSpan属性设置为数值,再设置其layout_gravity属性为fill即可,前一个设置表明该控件跨越的行数或列数,后一个设置表明该控件填满所跨越的整行或整列。
【例4.7】使用网格布局完成计算器界面设计。
程序界面设计效果如图4.8所示。
图4.8网格布局管理器案例运行结果图
android:layout_gravity="fill"和android:layout_columnWeight="1"能让按钮平均分配所占列宽。
4.2项目实战: 综合运用常用布局实现eShop首页界面效果〖*2〗4.2.1项目分析本小节要实现项目中首页的界面开发,在完成界面开发时,首先确定界面所需的布局,因此结合本章所学知识,确定界面所用的布局和布局间的嵌套关系。先看首页的组成,首页界面涉及多个布局管理器的应用,最外层是LinearLayout布局管理器以垂直的方式布局,内层首先嵌套一个FrameLayout布局管理器,此布局管理器的使用是为了实现将来在程序中添加广告的展示,当前只留出位置,内容在后续章节添加。中间以GridLayout布局管理器和LinearLayout布局管理器两种布局管理器来布局,实现显示各类功能的显示。左面表示表格布局中的第一行的布局,右面是第二行的布局,两部分的组成是相同的。接下来是第三部分,将来是热门店铺的推荐、热门商品的推荐等,这个板块也主要是应用线性布局管理器来实现的,应用到的其他控件将在后续章节介绍,这里不再赘述。
4.2.2项目实现
那么接下来就通过程序代码来学习这部分的具体实现。页面布局文件fragment_home.xml的代码如下。
"
4.2.3项目说明
本项目的首页涵盖内容较多,布局复杂,因此在首页的设计中用到了多种布局,首先把首页分成上中下三块,再以此进行每块的设计和布局,最终实现了总体效果。运行Activity文件显示的界面效果图如图4.9所示。
图4.9首页运行结果
4.3常用基本控件〖*2〗4.3.1文本类控件〖*2〗1. TextView在Android中使用TextView表示文本框,用于在屏幕上显示文本,主要显示不可编辑的文本,这与Java中的文本框控件不同,它相当于Java中的标签,TextView可以自动识别并链接如Email地址、Web地址、电话号码等特殊字符,它包含的主要属性如表4.2所示。表4.2TextView常用属性说明
属性说明android:text设置TextView显示的文本内容android:textColor设置文本颜色android:textSize设置文本字体的大小,支持度量单位: px(像素)/dp/sp/in/mmandroid:textStyle设置文本字体的风格,取值一般为bold、italic等android:height设置文本区域的高度,支持度量单位: px(像素)/dp/sp/in/mmandroid:layout_ height设置文本相对父类的长度的值,取值一般为match_parent,wrap_contentandroid:width设置文本区域的宽度,支持度量单位: px(像素)/dp/sp/in/mm,如果是android:layout_width="match_parent",那么设置 android:width 是没有意义的android:layout_width设置文本相对父类的宽度的值,取值一般为match_parent,wrap_contentandroid:layout_gravity设置该控件相对于父view 的位置android:numeric如果被设置,该TextView有一个数字输入法。有如下值设置: integer正整数、signed带符号整数、decimal带小数点浮点数android:password以小点“.”显示文本android:phoneNumber设置为电话号码的输入方式android:singleLine设置单行显示。如果和layout_width一起使用,当文本不能全部显示时,后面用“…”表示。如果不设置singleLine或者设置为false,文本将自动换行【例4.8】本案例介绍了TextView控件的各种显示效果,包括文字居中、文字跑马灯效果、设置文字阴影效果、设置文字阴影效果、设置网址超链接效果、设置文字超链接效果、设置电话超链接效果、设置字形、设置文字缩放、设置行间距、设置行间距的倍数等内容,具体的应用请看下面的例子,主要是通过TextView控件的属性来设置的,代码如下。
运行结果如图4.10所示。
图4.10TextView控件运行结果图
2. AutoCompleteTextView
自动文本框使用AutoCompleteTextView表示,实现用户输入一定字符后显示一个下拉菜单,供用户从中选择,当用户选择某个菜单项后,按用户所选自动填写该文本框。
在屏幕中添加自动文本框,可在XML布局文件中通过标记添加,格式为:
AutoCompleteTextView控件是由TextView派生的,所以它支持EditText控件提供的属性,同时,该控件还支持以下XML属性。
android:completionHint: 用于为弹出的下拉菜单指定提示标题。
android:completionThreshold: 用于指定用户至少输入几个字符才会显示提示。
android:dropDownHeight: 用于指定下拉菜单的高度。
android:dropDownWidth: 用于指定下拉菜单的宽度。
android:dropDownHorizontalOffset: 用于指定下拉菜单与文本之间的水平偏移,下拉菜单默认与文本框左对齐。
android:dropDownSelector: 下拉列表被选中的行的背景。
android:ems: 需要编辑的字符串长度。
3. MultiAutoCompleTextView
该控件可支持选择多个值(在多次输入的情况下),分别用分隔符分开,并且在每个值选中的时候再次输入值时会自动去匹配。可用在发短信、发邮件时选择联系人这种类型当中。使用时需要执行设置分隔符方法。
MultiAutoCompleteTextView的使用和AutoCompleteTextView类似,只是需要设置分隔符。
具体的使用方法为在setAdapter()方法后添加:setTokenizer(new MultiAutoCompleteTextView.CommaTokenizer());
4. EditText
在Android中,使用EditText表示输入框,用于在屏幕上显示文本输入框,这与Java中的文本框控件功能类似。不同之处在于,Android中的编辑框控件可以输入单文本,也可以输入多行文本,还可以输入指定格式的文本,例如电话号码、密码、Email地址等内容。
在Android中可使用两种方法向屏幕中添加编辑框,通常在XML布局文件中使用标记添加,添加格式如下:
由于EditText类是TextView的子类,所以TextView的属性适用于EditText控件,特别需要注意的是,在EditText控件中,android:inputType属性可以帮助输入法显示合适的类型。例如,要添加一个密码框,可以将android:inputType属性设置为textPassword。
通常在使用EditText控件时,还需要获取该控件输入的文本内容,可以通过编辑框控件提供的getText()方法实现。在使用该方法时,要先获取到编辑框控件,然后再调用getText()方法,例如,要获取布局文件中添加的ID属性为txt的编辑框内容,可通过如下代码实现:EditText txt=(EditText)(this.findViewById(R.id.txt));
String txtText=txt.getText().toString();
【例4.9】EditText控件、AutoCompleteTextView控件和MultiAutoCompleteTextView控件的应用。本案例介绍了三个控件的应用,使用EditText控件的输入文本功能,并实现了通过对EditText控件进行事件处理实现了对脏话的过滤功能,同时也实现了AutoCompleteTextView和MultiAutoCompleteTextView两个控件的自动完成单个和多个文本的输入功能。
其实现步骤如下。
新建一个模块,打开项目文件夹中的res\\layout目录下的activity_main.xml文件,将其中的代码替换为以下代码。
MainActivity中的主要代码如下。package com.example.chap4_2;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.EditText;
import android.widget.MultiAutoCompleteTextView;
public class Main4Activity extends AppCompatActivity {
privateEditText editText;
private AutoCompleteTextView auto;
private MultiAutoCompleteTextView multi;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main4);
editText=findViewById(R.id.edit);
auto=findViewById(R.id.auto);
multi=findViewById(R.id.multi);
String [] items={"bai","baidu","baicheng","baii"};
ArrayAdapter adapter=new ArrayAdapter<>(this,android.R.
layout.simple_list_item_1,items);
auto.setAdapter(adapter);
multi.setAdapter(adapter);
multi.setTokenizer(new MultiAutoCompleteTextView.CommaTokenizer());
//分隔符号是逗号
editText.addTextChangedListener(new TextWatcher() {
String [] filters={"NND","MMD","MM"};
String oldtext,newtext;
@Override
public void beforeTextChanged(CharSequence s, int start, int
count, int after) {
oldtext=editText.getText().toString();
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
newtext=editText.getText().toString();
if(newtext.equals(oldtext)){
return;
}
for(String filter:filters){
if(newtext.indexOf(filter)!=-1){
newtext=newtext.replaceAll(filter,"");
}
}
editText.setText(newtext);//重新设置文本框内容
editText.invalidate();//刷新页面
editText.setSelection(newtext.length());
//把光标置于文本框末尾
}
});
}
}
运行效果如图4.11所示。
在图4.11中,在AutoCompleteTextView控件中输入文本“Be”,程序会自动弹出提示两个可选项,可以选择其中一个输入,运行结果如图4.12所示。
图4.11TextView控件运行结果
图4.12输入“Be”后弹出可选项
在MultiAutoCompleteTextView控件中输入文本“Be”,程序也会自动弹出提示两个可选项,可以选择其中一个输入,也可以选择多个,自动用“,”分隔,运行结果如图4.13所示。
EditText控件具备文本输入的功能,在本案例中设置了对脏话的过滤功能,当从键盘输入“NND”时,屏幕自动显示“**”,把脏话隐藏了。具体显示结果如图4.14所示。
图4.13TextView控件运行结果
图4.14EditTex控件运行结果
4.3.2按钮类控件〖*2〗1. RadioButtonRadioButton表示单选按钮,是Button的子类,所以单选按钮继承了Button的各种属性,可以直接使用。默认情况下,单选按钮显示为一个圆形图标,并且在该图标旁边放置一些说明性文字,而在程序中,一般将多个单选按钮放置在按钮组中,使这些单选按钮能够实现互斥,当用户选中某个单选按钮后,按钮组中的其他按钮将自动取消选中状态。
RadioGroup是单选组合框,用于将RadioButton框起来;在没有RadioGroup的情况下,RadioButton可以全部都选中;当多个RadioButton被RadioGroup包含的情况下,RadioButton只可以选择一个。
RadioGroup常用方法如表4.3所示。表4.3RadioGroup常用的方法
方法功 能 描 述addView(View child, int index,ViewGroup.LayoutParams params)使用指定的布局参数添加一个子视图check(int id) 单选按钮组的勾选状态clearCheck() 清除当前的选择状态,当选择状态被清除,则单选按钮组里面的所有单选按钮将取消勾选状态,getCheckedRadioButtonId()将返回nullgetCheckedRadioButtonId() 返回该单选按钮组中所选择的单选按钮的标识ID,如果没有勾选则返回-1setOnCheckedChangeListener(RadioGroup.OnCheckedChangeListener listener)注册一个当该单选按钮组中的单选按钮勾选状态发生改变时所要调用的回调函数由于RadioButton是继承自TextView,所以TextView具有的属性,都可以继承。RadioGroup常用的属性如表4.4所示。表4.4RadioGroup常用的属性
属性描述android:checkedButton单选按钮组内默认被选中的单选按钮的idandroid:background可拉伸作为背景android:contentDescription定义文本简要描述了视图内容android:id对此视图提供一个标识符名称android:onClick在本视图的上下文视图被单击时调用方法的名称android:visibility控制视图的初始可视性2. SeekBar拖动条
SeekBar(拖动条)是ProgressBar的扩展,与水平形式的显示进度条类似,不过其最大的区别在于,拖动条可以由用户自己进行手工调节,例如,当用户需要调整播放器音量或者电影的播放速度时都会用到拖动条SeekBar类。用户可以拖动滑块并向左或向右拖动,或者可以使用方向键设置当前的进度等级。使用过程中不建议把可以获取焦点的widget放在SeekBar的左边或右边。
SeekBar类的层次关系如下。java.lang.Object
android.view.View
android.widget.ProgressBar
android.widget.AbsSeekBar
android.widget.SeekBar
【例4.10】按钮类的应用。
本案综合运用按钮,使用实现了CheckBox的多选和RadioButton的单选功能,对按钮做了事件处理,获取并输出了CheckBox和RadioButton的选中信息,设置switch控件的事件处理,监听WiFi是否打开状态,监听SeekBar滑动事件,可通过滑动SeekBar来改变字号大小。具体的应用请看下面的例子。
布局文件内容如下。
MainActivity.java 中的主要代码如下。package com.example.chap4_2;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.SeekBar;
import android.widget.Switch;
import android.widget.TextView;
import android.widget.Toast;
public class ButtonDemoActivity extends AppCompatActivity {
private RadioGroup radioContainer;
private LinearLayout checkContainer;
private Switch wifi;
private SeekBar seekBar;
private TextView txtResult;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_button_demo);
radioContainer=(findViewById(R.id.radioContainer));
checkContainer=(findViewById(R.id.checkContainer));
wifi=findViewById(R.id.wifi);
seekBar=findViewById(R.id.seekBar);
txtResult=findViewById(R.id.text);
seekBar.setOnSeekBarChangeListener(new
SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
txtResult.setTextSize(progress);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
wifi.setOnCheckedChangeListener(new CompoundButton.
OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(isChecked) {
Toast.makeText(ButtonDemoActivity.this, "wifi opened", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(ButtonDemoActivity.this, "wifi closed", Toast.LENGTH_LONG).show();
}
}
});
}
public void btnDisplaySelected(View view){
String radioText="";
for(int i=0;i
MainActivity.java中的主要代码如下。package com.example.chap4_2;
import java.util.Calendar;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.DatePicker;
import android.widget.DatePicker.OnDateChangedListener;
import android.widget.LinearLayout;
import android.widget.TextView;
public class DatePickerActivity extends Activity {
private TextView txtDate;
static int year, month, day;
private LinearLayout linear;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_date_picker);
txtDate=this.findViewById(R.id.txtDate);
linear=this.findViewById(R.id.linear);
//初始化Calendar日历对象。
Calendar c=Calendar.getInstance();
year=c.get(Calendar.YEAR);
month=c.get(Calendar.MONTH)+1;//获取Calendar对象中的月,0表示1月,1表示2月....
day=c.get(Calendar.DATE);
txtDate.setText(year+"--"+month+"--"+day);
txtDate.setTextSize(24);
}
public void set(View v) {
final DatePicker datePicker=new DatePicker(this);
linear.addView(datePicker);
datePicker.init(year, month, day, new OnDateChangedListener() {
//view:该事件关联的组件, myyear: 当前选择的年, monthOfYear:当前选
//择的月,dayOfMonth: 当前选择的日
public void onDateChanged(DatePicker view, int year,
int monthOfYear, int dayOfMonth) {
//修改year,month,day变量值,以便在依次单击按钮时DatePickerDialog
//上显示上一次修改后的值
DatePickerActivity.year=year;
DatePickerActivity.month=monthOfYear;
DatePickerActivity.day=dayOfMonth;
//在DatePickerDialog组件上设置日期后,同时修改TextView上的信息
txtDate.setText(year+"--"+(month+1)+"--"+day);
datePicker.setVisibility(View.GONE);
}
});
}
}
由上面的布局可以看出,该界面默认情况下并没有DatePicker控制,该控件是在程序运行中添加进来的。
运行结果如图4.17所示。
单击“设置日期”按钮,出现如下控件的显示界面,就可以进行日期的设置了。具体界面如图4.18所示。
图4.17DatePicker案例的运行结果 1
图4.18DatePicker案例的运行结果 2
4.4项目实战: 主页底端导航条的实现〖*2〗4.4.1项目分析项目底端导航条利用5个单选按钮实现不同页面的切换,5个单选按钮分别是“首页”“购物车”“分类”“搜索”“我的”,单击哪个按钮就会切换到哪个页面,因为目前各个页面还没有实现,所以此时使用弹出对话框显示切换到的页面索引值。底端导航条效果图如图4.19所示。
图4.19主页的底端导航条效果
4.4.2项目实现
图4.19界面的下方包含五个单选按钮处于屏幕底端,其余空间全部分配给页面,可使用线性布局实现上面的效果。布局文件的代码如下。
布局结构如图4.20所示。
图4.20主页的布局结构
4.4.3项目说明
本功能的实现需要监听单选按钮选中状态发生变化的事件,选中某个按钮,会把选中按钮的索引显示出来,如图4.21所示,若用户选择了购物车,则弹出的索引值为1。
图4.21eShop首页单选按钮运行结果
4.5常用高级控件〖*2〗4.5.1ListView列表组件ListView控件用于以列表形式显示数据,采用MVC模式将前端显示与后端数据进行分离。ListView相当于MVC中的View(视图),为ListView提供数据的List,数据或数据库相当于MVC中的Model(模型),而在需要添加数据的时候,则需要指定一个Adapter对象,Adapter则相当于MVC中的Controller(控制器)。
ListView类的层次关系如下。
java.lang.Object
android.view.View
android.view.ViewGroup
android.widget.AdapterView
android.widget.AbsListView
android.widget.ListView
ListView常用方法如表4.5所示。表4.5ListView常用的方法
方法功 能 描 述getAdapter()获取ListView的Adapter onFocusChanged(boolean gainFocus,int direction,Rect previouslyFocusedRect)获取view中焦点的变化setAdapter(ListAdapter adapter)绑定Adapter到ListView上1. ListView与Array Adapter
【例4.12】显示简单的ListView列表。
下面使用自定义布局建立图4.22所示的单行自定义ListView加载已经写好的数组内容。
图4.22单行自定义ListView
首先创建ListView并引用layout,layout里含有ListView想要展示的内容,控件的代码如下。
在Java文件中对该ListView加载具体内容,需显示的内容为下面定义的城市数组cities,并且通过Adapter将cities与ListView绑定,其代码如下。//1. 通过findViewById方法获取ListView对象
myListView=(ListView) findViewById(R.id.myListView);
//2. 定义一个数组,显示具体内容
String[] cities={"加格达奇","鄂尔多斯","呼伦贝尔"};
//3. 写一个adapter不写具体内容,内容从之前定义好的资源文件里引用过来
ArrayAdapter adapter=new ArrayAdapter(this,
R.layout.support_simple_spinner_dropdown_item,cities);
//4. 创建Adapter对象设置Adapter
myListView.setAdapter(adapter);
这里需要介绍一下R.layout.support_simple_spinner_dropdown_item布局,该布局是显示ListView所默认的布局,也可以对该布局的显示方式进行调整,使用自定义布局对城市信息进行显示。上述代码中只能选择一个条目,可以使用setChoiceMode实现对多条列表项的选择,使用语句如下:listView.setChoiceMode(listView.CHOICE_MODE_MULTIPLE);
2. ListView与SimpleAdapter
利用适配器SimpleAdapter匹配List数据,一般都是HashMap结构的List,List的每一节对应ListView的每一行。HashMap的每个键值数据映射到布局文件中对应id的组件上。
SimpleAdapter构造方法如下。public SimpleAdapter(Context context,List extends Map> data, int resource, String[] from,int[] to)
第一个参数context: 表示访问整个Android应用程序接口,基本上所有的组件都需要。
第二个参数data: 一个由Map(String,Object)列表选项构成的List。每一个Map对应列表中的一行,而且每一个Map中应该包含所有在from参数中指定的键。
第三个参数resource: 一个定义列表项的布局文件的资源ID。该布局文件中至少包含那些在to参数中定义了的空间ID。
第四个参数from: 一个被添加到Map映射的键名。
第五个参数to: 绑定数据的视图空间的ID,与from参数的值一一对应。
创建一个案例,显示朋友的用户名列表,列表具有头像和姓名属性,通过姓名查找朋友,然后进行数据的删除。
【例4.13】ListView使用SimpleAdapter显示图文排列。
例4.12实现的是ListView简单文本显示效果,下面将例4.12的Java代码进行修改,实现ListView图文显示效果。首先在主布局文件activity_main.xml中定义ListView。
为了使List显示图文效果,使用了一个自定义的布局文件activity_main2.xml,这个布局的主要作用是定义List需要显示的图文,关键代码如下。
在Activity中,首先获取ListView:setContentView(R.layout.activity_main);
listView1=(ListView) findViewById(R.id.listView1);
接下来定义一个list,并在list里添加具体内容,在SimpleAdapter中使用该list中的内容,关键代码如下。//准备数据,每一个HashMap就是一条记录
HashMap title1=new HashMap<>();
title1. put("title","这是第1行HashMap");
HashMap title2=new HashMap<>();
title2. put("title","文字可以随意填写");
HashMap title3=new HashMap<>();
title3. put("title","通过HashMap加入到list列表中");
//建立List列表
List