本章会介绍Android程序界面和很多组件的知识,是界面需要的知识。
通过学习本章的知识,可以开发出漂亮的图形用户界面,这些图形用户界面是Android应用开发的基础,也是非常重要的组成部分。
Android的绝大部分UI组件在android.widget包及其子包、android.view包及其子包中,Android的所有UI组件都继承于View类。
View类有一个重要的子类:ViewGroup,但是ViewGroup通常作为其他组件的容器使用。
Android推荐使用XML布局文件来定义用户界面,而不是使用Java代码来开发用户界面,提供了两种方式来控制组件的行为:
ViewGroup继承了View类,主要作为容器类使用,实际使用中通常是使用ViewGroup的子类来作为容器,例如布局管理器。
ViewGroup容器控制其子组件的分布依赖于ViewGroup.layoutParams、ViewGroup.MarginLayoutParams两个内部类。这两个内部类中提供了一些XML属性。
android:layout_height、android:layout_width两个属性支持两个属性值:
在Android应用的res/layout目录下定义一个主文件名的XML布局文件,在Java代码中通过如下方法在Activity中显示该视图:
setContentView(R.layout.<资源文件名字>);
当在布局文件中添加多个UI组件时,可以为该UI组件指定android:id属性,该属性的属性值代表该组件的唯一标识,在Java代码中访问指定的UI组件,可通过如下代码来访问:
findViewById(R.id.);
比较麻烦,并且不利于代码解耦,所以这里不展示。
可以混合使用XML布局文件和代码来控制UI界面,习惯上把变化小、行为比较固定的组件放在XML布局文件中进行管理,而那些变化较多、行为控制比较复杂的组件则用Java代码管理。
路径:~/res/layout/main.xml
下面在程序中获取该线性布局容器,并往该容器中添加组件。
package com.example.myapplication;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Toast;
import androidx.annotation.Nullable;
public class MixView extends Activity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MixView.this,"Button",Toast.LENGTH_SHORT).show();
}
});
}
}
基于Android UI组件的实现原理,开发者完全可以开发出项目定制的组件——通过继承View来派生自定义组件。
当开发者打算派生自己的UI组件时,首先定义一个继承View基类的子类,然后重写View类的一个或多个方法,可以被重写的方法如下。
构造器:
重写构造器是定制View的最基本方式,当Java代码创建一个View实例,或根据XML布局文件加载并构建界面时将需要调用该构造器。
当需要开发自定义view时,不需要重写上面列出来的所有方法,可以根据业务需要重写上面的部分方法。
实现一个跟随手指的小球。
DrawView.java
package com.example.myapplication;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.View;
public class DrawView extends View {
public float currentX = 40;
public float currentY = 50;
public DrawView(Context context){
super(context);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint p = new Paint();
p.setColor(Color.RED);
canvas.drawCircle(currentX,currentY,15,p);
}
}
上面的DrawView组件继承了View基类,并重写了onDraw方法——该方法负责在该组件的指定位置绘制一个小球。
接下来通过java代码将该组件添加到指定容器中。
MixView.java
package com.example.myapplication;
import android.app.Activity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Toast;
import androidx.annotation.Nullable;
public class MixView extends Activity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
LinearLayout root = (LinearLayout) findViewById(R.id.root);
final DrawView draw = new DrawView(this);
draw.setMinimumWidth(300);
draw.setMinimumHeight(500);
draw.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
//修改draw组件的currentX和currentY两个属性
draw.currentX = motionEvent.getX();
draw.currentY = motionEvent.getY();
//通知draw组件重新绘制
draw.invalidate();
//返回true表明处理方法已经处理该事件
return true;
}
});
root.addView(draw);
}
}
先创建了自定义组件的实例,然后为该组件绑定了一个onTouchListener监听触摸屏事件的监听器。手指在触摸屏上移动时,会不断触发触摸屏事件,事件监听器中负责触发事件的坐标会传到DrawView组件,并通知该组件重新绘制。
结果
通过使用布局管理器,Android应用的图形用户界面具有良好的平台无关性。
布局管理器可以根据运行平台来调整组件的大小,程序员要做的,只是为容器选择合适的布局管理器。
布局管理器的具体内容见:基本布局
在界面布局中指定各个组件的android:layout_x等属性时会执行形如20dip这样的属性值,这时一个距离值。
Android中一般支持如下常用的距离单位:
px(像素):每个px对应屏幕上的一个点
dip或dp:一种基于屏幕密度的抽象单位。在每英寸160点的显示屏上,1dip = 1px。但是随着屏幕密度的改变,dip与px之间的换算会发生变化。
sp比例像素:主要处理字体大小,可以根据用户的字体大小首选项进行缩放。
in英寸:标准长度单位。
mm毫米:标准长度单位。
pt磅:标准长度单位,1/72英寸。
TextView直接继承了View,是EditText、Button两个UI组件类的父类。
TextView的作用是在界面上显示文本。
如果开发者想要定义一个可以编辑内容的文本框,可以使用EditText,它允许用户编辑文本框中的内容。
TextView提供了大量的XML属性,这些XML属性大部分可以适用于TextView和EditText。
其中的android:autoLink属性值是如下几个属性值的一个或几个,多个属性值之间用竖线隔开。
none:不设置任何超链接
web:将文本中的URL地址转换成超链接
email:将文本中的email地址转换成超链接
phone:将文本中的电话号码转换成超链接
map:将文本中的街道地址转换成超链接
all:相当于指定web|email|phone|map
android:ellipsize属性可以支持如下几个属性值:
none:不进行任务处理
start:在文本开头部分进行省略
middle:在文本中间部分进行省略
end:在文本结尾处进行省略
marquee:在文本结尾处以淡出的方式省略
示例:
不管是Button还是ImageButton,它们的功能都很单一,主要是在UI界面上生成一个按钮,该按钮可以单击,当用户单击按钮时,会触发一个onClick事件。
Button和ImageButton的区别:
Button生成的按钮上显示文字
ImageButton生成的按钮上显示图片
Android中的RadioButton和CheckBox都继承了Button按钮,可以直接使用Button支持的各种属性和方法。
它们多了一个可选中的功能,因此RadioButton、CheckBox都可以额外指定一个android:checked属性,该属性用于指定RadioButton、CheckBox初始时是否被选中。
一组RadioButton只能选中其中一个,因此RadioButton通常要与RadioGroup一起使用,用于定义一组单选按钮。
示例:
在需要获取用户信息的界面中,有些信息不需要用户直接输入,可以考虑让用户进行选择,比如用户的性别、爱好等。我们先只显示用户的性别:
结果:
从界面上看,它与CheckBox复选框非常相似,它们都可以提供两个状态。
ToggleButton主要用于切换程序中的某种状态。
XML属性 | 相关方法 | 说明 |
---|---|---|
android:checked | setChecked(boolean) | 设置该按钮是否被选中 |
android:textOff | 设置该按钮没有被选中时显示的文本 | |
android:textOn | 设置该按钮被选中时显示的文本 |