安卓中级控件(图形、选择按钮、文本输入、对话框)

图形定制

图形Drawable

Android把所有能够显示的图形都抽象为Drawable类(可绘制的)。这里的图形不止是图片,还包括色块、画板、背景等。
包含图片在内的图形文件放在res目录的各个drawable目录下,其中drawable目录一般保存描述性的XML文件,而图片文件一般放在具体分辨率的drawable目录下。例如:

  • drawable-ldpi里面存放低分辨率的图片(如240×320),现在基本没有这样的智能手机了。
  • drawable-mdpi里面存放中等分辨率的图片(如320×480),这样的智能手机已经很少了。
  • drawable-hdpi里面存放高分辨率的图片(如480×800),一般对应4英寸!4.5英寸的手机(但不绝对,同尺寸的手机有可能分辨率不同,手机分辨率就高不就低,因为分辨率低了屏幕就会有模糊的感觉)。
  • drawable-xhdpi里面存放加高分辨率的图片(如720×1280),一般对应5英寸~5.5英寸的手机。
  • drawable-xxhdpi里面存放超高分辨率的图片(如1080×1920),一般对应6英寸~6.5英寸的手机。
  • drawable-xxxhdpi里面存放超超高分辨率图片(如1440×2560),一般对应7英寸以上的手机。

基本上,分辨率每加大一级,宽度和高度就要增加二分之一或三分之一像素。如果各自目录存在同名图片,Android就会根据手机的分辨率分别适配对应文件夹里的图片。在开发App时,为了兼容不同的手机屏幕,在各个目录存放不同分辨率的图片,才能达到最合适的显示效果。例如,在drawable-hdpi里面放了一张背景图片bg.png(分辨率480×800),其他目录没放,使用分辨率为480×800的手机查看该App界面没有问题,但是使用分辨率为720×1280的手机查看该图片就会模糊,原因是Android为了让bg.png适配高分辨率的屏幕,强行把bg.png拉伸到了720×1280,拉伸的结果就是图片模糊了。
在XML布局文件中引用图片文件中引用图形文件可用“@drawable/不含扩展名的文件名称”这种形式,如各视图的background属性、ImageViewImageButton的src属性、TextViewButton四个方向的drawable***系列属性都可以引用图形文件。

形状图形

Shape图形又称形状图形,用来描述常见的几何形状,包括矩形、圆角矩形、圆形、椭圆等。用好形状图形可以让App页面不在呆板,还可以节省美工不少工作量。
形状图形的定义文件放在srawable目录下,它是以shape标签为根节点的XML描述文件。根节点下定义了6个节点,分别是size(尺寸)、stroke描边、corners(圆角)、solid(填充)、padding(间隔)、gradient(渐变),各节点的属性值主要是宽和高、半径、角度以及颜色。下面是形状各个节点及其属性的简要说明。

shape(形状)

Shape是形状图形文件的根节点,它描述了当前是哪几种几何图形。下面是shape节点的常用属性说明。

  • shape:字符串类型,表示图形的形状。形状取值说明见下表
形状类型说明
rectangle矩形。默认值
oval椭圆。此时corners节点会失效
Line直线。此时必须设置stroke节点,不然会报错
ring圆环

size(尺寸)

size是shape的下级节点,它描述了形状图形的宽高尺寸。若无size节点,则表示宽高与宿主视图一样大小。下面是size节点的常用属性说明。

  • height:像素类型,图形高度。
  • width:像素类型,图形宽度

stroke(描边)

stroke是shape的下级节点,它描述形状图形的描边规格。若无stroke节点,则表示不存在描边。下面是stroke节点的常用属性说明。

  • color:颜色类型,描边的颜色。
  • dashGap:像素类型,每段虚线之间的间隔。
  • dashWidth:像素类型,每段虚线的宽度。若dashGap和dashWidth有一个值为0,则描边为实线。
  • width:像素类型,描边的厚度。

corners(圆角)

corners是shape的下级节点,它描述了形状图形的圆角大小。若无corners节点,则表示没有圆角。下面是corners节点的常用属性说明。

  • bottomLeftRadius:像素类型,左下圆角的半径。
  • bottomRightRadius:像素类型,右下圆角的半径。
  • topLeftRadius:像素类型,左上圆角的半径。
  • topRightRadius:像素类型,右上圆角半径。
  • radius:像素类型,4个圆角的半径(若有上面4个圆角半径的定义,则不需要radius定义)。

solid(填充)

solid是shape的下级节点,它描述了形状图形的填充色彩。若无solid节点,则表示无填充颜色。下面是solid节点的常用属性说明。

  • color:颜色类型,内部填充的颜色。

padding(间隔)

padding是shape的下级节点,它描述了形状与周围边界的间隔。若无padding节点,则表示四周不设间隔。下面是padding节点的常用属性说明。

  • top:像素类型,与上方的间隔。
  • bottom:像素类型,与下方的间隔。
  • right:像素类型,与右边的间隔。
  • left:像素类型,与左边的间隔。

gradient(渐变)

gradient是shape的下级节点,它描述了形状图形的颜色渐变。若无gradient节点,则表示没有渐变效果。下面是gradient节点的常用属性说明。

  • angle:整型,渐变的起始角度。为0时表示始终的9点位置,值增大表示往逆时针方向旋转。
  • type:字符串类型,渐变类型。渐变类型取值见下表:
渐变类型说明
linear线性渐变,默认值
radial放射渐变,其实颜色就是圆心颜色
sweep滚动渐变,即一个线段以某个断电为圆心做360°旋转
  • centerX:浮点型,圆形的X坐标。当android:type="linear"时不可用。
  • centerY:浮点型,圆形的Y坐标。当android:type="linear"时不可用。
  • gradientRadius:整型,渐变半径。当android:type="radial"时需要设置该属性。
  • centerColor:颜色类型,渐变的中间颜色。
  • startColor:颜色类型,渐变的起始颜色。
  • endColor:颜色类型,渐变的终止颜色。
  • useLevel:布尔类型,设置为true为无渐变色、false为有渐变色。

在实际开发中,形状图形主要使用3个节点:stroke(描边)、corners(圆角)和solid(填充)。至于shape根节点的属性一般不用设置(默认矩形即可)。
接下来演示一下形状图形的界面效果,首先右击drawable目录,并依次选择右键菜单的New->Drawable resource file,在弹窗中输入文件名称再单击OK按钮,即可自动生成一个XML描述文件。往该文件填入下面的圆角矩形内容定义:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!--  指定了形状内部的填充颜色  --><solid android:color="#ffdd66" />
<!--  指定了形状轮廓的粗细与颜色  --><strokeandroid:width="1dp"android:color="#aaaaaa" />
<!--  指定了形状4个圆角的半径  --><corners android:radius="10dp" />
</shape>

接着再创建一个椭圆图形,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"android:shape="oval">
<!--  指定了形状内部的填充颜色  --><solid android:color="#ff66aa" />
<!--  指定了形状轮廓的粗细与颜色  --><strokeandroid:width="1dp"android:color="#aaaaaa" />
</shape>

执行代码,切换两种图形显示,就能看到如下两种效果图:
椭圆图形
矩形图形

九宫格图片

将某张图片设置成视图背景时,如果图片尺寸太小,则系统会自动拉伸图片使之填满背景。但是一旦图片拉伸过大,其画面容易变得模糊,如下图:
在这里插入图片描述
如上图所示,上面的按钮的背景图片被拉得很宽,此时左右两边的边缘即变宽又变得模糊。需要注意的是,我们在xml文件里通过背景属性这样android:background="@drawable/button_normal_orig"直接设置背景图片可能显示不出来。这时只需要将按钮控件用<android.widget.Button代替<Button就可以了。
为了解决拉伸模糊问题,Android设计了点九图片。点九图片的扩展名是.png,文件后面常带有“.9”字样。因为该图片划分了3×3的九宫格区域,所以得名点九图片,也叫做九宫格图片。如果背景是个形状图形,其stroke节点的width属性已经设置了固定数值(如1dp),那么无论该图形被拉到多大,描边宽度始终是1dp。九宫格图片的实现原理与之类似,即拉伸图形时,只拉伸内部区域,不拉伸边缘线条。
为了演示九宫格图片的展示效果,利用Android Studio制作一张点九图片。首先在drawable目录下找到待加工的原始图片button_pressed_orig.png,右击它弹出右键菜单,如下图:
在这里插入图片描述
选择上图右键显示菜单的Create 9-Patch file...,并在随后弹出的对话框中单击OK按钮。接着drawable目录自动生成一个名为“button_pressed_orig.9.png”的图片,双击该文件,主界面右侧弹出如下图显示的点九图片的加工窗口:
在这里插入图片描述
上图的左侧窗口时图片加工区域,右侧窗口是图片预览区域,从上到下依次是纵向拉伸预览,横向拉伸预览、两方向同时拉升预览。在左侧窗口图片四周的马赛克处单击会出现一个黑点,把黑点左右或上下拖动会拖出一段黑线,不同方向上的黑线表示不同效果。
下图所示,界面上的黑线指的是水平方向的拉伸区域。在水平方向拉伸图片时,只有黑线区域内的图像会被拉伸,黑线以外的图像保持原状,从而保证左右两边的边框厚度不变。
在这里插入图片描述
下图所示,界面左边的黑线指的是垂直方向的拉伸区域。在垂直方向拉伸图片时,只有黑线区域内的图像会被拉伸,黑线以外的图像保持原状,从而保证上下两侧的边框厚度不变。
在这里插入图片描述
下图所示,界面下边的黑线指的是该图片作为控件背景时,控件内部的文字左右边界只能放在黑线区域内,这里Horizontal Padding的效果就相当于android:paddingLeftandroid:paddingRight
在这里插入图片描述
下图所示,界面右边的黑线指的是该图片作为控件背景时,控件内部的文字上下边界只能放在黑线区域内。这里Vertical Padding的效果相当于android:paddingTopandroid:paddingBottom
在这里插入图片描述
注意:如果点九图片被设置为视图背景,且该图片指定了Horizontal PaddingVertical Padding,那么视图内部将一直与视图边缘保持固定间距,无论怎么调整XML文件和Java代码都无法缩小,缘由时点九图片早已在水平和垂直都设置了padding。

状态列表图形

常见的图形文件一般为静态文件,但有时会用到动态文件,比如按钮控件的背景在正常情况下是凸起的,在按下时是凹陷的,从按下到弹起的过程,用户便知道点击了该按钮。根据不同的触摸情况变更形态,这种情况用到了Drawable的一个子类StateListDrawable(状态列表图形),它在XML文件中规定了不同状态所呈现的图形列表。
接下来演示一下状态列表图形的界面效果,右击drawable目录,并依次选择右键菜单的New->Drawable resource file,在弹窗中输入文件名再单击OK按钮,即可自动生成一个XML描述文件。往该文件填入下面的状态列表图形定义:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"><item android:state_pressed="true"android:drawable="@drawable/button_pressed" /><item android:drawable="@drawable/button_normal" />
</selector>

上述XML文件的关键点是state_pressed属性,该属性表示按下状态,值为true表示按下时显示button_pressed图像,其余情况显示button_normal图像。
接下来做个验证,首先将“定制样式的按钮”这一按钮控件的android:background属性设置为@drawable/btn_nine_selector,然后再屏幕上点击按钮,观察发现按下按钮时的界面如下图所示:
定制样式按钮按下
未点击时的状态如下:
定制样式按钮未按下
状态列表图形不仅用于按钮控件,还可用于其他拥有多种状态的控件,这取决于开发者在XML文件中指定了哪种状态类型。各种状态类型取值说明取值如下表:

状态类型的属性名称说明适用的控件
state_pressed是否按下按钮Button
state_checked是否勾选复选框CheckBox、单选按钮RadioButton
state_foused是否获取焦点文本编辑框EditText
state_selected是否选中各控件通用

选择按钮

复选框CheckBox

在学习复选框之前,先了解一下CompoundButton类。在Android体系中,CompoundButton类是抽象的符合按钮,因为是抽象类,所以它不能直接使用。在实际开发中用的是CompoundButton的几个派生类,主要有复选框CheckBox、单选按钮RadioButton以及开关按钮Switch,这些派生类均可使用CompoundButton的属性和方法。加之CompoundButton本身继承了Button类,故以上几种按钮同时具备Button的属性和方法,它们之间的继承关系如下图所示:
在这里插入图片描述

CompoundButton在XML文件中主要使用下面两个属性。

  • checked:指定按钮的勾选状态,true表示勾选,false则表示未勾选。默认为未勾选。
  • button:指定左侧勾选图标的图形资源,如果不指定就使用系统的默认图标。

CompoundButton在Java代码中主要使用下列4个方法。

  • setChecked:设置按钮的勾选状态。
  • setButtonDrawable:设置左侧勾选图标的图形资源。
  • setOnCheckedChangeListener:设置勾选状态变化的监听器。
  • isChecked:判断按钮是否勾选。

复选框CheckBox是CompoundButton一个最简单的实现控件,点击复选框将它勾选,再次点击取消勾选。复选框对象调用setOnCheckedListener方法设置勾选监听器,这样在勾选和取消勾选时就会触发监听器的勾选事件。
为了验证,页面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"><CheckBoxandroid:id="@+id/ck_system"android:layout_width="match_parent"android:layout_height="wrap_content"android:padding="5dp"android:checked="false"android:text="这是系统的CheckBox"android:textColor="@color/black"android:textSize="17sp" /><android.widget.CheckBoxandroid:id="@+id/ck_custom"android:layout_width="match_parent"android:layout_height="wrap_content"android:button="@drawable/checkbox_selector"android:padding="5dp"android:checked="false"android:text="这个CheckBox换了图标"android:textColor="@color/black"android:textSize="17sp" />
</LinearLayout>

复选框的状态有选中和没选中两种,图形XML文件checkbox_selector编写如下:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"><item android:state_checked="true" android:drawable="@drawable/check_choose" /><item android:drawable="@drawable/check_unchoose" />
</selector>

页面对应的java代码编写如下:

// 该页面实现了接口OnCheckedChangeListener,意味着重写勾选监听器的onCheckedChanged方法
public class CheckBoxActivity extends AppCompatActivity implements CompoundButton.OnCheckedChangeListener {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_check_box);// 给ck_system设置勾选监听器,一旦用户点击复选框,就触发监听器的onCheckedChanged方法((CheckBox)findViewById(R.id.ck_system)).setOnCheckedChangeListener(this);// 给ck_custom设置勾选监听器,一旦用户点击复选框,就触发监听器的onCheckedChanged方法((CheckBox)findViewById(R.id.ck_custom)).setOnCheckedChangeListener(this);}@Overridepublic void onCheckedChanged(CompoundButton compoundButton, boolean b) {String desc = String.format("您%s了这个CheckBox", b? "勾选":"取消勾选");compoundButton.setText(desc);}
}

运行App,不点击,两个复选框显示如下:
在这里插入图片描述
点击时,复选框变化如下:
在这里插入图片描述

开关按钮Switch

Switch是开关按钮,它像是一个高级版本的CheckBox,在选中与取消中时可展现的界面元素比复选框丰富。Switch控件新添加的XML属性说明如下:

  • textOn:设置右侧开启时的文本。
  • textOff:设置左侧关闭时的文本。
  • track:设置开关轨道的背景。
  • thumb:设置开关标识的图标。

虽然开关按钮时升级版的复选框,但它在实际开发中用的不多。原因之一是大家觉得Switch的默认界面不够美观,图标感觉有点小巧,效果如下:
在这里插入图片描述
不过我们可以使用CheckBox实现一个大气一点的开关按钮,通过借助状态列表图形,创建一个图形专用的XML文件,给状态列表指定选中与未选中时的开关图标,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"><item android:state_checked="true" android:drawable="@drawable/switch_on" /><item android:drawable="@drawable/switch_off" />
</selector>

然后把CheckBox标签的background属性设置为@drawable/switch_selector,同时将button属性设置为@null。完整的CheckBox标签内容如下:

 <CheckBoxandroid:id="@+id/ck_status"android:layout_width="60dp"android:layout_height="30dp"android:background="@drawable/switch_selector"android:button="@null" />

这里解释一下,为什么状态图片设置到android:background属性而不是android:button属性。因为android:button有局限性,无论图片多大,都只显示一个和我们设置的宽高大小的图片部分,因此我们在这还是设置图片到android:background。最后的效果如下图:
在这里插入图片描述

单选按钮RadioButton

单选按钮,指的是在一组按钮中选择一项不能多选。通过RadioGroup这个容器确定单选组的范围,同一组RadioButton都放在同一个RadioGroup下。可以通过RadioGroup的android:orientation属性指定下级控件的排列方向,该属性的值为horizontal时,单选按钮在水平方向排列;该属性的值为vertical时,单选按钮在垂直方向排列。
其实RadioGroup下面除了放RadioButton还可以放其他子控件(如TextView、ImageView等)。如此看来,单选按钮相当于特殊的线性布局,他们主要有以下两个区别:

  • 单选组多了管理单选按钮的功能,而线性布局不具备该功能。
  • 如果不指定orientation属性,那么单选组默认垂直排列,而线性布局默认水平排列

下面是RadioGroup在Java代码中3个常用的方法:

  • check:选中指定资源编号的单选按钮
  • getCheckedRadioButtonId:获取已经选中的单选按钮资源编号
  • setOnCheckedChangedListener:设置单选按钮勾选变化的监听器

与CheckBox不同的是,RadioButton默认未选中,点击后才会显示选中,再次点击不会取消选中。只有点击其他同组单选按钮时,原来选中的单选按钮才会取消选中。另外单选按钮的选中事件不是由RadioButton处理,而是由RadioGroup处理。
为了显示效果,我们活动页面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"android:padding="5dp"><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:text="请选择您的性别"android:textColor="@color/black"android:textSize="17sp" /><RadioGroupandroid:id="@+id/rg_sex"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal" ><RadioButtonandroid:id="@+id/rb_male"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:checked="false"android:text=""android:textColor="@color/black"android:textSize="17sp" /><RadioButtonandroid:id="@+id/rb_female"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:checked="false"android:text=""android:textColor="@color/black"android:textSize="17sp" /></RadioGroup><TextViewandroid:id="@+id/tv_sex"android:layout_width="match_parent"android:layout_height="wrap_content"android:textColor="@color/black"android:textSize="17sp" />
</LinearLayout>

界面对应的Java代码编写如下:

public class RadioHorizontalActivity extends AppCompatActivity implements RadioGroup.OnCheckedChangeListener {private TextView tv_sex; // 声明一个文本视图对象@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_radio_horizontal);// 从布局文件中获取视图控件tv_sextv_sex = findViewById(R.id.tv_sex);// 注册监听器,一旦点击组内单选按钮,就触发监听器的onCheckChanged方法((RadioGroup)findViewById(R.id.rg_sex)).setOnCheckedChangeListener(this);}@Overridepublic void onCheckedChanged(RadioGroup radioGroup, int checkedId) {if (R.id.rb_male == checkedId) {tv_sex.setText("性别为男");} else if (R.id.rb_female == checkedId) {tv_sex.setText("性别为女");}}
}

运行App,一开始没选中时页面显示如下,此时两个单选按钮均未选中:
在这里插入图片描述
单击单选按钮,则界面变化如下:
在这里插入图片描述

文本输入

编辑框EditText

编辑框EditText用于接收软键盘输入的文字,例如用户名、密码、评论内容等,它由文本视图派生而来,除了TextView已有的属性和方法外,EditText还支持下列XML属性。

  • inputType:指定输入的文本类型。输入类型的取值说明见下表,若同时使用多种类型,则可使用竖线(|)把多种文本类型拼接起来。
输入类型说明
text文本
textPassword文本密码。显示时用圆点(●)代替
number整型数
numberSigned带符号的数字。允许在开头带负号(-)
numberDecimal带小数点的数字
numberPassword数字密码。显示时用(●)代替
datetime时间日期格式。除了数字外,还允许输入横线(_)、斜杠(/)、空格( )、冒号(:)
date日期格式。除了数字外,还允许输入横线(_)和斜杠(/)
time时间格式。除了数字外,还允许输入冒号(:)
  • maxLength:指定文本允许输入的最大长度。
  • hint:指定提示文本的内容。
  • textColorHint:指定提示文本的颜色。

接下来进行效果验证,编写页面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:padding="5dp"android:orientation="vertical"><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="5dp"android:text="下面是登录信息"android:textColor="@color/black"android:textSize="17sp" /><EditTextandroid:layout_width="match_parent"android:layout_height="wrap_content"android:inputType="text"android:maxLength="10"android:hint="请输入用户名"android:textColor="@color/black"android:textSize="17sp" /><EditTextandroid:layout_width="match_parent"android:layout_height="wrap_content"android:inputType="textPassword"android:maxLength="8"android:hint="请输入密码"android:textColor="@color/black"android:textSize="17sp" /><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="10dp"android:text="下面是手机信息"android:textColor="@color/black"android:textSize="17sp" /><EditTextandroid:layout_width="match_parent"android:layout_height="wrap_content"android:inputType="number"android:maxLength="11"android:hint="请输入11位手机号码"android:textColor="@color/black"android:textSize="17sp" /><EditTextandroid:layout_width="match_parent"android:layout_height="wrap_content"android:inputType="numberPassword"android:maxLength="11"android:hint="请输入6位服密码"android:textColor="@color/black"android:textSize="17sp" />
</LinearLayout>

运行App后,进入初始的编辑界面如下图:
在这里插入图片描述
在XML文件中通过inputType属性对各个输入框的输入内容进行了限制,输入内容后,界面显示如下:
在这里插入图片描述

在实际开发中,我们可能有自定义输入框边框的需求,在输入与为输入时可能会显示两种不同边框以表示不同状态。那么此时就可以通过background属性,对两种状态进行修改。下面将演示默认边框、无边框和圆角矩形边框三种形态。
首先编写未输入(为获取焦点)时圆角矩形的形状图形文件,该文件显示灰色圆角矩形轮廓,对应的XML文件定义如下:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"><!--  指定形状内部填充的颜色  --><solid android:color="#ffffff" /><!--  指定了形状轮廓的粗细与颜色  --><strokeandroid:width="1dp"android:color="#aaaaaa" /><!--  指定了形状四个圆角的半径  --><corners android:radius="5dp" /><!--  指定了形状四个方向的间距  --><paddingandroid:bottom="2dp"android:left="2dp"android:right="2dp"android:top="2dp" />
</shape>

然后编写的是输入(获取焦点)时圆角矩形的形状图形文件,该文件显示蓝色圆角矩形轮廓,对应的XML文件定义如下:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"><!--  指定了形状内部的填充颜色  --><solid android:color="#ffffff" /><!--  指定了形状轮廓的粗细与颜色  --><strokeandroid:color="#0000ff"android:width="1dp" /><!--  指定了形状四个圆角的半径  --><corners android:radius="5dp" /><!--  指定了圆角四个方向的间距  --><paddingandroid:top="2dp"android:right="2dp"android:left="2dp"android:bottom="2dp" />
</shape>

接着编写编辑框的状态列表图形文件editext_selector,主要在selector节点下添加两个item:一个item设置了获取焦点时(android:state_focused="true")的图形为@drawable/shape_edit_focus;另一个item设置了图形@drawable/shape_edit_normal但未指定任何状态,表示其他状态都展示该图形。完整状态列表图形定义如下:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"><item android:state_focused="true" android:drawable="@drawable/shape_edit_focus" /><item android:drawable="@drawable/shape_edit_normal" />
</selector>

最后编写页面XML文件,一共有3个EditText控件:第一个采用默认编辑框;第二个将编辑框的background属性设置为@null表示不显示边框;第三个将background属性设置为@drawable/editext_selector,其背景由editext_selector.xml文件定义的状态列表图形决定。页面布局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:padding="5dp"android:orientation="vertical"><EditTextandroid:layout_width="match_parent"android:layout_height="wrap_content"android:inputType="text"android:hint="这是默认边框"android:textColor="@color/black"android:textSize="17sp" /><EditTextandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="5dp"android:inputType="text"android:hint="我的边框不见了"android:background="@null"android:textColor="@color/black"android:textSize="17sp" /><EditTextandroid:layout_width="match_parent"android:layout_height="wrap_content"android:inputType="text"android:hint="我的边框是圆角"android:background="@drawable/editext_selector"android:textColor="@color/black"android:textSize="17sp" />
</LinearLayout>

运行App,更换边框背景的编辑框界面显示如下:
在这里插入图片描述

焦点变更监听

当点击编辑框后,EditText当即获取焦点,此时就会发生焦点状态变更触发onFocusChange方法。编辑框的焦点,直观地看就是编辑框地光标闪动,哪个编辑框有光标,焦点就落在哪里。需要注意的是,编辑框比较特殊,要点击两次才会触发点击事件,因为第一次点击触发地是焦点变更。因此对于编辑框来说,一般都注册焦点监听器,而非点击监听器。
下面是以输入手机号码以及密码为例,给密码框注册焦点变更监听器地代码例子:

// 从布局文件中获取密码编辑框et_password
EditText et_password = findViewById(R.id.et_password);
// 给密码编辑框注册一个焦点变化监听器,一旦焦点发生变化,就触发onFocusChange方法
et_password.setOnFocusChangeListener(this);

为了能成功注册焦点变更监听器,还需要让活动实现接口View.OnFocusChangeListener,并重写该接口方法。我们的代码逻辑是,当密码输入框获取焦点时,判断手机号长度是否正确,不正确则将焦点重新设置到手机号输入框。焦点变更监听器的代码如下:

// 焦点变更事件的处理方法,hasFocus表示当前控件是否获得焦点。
// 为什么光标进入事件不选onClick?因为要点两下才会触发onClick动作(第一下是切换焦点动作)
@Override
public void onFocusChange(View view, boolean hasFocus) {// 判断密码编辑框是否获得焦点。hasFocus为true表示获得焦点,为false表示失去焦点if (view.getId()==R.id.et_password && hasFocus) {String phone = et_phone.getText().toString();if (TextUtils.isEmpty(phone) || phone.length()<11) {// 手机号码编辑框请求焦点,也就是把光标移回手机号码编辑框et_phone.requestFocus();Toast.makeText(this, "请输入11位手机号码", Toast.LENGTH_SHORT).show();}}
}

运行App,当手机输入框数据长度不够时,点击密码输入框弹出提示如下:
在这里插入图片描述

文本变化监听器

有时我们在输入账号密码时,可能在我们输入内容后想直接点击登录而不必点击键盘的Enter键收起键盘后再点击登录。那么我们只需要在满足某些条件后关闭软键盘即可,例如手机号码输入满11位或者密码输入满6位,等等。
现在明确需求条件后,达到指定长度关闭软键盘功能,现在我们可以分解为功能点:一个是如何关闭软键盘;另一个是如何判断已输入的文字是否达到指定字数。分别说明如下:

  1. 如何关闭软键盘
    输入法键盘由系统服务Context.INPUT_METHOD_SERVICE管理,所以关闭键盘也要由该服务处理,下面是使用系统服务关闭软键盘代码样例:
public static void hideOneInputMethod(Activity act, View v) {// 从系统服务中获取输入法管理器InputMethodManager imm = (InputMethodManager) act.getSystemService(Context.INPUT_METHOD_SERVICE);// 关闭屏幕上的输入法软键盘imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}

注意上述代码里面的视图对象v,虽然控件类型是View,当他必须是EditText类型才能正常关闭软键盘。

  • 如何判断已输入的文字是否达到指定位数
    该功能点需要实时监控当前输入的文本长度,这个监控操作用到文本监听器接口TextWatcher,该接口提供3个监控方法,具体如下:
  • beforeTextChanged:在文本改变之前触发
  • onTextChanged:在文本改变过程中触发
  • afterTextChanged:在文本改变之后触发

具体代码中需要自己实现接口TextWatcher,再调用编辑框对象的addTextChangedListener方法注册文本监听器。监听操作建议在afterTextChanged方法中完成,同时监听11位手机号和6位密码,一旦输入长度达到指定长度就关闭软键盘,详细监听器代码如下:

// 定义一个编辑框监听器,在输入文本达到指定长度时自动隐藏输入法
private class HideTextWatcher implements TextWatcher {private EditText mView; // 声明一个编辑框对象private int mMaxLength; // 声明一个最大长度变脸HideTextWatcher(EditText editText, int maxLength) {super();mView = editText;mMaxLength = maxLength;}// 在编辑框的输入文本变化前触发@Overridepublic void beforeTextChanged(CharSequence charSequence, int start, int count, int after) {}// 在编辑框的输入文本变化时触发@Overridepublic void onTextChanged(CharSequence charSequence, int start, int before, int count) {}// 在编辑框的输入文本变化后触发@Overridepublic void afterTextChanged(Editable editable) {String str = editable.toString(); // 获取已输入的文本字符// 输入字符串长11位(手机号),或者达6位(密码)时关闭输入法if ((11 == str.length() && 11 == mMaxLength) || (6 == str.length() && 6 == mMaxLength)) {ViewUtil.hideOneInputMethod(EditHideActivity.this, mView);}}
}

写好监听器代码,还要给手机编辑框和密码编辑框分别注册监听器,注册代码示例如下:

// 获取编辑框et_phone
EditText et_phone = findViewById(R.id.et_phone);
// 获取编辑框et_password
EditText et_password = findViewById(R.id.et_password);
// 给手机号编辑框添加文本变化监听器
et_phone.addTextChangedListener(new HideTextWatcher(et_phone, 11));
// 给密码编辑框添加文本变化监听器
et_password.addTextChangedListener(new HideTextWatcher(et_password, 6));

运行App,输入手机号,但手机号长度没达到11位时软键盘依旧显示,如下图:
在这里插入图片描述
当输入总长度达11位后,软键盘收起,如下图:
在这里插入图片描述

对话框

提醒对话框AlertDialog

AlertDialog名为提醒对话框,它是Android中最常用的对话框,可以完成常见的交互操作,例如提示、确认、选择等功能。由于AlertDialog没有公开的构造方法,因此必须借助建造器AlertDialog.Builder才能完成参数设置,AlertDialog.Builder常用方法如下:

  • setIcon:设置对话框的标题图标。
  • setTitle:设置对话框的标题文本。
  • setMessage:设置对话框的内容文本。
  • setPositiveButton:设置肯定按钮的信息,包括按钮文本和监听器。
  • setNegativeButton:设置否定按钮的信息,包括按钮文本和监听器。
  • setNeturalButton:设置中性按钮的信息,包括按钮文本和点击监听器,该方法比较少用。

通过AlertDialog.Builder设置完成对话框参数,还需要调用建造器的create方法才能生成对话框实例。最后调用对话框实例的show方法,在页面上弹出提醒对话框。
下面是构建并显示提醒对话框的Java代码例子:

// 创建提示对话框的建造器
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("尊敬的用户"); // 设对话框标题
builder.setMessage("你真的要卸载我吗?"); // 设置对话框的提示内容
// 设置对话框的肯定按钮文本及其监听器
builder.setPositiveButton("残忍卸载", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialogInterface, int which) {tv_alert.setText("虽然依依不舍,但是只能离开了");}
});
// 设置对话框的否定按钮文本及其监听器
builder.setNegativeButton("我再想想", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialogInterface, int which) {tv_alert.setText("让我再陪你三百六十五个日夜");}
});
AlertDialog alert = builder.create(); // 根据构造器构建提醒对话框对象
alert.show();

提示对话框如下图所示,可以看见对话框由标题和内容,还有两个按钮:
在这里插入图片描述

日期对话框DatePickerDialog

系统专门提供了日期选择器DatePicker ,供用户选择具体的年、月、日。不过,DatePicker并非弹窗模式,而是在当前页面占据一块区域,并且不会自动关闭。使用习惯上,日期控件应该是需要时弹出,使用完毕后关闭。因此,界面上很少直接显示DatePicker,而是通过系统封装好的DatePickerDialog实现。
DatePickerDialog相当于在AlertDialog上装载了DatePicker,编码时只需要调用构造方法设置当前的年、月、日,然后调用show方法即可弹出日期对话框。日期选择事件则由监听器DatePickerDialog.OnDateSetListener负责响应,在该监听器的onDateSet方法中,开发者获取用户选择的具体日期,再做后续处理。需要注意的是,onDateSet方法的月份参数,它的起始值是从0开始的,也就是说一月份对应的数值是0而十二月份对应的数值是11,中间值以此类推。
在界面上嵌入DatePicker的效果如下图所示:
在这里插入图片描述
单独弹出日期对话框的效果如下图所示效果:
在这里插入图片描述
下面是使用日期对话框的Java代码例子,包括弹出日期对话框和处理日期监听事件:

// 该页面类实现了接口OnDateSetListener,意味着要重写日期监听器的onDateSet方法
public class DatePickerActivity extends AppCompatActivity implementsView.OnClickListener, DatePickerDialog.OnDateSetListener {private TextView tv_date; // 声明一个文本控件private DatePicker dp_date; // 声明一个日期选择器对象@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_date_picker);// 从布局文件中获取文本控件tv_datetv_date = findViewById(R.id.tv_date);// 从布局文件中获取日期选择器dp_datedp_date = findViewById(R.id.dp_date);findViewById(R.id.btn_date).setOnClickListener(this);findViewById(R.id.btn_ok).setOnClickListener(this);}@Overridepublic void onClick(View view) {if (R.id.btn_date == view.getId()) {// 获取日历的一个实例,里面包含了当前的年月日Calendar calendar = Calendar.getInstance();// 构建一个日期对话框,该对话框已经集成了日期选择器// DatePickerDialog的第二个参数指定了日期监听器DatePickerDialog dialog = new DatePickerDialog(this, this,calendar.get(Calendar.YEAR),  // 年份calendar.get(Calendar.MONTH), // 月份calendar.get(Calendar.DATE)); // 日子dialog.show(); // 显示日期对话框} else if (R.id.btn_ok == view.getId()) {// 获取日期选择器dp_date设定的年月份String desc = String.format("您选择的日期是%d年%d月%d日",dp_date.getYear(), dp_date.getMonth() + 1, dp_date.getDayOfMonth());tv_date.setText(desc);}}@Overridepublic void onDateSet(DatePicker datePicker, int year, int monthOfYear, int dayOfMonth) {// 获取日期对话框设定的年月份String desc = String.format("您选择的日期是%d年%d月%d日",year, monthOfYear + 1, dayOfMonth);tv_date.setText(desc);}
}

时间对话框TimePickerDialog

安卓同样给开发者提供了时间选择。同样的,在实际开发中也不常直接用TimePicker,而是用封装好的时间选择器对话框TimePickerDialog。该对话框的用法类似DatePickerDialog,不同之处主要有以下两点:

  1. 构造方法传入的是当前的小时和分钟,最后一个参数表示是否采取24小时制,true表示小时的数值取值0~23;若为false则表示采取的12小时制。
  2. 时间选择监听器为TimePickerDialog.OnTimeSetListener,对应的实现方法为onTimeSet,在该方法中可获得用户选择得小时和分钟。

在界面上显示的TimePicker效果如下图所示:
在这里插入图片描述
单独弹出的小时和分钟按照钟表的形式显示如下:
在这里插入图片描述

下面是使用时间对话框的Java代码,包括弹出时间对话框和处理时间监听事件:

// 该页面类实现了接口OnTimeSetListener,意味着要重写时间监听器的onTimeSet方法
public class TimePickerActivity extends AppCompatActivity implementsView.OnClickListener, TimePickerDialog.OnTimeSetListener {private TextView tv_time; // 声明一个文本对象private TimePicker tp_time; // 声明一个时间选择器对象@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_time_picker);// 从布局文件中获取文本对象tv_timetv_time = findViewById(R.id.tv_time);// 从布局文件中获取时间选择器对象tp_timetp_time = findViewById(R.id.tp_time);findViewById(R.id.btn_time).setOnClickListener(this);findViewById(R.id.btn_ok).setOnClickListener(this);}@Overridepublic void onClick(View view) {if (R.id.btn_time == view.getId()) {// 获取日历的一个实例,里面包含当前的分秒Calendar calendar = Calendar.getInstance();// 创建一个对话框,该对话框已经集成了时间选择器// TimePickerDialog的第二个参数指定了时间监听器TimePickerDialog dialog = new TimePickerDialog(this, this,calendar.get(Calendar.HOUR_OF_DAY), // 小时calendar.get(Calendar.HOUR_OF_DAY), // 分钟true);  // 使用24小时制;false表示12小时制dialog.show(); // 显示时间对话框} else if (R.id.btn_ok == view.getId()) {// 获取定时器tp_time的时间String desc = String.format("您选择的时间是%d时%d分",tp_time.getHour(), tp_time.getMinute());tv_time.setText(desc);}}// 一旦点击时间对话框上的确定按钮,就会触发监听器的onTimeSet方法@Overridepublic void onTimeSet(TimePicker timePicker, int hourOfDay, int minute) {// 获取时间对话框设定的小时和分钟String desc = String.format("您选择的时间是%d时%d分", hourOfDay, minute);tv_time.setText(desc);}
}

工程源码

所有样例代码都可点击工程源码下载。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/661799.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

spring-boot示例

spring-boot版本&#xff1a;2.0.3.RELEASE 数据库: H2数据库 &#xff08;嵌入式内存性数据库&#xff0c;安装简单&#xff0c;方便用于开发、测试&#xff0c;不适合用于生产&#xff09; mybatis-plus框架&#xff0c;非常迅速开发CRUD

【LAMMPS学习】八、基础知识(5.3)Body particles体粒子

8. 基础知识 此部分描述了如何使用 LAMMPS 为用户和开发人员执行各种任务。术语表页面还列出了 MD 术语&#xff0c;以及相应 LAMMPS 手册页的链接。 LAMMPS 源代码分发的 examples 目录中包含的示例输入脚本以及示例脚本页面上突出显示的示例输入脚本还展示了如何设置和运行各…

TCP/IP和HTTP协议

TCP/IP OSI 七层模型在提出时的出发点是基于标准化的考虑&#xff0c;而没有考虑到具体的市场需求&#xff0c;使得该模型结构复杂&#xff0c;部分功能冗余&#xff0c;因而完全实现 OSI 参考模型的系统不多。而 TCP/IP 参考模型直接面向市场需求&#xff0c;实现起来也比较…

java:错误:不支持发行版本

你在运行的时候是否遇见过这样的问题: 有时候新建一个Java项目后&#xff0c;运行起来就会提示这样的错误。主要原因是因为项目使用的Java版本和安装的Java版本不符合 &#xff0c;在这里总结一下解决方法: 首先点击file的project 把Java编译器也设置成 一样的版本 即可解决问…

计算机毕业设计python_django宠物领养系统z6rfy

本宠物领养系统主要包括两大功能模块&#xff0c;即管理员模块、用户模块。下面将对这两个大功能进行具体功能需求分析。 &#xff08;1&#xff09;管理员&#xff1a;管理员登录后主要功能包括个人中心、用户管理、送养宠物管理、地区类型管理、失信黑名单管理、申请领养管理…

c#数据库: 4.修改学生成绩

将4年级的学生成绩全部修改为100分,。修改前的学生信息表如图所示: using System; using System.Collections.Generic; using System.Data.SqlClient; using System.Linq; using System.Text; using System.Threading.Tasks;namespace StudentUpdate {internal class Program{s…

麒麟服务器操作系统SP3如何设置GRUB密码

原文链接&#xff1a;麒麟服务器操作系统SP3如何设置GRUB密码 Hello&#xff0c;大家好啊&#xff01;为了增强系统的安全性&#xff0c;设置GRUB&#xff08;GNU GRand Unified Bootloader&#xff09;密码是一个非常有效的方法。这可以防止未经授权的用户修改启动参数或使用恢…

面试二十四、继承多态

一、继承的本质和原理 组合&#xff08;Composition&#xff09;&#xff1a; 组合是一种"有一个"的关系&#xff0c;表示一个类包含另一个类的对象作为其成员。这意味着一个类的对象包含另一个类的对象作为其一部分。组合关系通常表示强关联&#xff0c;被包含的对象…

idea No versioned directories to update were found

idea如何配置svn以及svn安装时需要注意什么 下载地址&#xff1a;https://112-28-188-82.pd1.123pan.cn:30443/download-cdn.123pan.cn/batch-download/123-820/3ec9445a/1626635-0/3ec9445a25ba365a23fc433ce0c16f34?v5&t1714358478&s171435847804276f7d9249382ba512…

翻译: 什么是ChatGPT 通过图形化的方式来理解 Transformer 架构 深度学习二

合集 ChatGPT 通过图形化的方式来理解 Transformer 架构 翻译: 什么是ChatGPT 通过图形化的方式来理解 Transformer 架构 深度学习一翻译: 什么是ChatGPT 通过图形化的方式来理解 Transformer 架构 深度学习二翻译: 什么是ChatGPT 通过图形化的方式来理解 Transformer 架构 深…

PHP定时任务框架taskPHP3.0学习记录7宝塔面板手动可以执行自动无法执行问题排查及解决方案(sh脚本、删除超过特定天数的日志文件、kill -9)

PHP定时任务框架taskPHP3.0学习记录 PHP定时任务框架taskPHP3.0学习记录1&#xff08;TaskPHP、执行任务类的实操代码实例&#xff09;PHP定时任务框架taskPHP3.0学习记录2&#xff08;环境要求、配置Redis、crontab执行时间语法、命令操作以及Screen全屏窗口管理器&#xff0…

算法:双指针题目练习

目录 题目一&#xff1a;移动零 题目二&#xff1a;复写零 题目三&#xff1a;快乐数 题目四&#xff1a;盛最多水的容器 题目五&#xff1a;有效三角形的个数 题目六&#xff1a;和为s的两个数字(剑指offer) 题目七&#xff1a;三数之和 题目八&#xff1a;四数之和 常…