AndroidUI组件
Q7nl1s admin

主要内容:
◼ 界面布局
◼ 常用UI组件编程
◼ 多种监听器用法
◼ ImageView图像加载方法
◼ Adapter适配器
◼ 自定义布局
◼ Handler.postDelayed定时器
◼ CountDownTimer倒计时
◼ ExoPlayer媒体播放器

image-20230320205105136

界面布局

◼ 新建一个Module(相当于新app)
◼ 应用名称为:UIDemo
◼ Activity默认:MainActivity

新建Module时注意命名:

image-20230320205145777

界面布局

◼ 布局作用:
◼ 将应用的外观代码(xml)与控制其行为的代码(java)分开(表现层和控制层分离),调整用户界面时,无需更改程序的源代码。
◼ 基本布局:
◼ 约束布局 ConstraintLayout
◼ 线性布局 LinearLayout

image-20230320205341884

1.ConstraintLayout

◼ 默认布局,依靠约束关系来确定位置
◼ 能够灵活定位和调整界面元素的大小
◼ 无任何嵌套,减少布局层级,优化渲染性能
◼ 能完全代替其他布局

image-20230320205703047

基线对齐示例:

image-20230320205721053

2.LinearLayout

◼ 线性布局:界面元素都在一行(水平方向)或一列(垂直方向),可嵌套
◼ 通过 android:orientation 属性指定布局方向:
android:orientation="horizontal" 水平布局 (默认)
android:orientation="vertical" 垂直布局

线性布局示例:

image-20230320205523458

◼ 嵌入一个垂直布局
• android:orientation = “vertical”
• android:layout_width = “match_parent”
• android:layout_height = “wrap_content”
• android:gravity = “center_horizontal”

改为”horizontal” 水平布局

View 与 ViewGroup 的概念

◼ Android中所有的UI元素都是使用View和ViewGroup对象建立的。
◼ View是一个可以将一些信息绘制在屏幕上并与用户产生交互的对象。例如Button、TextView等
◼ ViewGroup是一个包含多个的View和ViewGroup的容器,用来定义UI布局。例如ConstraintLayout、LinearLayout、RadioGroup等。
◼ View类作为界面开发的超类,所有的界面开发都与View有关。

image-20230320205820363

常用UI组件

基本属性

基本属性 描述
id 组件唯一标识
layout_width 组件的宽度
layout_height 组件的高度
text 文本内容
textColor 字体颜色
textSize 字体大小 ==注:字体大小默认单位为 sp,宽高默认单位是 dp==
textStyle 字体样式(normal|bold|italic)
backgroundTint 背景颜色
gravity 内部元素对齐方式:left|center|right|center_horizontal|center_vertical等(父容器要求子元素如何对齐)
layout_gravity 容器中的子元素相对父容器的对齐方式(取值同上)
layout_weight 用来分配空间占比权重(常用于线性布局 + layout_width=”0dp”配合)

layout_width 和 layout_height 为必填的2个属性,可以设置数值(dp),也可以使用:
wrap_content:根据内容自动扩展以适应内容大小
match_parent:控件大小填满整个父容器

ayout_weight 宽度占比示例:

image-20230320210637847

1.TextView

image-20230320210731869

常用属性 描述
background 背景颜色(或背景图片)
autoLink 文本自动识别为web超链接、Email地址等
image-20230320211007911

autoLink 用法

image-20230320211246869

常用方法

1
2
3
4
5
6
7
◼ 示例:
TextView tv = (TextView) findViewById(R.id.***);
String str = tv.getText().toString(); //获取文本内容,需要转换为字符串
tv.setText("hello"); //设置文本内容
tv.setTextSize(30); //设置文字大小,默认单位是sp
tv.setTextColor(Color.BLUE); //设置文本颜色
// 颜色值还可用 Color.rgb(255, 0, 0) 或 Color.parseColor("#0000ff")

示例:TextViewActivity

image-20230320211511624

activity_text_view.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".TextViewActivity">
<TextView
android:id="@+id/tv1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="124dp"
android:autoLink="web"
android:text="https://www.wust.edu.cn"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:autoLink="email"
android:text="zhangzhi@wust.edu.cn"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.502"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv1" />
<TextView
android:id="@+id/tv3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:autoLink="phone"
android:text="+8613012345678"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.497"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv2" />
<TextView
android:id="@+id/tv4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:autoLink="map"
android:text="620 Eighth Avenue New York, NY 10018"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.497"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv3" />
<TextView
android:id="@+id/tv5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="60dp"
android:autoLink="map"
android:text="welcome"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.491"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv4" />
<Button
android:id="@+id/btn_change"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="修改welcome"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv5" />
</androidx.constraintlayout.widget.ConstraintLayout>

TextViewActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class TextViewActivity extends AppCompatActivity {
Button btn;
TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_text_view);
ActionBar actionBar = getSupportActionBar();
actionBar.setTitle("TextView示例"); //设置标题
actionBar.setDisplayHomeAsUpEnabled(true); //返回箭头按钮
tv=findViewById(R.id.tv5);
btn=findViewById(R.id.btn_change);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
tv.setText("武汉科技大学"); //设置文本内容
tv.setTextSize(22); //设置文字大小,默认单位是sp
tv.setTextColor(Color.BLUE); //设置文本颜色
}
});
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()){
case android.R.id.home: /*返回按钮id*/
finish();
}
return super.onOptionsItemSelected(item);
}
}

2.EditText

image-20230320211920432

常用属性 描述
hint 提示信息
textColorHint 提示信息的颜色
inputType 输入类型(number|textPassword|numberPassword … )
image-20230320212415446
maxLength 文本最大长度
digits 允许输入的字符 (如digits=”abcd” 只能输入abcd这4个小写字母)
多行文本设置
inputType “textMultiLine” //显示多行
minLines “3” //最小显示3行
gravity “left|top” // 输入时光标位于左上角

inputType 取值不同:会使得输入键盘不同

image-20230320212112963

常用方法

◼ 示例:

1
2
3
EditText et = (EditText) findViewById(R.id.***);
String msg = et.getText().toString(); //获取文本内容
et.setText("hello"); //设置文本内容

示例:EditTextActivity

image-20230320212208797

activity_edit_text.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".EditTextActivity">
<EditText
android:id="@+id/et_phone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:ems="10"
android:hint="11位手机号"
android:inputType="phone"
android:maxLength="11"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/et_password"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:ems="10"
android:hint="6位密码"
android:inputType="numberPassword"
android:maxLength="6"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.497"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/et_phone" />
<EditText
android:id="@+id/et_multitext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:ems="10"
android:hint="个人简介"
android:inputType="textMultiLine"
android:minLines="3"
android:gravity="top|left"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.502"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/et_password" />
<Button
android:id="@+id/btn_getdata"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="获取输入值"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/et_multitext" />
</androidx.constraintlayout.widget.ConstraintLayout>

EditTextActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public class EditTextActivity extends AppCompatActivity {
EditText phone;
EditText password;
EditText info;
Button btn;
String s_phone;
String s_password;
String s_info;
View.OnClickListener listener = new View.OnClickListener() {
@Override
public void onClick(View v) {
s_phone = phone.getText().toString(); //获取输入的值
s_password = password.getText().toString();
s_info = info.getText().toString();
new AlertDialog.Builder(EditTextActivity.this)
.setTitle("输入的数据:")
.setMessage("电话:" + s_phone + "\n密码:" + s_password + "\n个人简介:\n" + s_info)
.setNegativeButton("取消", null)
.show();
}
};
public void initView() {
phone = findViewById(R.id.et_phone);
password = findViewById(R.id.et_password);
info = findViewById(R.id.et_multitext);
btn = findViewById(R.id.btn_getdata);
btn.setOnClickListener(listener);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit_text);
initView();
ActionBar actionBar = getSupportActionBar(); //获取ActionBar
actionBar.setTitle("TextView示例"); //设置标题
actionBar.setDisplayHomeAsUpEnabled(true); //在ActionBar最左边显示返回上一层箭头按钮
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
finish();
}
return super.onOptionsItemSelected(item);
}
}

3.ImageView

image-20230320212532636

常用属性 描述
srcCompat 图片源
scaleType 图片缩放类型,常用取值:center、centerCrop、centerInside、fitCenter、fitEnd、fitStart、fitXY、matrix等
image-20230320212922093

scaleType 取值

取值 描述
fitCenter 保持图片的宽高比,对图片进行X和Y方向缩放,直到一个方向铺满ImageView。缩放后图片居中显示。(默认)
fitXY 对X和Y方向独立缩放,直到图片铺满ImageView。这种方式可能会改变图片原本的宽高比,导致图片拉伸变形。
fitStart 保持图片的宽高比,对图片进行X和Y方向缩放,直到一个方向铺满ImageView。缩放后图片左上角对齐进行显示。
fitEnd 保持图片的宽高比,对图片进行X和Y方向缩放,直到一个方向铺满ImageView。缩放后图片右下角对齐进行显示。
center 图片居中显示在ImageView中,不对图片进行缩放。
centerInside 如果图片宽度<=ImageView宽度&&图片高度<=ImageView高度,不执行缩放,居中显示在ImageView中。其余情况按ScaleType.FIT_CENTER处理。
centerCrop 保持图片的宽高比,等比例对图片进行X和Y方向缩放,直到每个方向都大于等于ImageView对应的尺寸。缩放后的图片居中显示,超出部分做裁 剪处理。
matrix 使用Matrix绘制图片

image-20230320213126237

image-20230320213144074

常用方法

◼ 示例:

1
2
3
4
5
6
7
ImageView iv = (ImageView) findViewById(R.id.***);
iv.setVisibility( View.INVISIBLE ); //隐藏图片框
❤ 动态加载图片的重要方法:
(1) iv.setImageResource(R.drawable.图片资源) //直接加载图片资源
(2) iv.setImageDrawable( getDrawable(R.drawable.图片资源) );
(3) iv.setImageURI(Uri uri) / /通过图片URI地址加载图片
(4) iv.setImageBitmap(Bitmap bitmap) //加载bitmap对象

示例:ImageViewActivity

image-20230320213304043

定时器用法:Handler.postDelayed(Runnable, long) 方法

定时器基本架构

1
2
3
4
5
6
7
8
9
10
11
12
Handler handler = new Handler(); // Handler是消息处理器
Runnable runnable = new Runnable() { // Runnable是子线程
@Override
public void run() {
//要做的事情
handler.postDelayed( this, m ); // m毫秒后再执行一次当前runnable(重复做时需要)
}
};
// 启动计时器:
handler.postDelayed( runnable, n ); // n毫秒后执行一次runnable
// 取消定时器:
handler.removeCallbacks( runnable );

注:postDelayed 函数没每次调用只执行一次,所以要使用递归

activity_image_view.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ImageViewActivity">
<ImageView
android:id="@+id/iv_photo"
android:layout_width="174dp"
android:layout_height="180dp"
android:layout_marginTop="184dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.496"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/login" />
<Button
android:id="@+id/btn_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="53dp"
android:text="启动定时器"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/iv_photo" />
<Button
android:id="@+id/btn_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="关闭定时器"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.501"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn_start" />
</androidx.constraintlayout.widget.ConstraintLayout>

ImageViewActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public class ImageViewActivity extends AppCompatActivity {
ImageView imageView;
Button btn1, btn2;
int idx = 0;
int[ ] resIds = new int[ ]{ R.drawable.lstx_001, R.drawable.lstx_002,
R.drawable.lstx_003, R.drawable.lstx_004 };
Handler handler = new Handler();
Runnable runnable = new Runnable() {
@Override
public void run() {
imageView.setImageResource(resIds[idx]);
if (idx < resIds.length - 1) {
idx++;
} else {
idx = 0;
}
handler.postDelayed(this, 2000); // 2秒后执行当前runnable
}
};
View.OnClickListener listener = new View.OnClickListener() {
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_start:
handler.postDelayed(runnable, 2000); // 2秒后执行一次Runnable
break;
case R.id.btn_cancel:
handler.removeCallbacks(runnable); // 关闭定时器
break;
}
}
};
public void initView() {
imageView = findViewById(R.id.iv_photo);
btn1 = findViewById(R.id.btn_start);
btn2 = findViewById(R.id.btn_cancel);
btn1.setOnClickListener(listener);
btn2.setOnClickListener(listener);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_image_view);
initView();
}
}

4.Button 和 ImageButton

按钮类型 描述
Button image-20230321160001779 普通按钮(仅包含文本)
ImageButton image-20230321160016443 图片按钮(仅包含图标)

◼ srcCompat属性:设置图片源
◼ scaleType属性:同ImageView
◼ 配合backgroundTint = “#00000000” (8个0) 可以透明png图片背景 ==会导致点击没有波纹效果==
◼ 动态修改图片:setImageDrawable(getDrawable(R.drawable.***));
Button组件 image-20230321160051846 包含文本和图标按钮

◼ text属性:文本内容
◼ drawableLeft属性:设置图片源(图片在文字左侧)

drawableLeft 属性

drawableRight 属性:图片在文字右侧
drawableTop 属性:图片在文字上方
drawableBottom 属性:图片在文字下方

按钮监听器:单击事件响应

1
2
3
4
5
6
7
Button btn = (Button) findViewById(R.id.***);
bt.setOnClickListener( new View.OnClickListener() { // ImageButton也用这个监听器
@Override
public void onClick(View v) {
// 代码
}
});

禁用按钮方法:

1
2
btn.setEnabled( false ); //按钮将不再响应点击、触摸以及键盘事件等,处于完全被禁用的状态
btn.setEnabled( true ); //恢复按钮

示例:ButtonActivity

image-20230321160330365

(1) 文字颜色:Button 按下状态改变文字颜色

image-20230321160400606

第 1 步:在 res/drawable/ 目录中新建一个 drawable 资源文件

image-20230321160428341

第 2 步: btn.xml 代码

1
2
3
4
5
6
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 注:默认状态要放在最后 -->
<item android:state_pressed="true" android:color="#ff0" /> <!-- 按下去的状态-->
<item android:color="#fff" /> <!-- 默认时的状态 -->
</selector>

第 3 步: Button 按钮设置

属性
textColor @drawable/btn 引用自定义的xml资源

注:手工强制添加:android:textColor=”@drawable/btn”

(2) ImageButton:根据按钮状态来更改背景

image-20230321160733731

第 1 步:

先将三种图片复制到 res/drawable/ 目录中

◼ 在 res/drawable/ 目录中新建一个 drawable 资源文件:

image-20230321160816347

第 2 步: button_custom.xml 代码

1
2
3
4
5
6
7
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 注:三个<item>定义必须按此顺序才有效 -->
<item android:drawable = "@drawable/button_pressed" android:state_pressed = "true" />
<item android:drawable = "@drawable/button_focused" android:state_focused = "true" />
<item android:drawable = "@drawable/button_default" />
</selector>

◼ 第一个 <item> 定义按下(激活)按钮后使用的图片
◼ 第二个 <item> 定义按钮处于聚焦状态时(使用方向键突出显示按钮时)使用的图片
◼ 第三个 <item> 定义按钮处于默认状态时(既未按下,也未聚焦时)使用的图片

第 3 步: ImageButton按钮设置

属性
background #00000000(8个0,使得png图片背景透明)<- background 透明会让按钮紧密贴合图片
srcCompat @drawable/button_custom (引用自定义的xml资源)

activity_button.mxl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ButtonActivity">
<Button
android:id="@+id/button"
android:layout_width="131dp"
android:layout_height="72dp"
android:layout_marginTop="92dp"
android:text="Button"
android:textColor="@drawable/btn"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.135"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageButton
android:id="@+id/imageButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="64dp"
android:background="#00000000"
app:srcCompat="@drawable/button_custom"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.482"
app:layout_constraintStart_toEndOf="@+id/button"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

ButtonActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class ButtonActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_button);
ActionBar actionBar = getSupportActionBar(); // 获取ActionBar
actionBar.setTitle("按钮示例"); //设置标题
actionBar.setDisplayHomeAsUpEnabled(true); // 显示返回箭头按钮
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()){
case android.R.id.home:
finish();
}
return super.onOptionsItemSelected(item);
}
}

5.ToggleButton 和 Switch

按钮类型 描述
ToggleButton image-20230321161904912 按钮开关,常用属性 textOn、textOff:开、关显示的文字
Switch image-20230321161932046 滑块开关,常用属性 switchMinWidth:开关最小宽度
通用属性:checked true:开启,false:关闭

开关的监听器:监听开关的状态改变

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 定义监听器
private CompoundButton.OnCheckedChangeListener listener = new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { // 开关状态,true表示开关开启
switch ( buttonView.getId() ) {
case R.id.toggleButton:
if ( isChecked )
//开启…
else
//关闭…
break;
}
}
};

1
2
3
4
ToggleButton tb = (ToggleButton) findViewById(R.id.toggleButton);
Switch sw = (Switch) findViewById(R.id.switch1);
tb.setOnCheckedChangeListener(listener);
sw.setOnCheckedChangeListener(listener); // ToggleButton、Switch都可以使用这个监听器

示例:SwitchActivity

image-20230321161626127

activity_switch.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".SwitchActivity">
<Switch
android:id="@+id/switch1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="120dp"
android:checked="false"
android:switchMinWidth="60dp"
android:text="夜间模式"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="88dp"
android:text="Button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/switch1" />
</androidx.constraintlayout.widget.ConstraintLayout>

SwitchActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class SwitchActivity extends AppCompatActivity {
Switch sw;
CompoundButton.OnCheckedChangeListener listener = new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
switch ( buttonView.getId() ) {
case R.id.switch1:
if ( isChecked ) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES); // 开启白天主题(白天主题是:themes.xml)
} else {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO); // 开启夜间主题(夜间主题是:themes.xml (night)
}
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_switch);
sw = (Switch) findViewById(R.id.switch1);
sw.setOnCheckedChangeListener(listener);
}
}

6.RadioButton

image-20230321162107898

◼ 单选按钮一般归属于某个组(RadioGroup),每组中只能有一个被选中(互斥)
◼ 创建过程:先新建 RadioGroup,然后将 RadioButton 拖放到组中(详见下页)

image-20230321162122179

组件 属性描述
RadioGroup orientation属性:horizontal (水平排列) 或 vertical (垂直排列,默认)
RadioButton text属性:按钮文本,checked属性:是否选中(true表示选中)

用法示例:先创建 RadioGroup 组件

image-20230321162402922

再创建 RadioButton 组件

image-20230321162420512

RadioButton 的监听器:监听单击事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
View.OnClickListener listener = new View.OnClickListener() {	// 定义监听器
@Override
public void onClick(View view) {
// 需要强转一下
boolean checked = ((RadioButton) view).isChecked(); //判断是否选中
switch( view.getId() ) {
case R.id.rb_male: // RadioButton的id值
if ( checked )
Toast.makeText(getApplicationContext(),"选中男",Toast.LENGTH_SHORT).show();
break;
case R.id.rb_female: // RadioButton的id值
if ( checked )
Toast.makeText(getApplicationContext(),"选中女",Toast.LENGTH_SHORT).show();
break;
}
}
};
1
2
3
4
RadioButton rb1 = (RadioButton) findViewById(R.id.rb_male);
RadioButton rb2 = (RadioButton) findViewById(R.id.rb_female);
rb1.setOnClickListener(listener);
rb2.setOnClickListener(listener); // 使用监听器

RadioGroup的监听器:监听选择状态改变(常用)

1
2
3
4
5
6
7
8
RadioGroup.OnCheckedChangeListener listener = new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) { // checkedId 表示选中项按钮的 id
RadioButton rb = (RadioButton) findViewById(checkedId); //选中项按钮
String ss = rb.getText().toString(); //获取按钮文本
Toast.makeText(getApplicationContext(), "选中"+ss, Toast.LENGTH_SHORT).show();
}
};
1
2
RadioGroup rbg=(RadioGroup)findViewById(R.id.radioGroup);
rbg.setOnCheckedChangeListener( listener ); // 使用监听器

示例:RadioActivity

image-20230321162949502

activity_radio.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".RadioActivity">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="32dp"
android:text="宋朝开国皇帝是哪一位?"
android:textSize="20sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<RadioGroup
android:id="@+id/radioGroup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="16dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView">
<RadioButton
android:id="@+id/radioButton1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="李渊"
android:textSize="20sp" />
<RadioButton
android:id="@+id/radioButton2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="赵匡胤"
android:textSize="20sp" />
<RadioButton
android:id="@+id/radioButton3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="朱元璋"
android:textSize="20sp" />
<RadioButton
android:id="@+id/radioButton4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="努尔哈赤"
android:textSize="20sp" />
</RadioGroup>
</androidx.constraintlayout.widget.ConstraintLayout>

RadioActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class RadioActivity extends AppCompatActivity {
RadioGroup rg;
RadioGroup.OnCheckedChangeListener listener=new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
RadioButton rb = findViewById(checkedId);
String answer = rb.getText().toString();
if( answer.equals("赵匡胤") )
Toast.makeText(RadioActivity.this,"答对了",Toast.LENGTH_SHORT).show();
else
Toast.makeText(RadioActivity.this,"答错了",Toast.LENGTH_SHORT).show();
}
};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_radio);
rg= findViewById(R.id.radioGroup);
rg.setOnCheckedChangeListener(listener);
}
}

7.CheckBox

image-20230321163040885
属性 描述
text 按钮文本
checked 是否选中(true为选中)

CheckBox 的监听器:监听选择状态的改变

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private CompoundButton.OnCheckedChangeListener listener = new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { // 自带选中状态
switch ( buttonView.getId() ) {
case R.id.cb_music: // CheckBox的id值
if ( isChecked )
Toast.makeText(getApplicationContext(), "选择音乐", Toast.LENGTH_SHORT).show();
else
Toast.makeText(getApplicationContext(), "取消选择音乐", Toast.LENGTH_SHORT).show();
break;
case R.id.cb_movie:

}
}
};
1
2
3
4
5
6
CheckBox cb1 = (CheckBox) findViewById(R.id.cb_music);
CheckBox cb2 = (CheckBox) findViewById(R.id.cb_movie);
CheckBox cb3 = (CheckBox) findViewById(R.id.cb_sport);
cb1.setOnCheckedChangeListener(listener);
cb2.setOnCheckedChangeListener(listener);
cb3.setOnCheckedChangeListener(listener);

示例:CheckBoxActivity 使用 List 存储选中项

image-20230321163357953

activity_check_box.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/constrainLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".CheckBoxActivity">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="44dp"
android:layout_marginTop="76dp"
android:text="选择爱好"
android:textSize="20sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<CheckBox
android:id="@+id/cb_music"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="40dp"
android:layout_marginTop="120dp"
android:text="音乐"
android:textSize="20sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<CheckBox
android:id="@+id/cb_movie"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="120dp"
android:text="电影"
android:textSize="20sp"
app:layout_constraintStart_toEndOf="@+id/cb_music"
app:layout_constraintTop_toTopOf="parent" />
<CheckBox
android:id="@+id/cb_sport"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="120dp"
android:text="体育"
android:textSize="20sp"
app:layout_constraintStart_toEndOf="@+id/cb_movie"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

CheckBoxActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class CheckBoxActivity extends AppCompatActivity {
private List<String> list = new ArrayList<>();
CompoundButton.OnCheckedChangeListener listener = new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if ( isChecked )
list.add( buttonView.getText().toString() );
else
list.remove( buttonView.getText().toString() );
Log.d("flag", list.toString());
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_check_box);
CheckBox cb1 = (CheckBox) findViewById(R.id.cb_music);
CheckBox cb2 = (CheckBox) findViewById(R.id.cb_movie);
CheckBox cb3 = (CheckBox) findViewById(R.id.cb_sport);
cb1.setOnCheckedChangeListener(listener);
cb2.setOnCheckedChangeListener(listener);
cb3.setOnCheckedChangeListener(listener);
}
}

8.SeekBar

image-20230321163544115

属性/方法 描述
min 滑动条的最小值(一般设置为 0)
max 滑动条的最大值(如 100)
setMin(int) 设置滑动条的最小值
setMax(int) 设置滑动条的最大值
progress 滑动条的当前值(如初始设置为50)
setProgress(int) 设置滑动条当前值
getProgress() 返回滑动条当前值
thumb 滑块的drawable(如设置滑块图片)
image-20230321163741555

SeekBar 监听器:监听滑块进度变化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { // progress 表示当前进度值
//当进度条发生变化时触发
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
//当按住滑块开始滑动时触发
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
//当放开滑块结束滑动时触发
}
});

示例:SeekBarActivity

image-20230321163906153

activity_seek_bar.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".SeekBarActivity">
<TextView
android:id="@+id/seekbarvalue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:text="1×"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<SeekBar
android:id="@+id/seekBar2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="80dp"
android:layout_marginEnd="24dp"
android:max="20"
android:min="0"
android:progress="10"
android:thumb="@drawable/twitter"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<ImageView
android:id="@+id/photo2"
android:layout_width="285dp"
android:layout_height="371dp"
android:layout_marginTop="32dp"
android:scaleType="matrix"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/seekBar2"
app:srcCompat="@drawable/alert" />
</androidx.constraintlayout.widget.ConstraintLayout>

SeekBarActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public class SeekBarActivity extends AppCompatActivity {
SeekBar seekBar;
TextView seekBarValue;
ImageView imageView;
Matrix matrix = new Matrix();

// 注:ImageView 的 scaleType="matrix" 才能使用 Matrix 编程
public void scale(float sx,float sy) {
matrix.set( imageView.getImageMatrix() ); // 获得图片的matrix
// 获得图片中心点
int x = imageView.getDrawable().getBounds().centerX();
int y = imageView.getDrawable().getBounds().centerY();
// sx,sy 为x轴、y轴缩放比例
matrix.setScale( sx, sy , x, y ); //以(x,y)为起始点进行缩放
imageView.setImageMatrix( matrix ); //matrix送回图片框
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_seek_bar);
seekBar = (SeekBar) findViewById(R.id.seekBar2);
seekBarValue = (TextView) findViewById(R.id.seekbarvalue);
imageView = findViewById(R.id.photo2);
imageView.setScaleType(ImageView.ScaleType.MATRIX);
//再次确认将scaleType属性设置为"matrix"


seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean
fromUser) {
seekBarValue.setText( progress/10.0f + "×" );
scale( progress/10.0f, progress/10.0f ); //等比缩放
}

@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}

@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
}
}

9.Spinner

image-20230321164222619
常用属性和方法 描述
entries属性 选项的数据来源(静态填充数据)
getSelectedItem() 获取选中项(注:使用toString()转为字符串)
getItemAtPosition(int) 根据位置选择某项(注:使用toString()转为字符串)

说明:默认情况下 Spinner 字体/颜色等不能直接设置,需自定义布局

Spinner 数据填充:静态填充

(1)先在 res/values/strings.xml 文件中声明字符串数组

1
2
3
4
5
6
<string-array name="major_array"> <!-- major_array 为数组名,它的静态引用为 @array/major_array -->
<item>软件工程</item>
<item>计算机科学</item>
<item>网络工程</item>
<item>信息安全</item>
</string-array>

(2)Spinner的entries属性设置为:@array/major_array ==静态引用==

Spinner 数据填充:动态填充(常用)

1
2
3
4
5
6
7
8
9
10
11
List<String> list = new ArrayList<String>();	// 填充的集合数据 list
// 动态赋值
list.add("软件工程");
list.add("计算机科学");
list.add("网络工程");
list.add("信息安全");
// 定义一个String类型适配器
ArrayAdapter<String> adapter = new ArrayAdapter<String>( 当前Activity.this, android.R.layout.simple_list_item_1, list );
// android.R.layout.simple_list_item_1 使用系统内置的布局,也可以自定义布局(见示例1)
Spinner spinner = (Spinner)findViewById(R.id.spinner的id);
spinner.setAdapter(adapter); // 使用适配器给Spinner指定布局和填充数据

系统内置的常见布局:

android.R.layout.布局id 描述
simple_list_item_1 每个列表项是一个普通的文字
simple_list_item_2 每个列表项是两个文本(一主一副) -> image-20230321164949717
simple_list_item_checked 每个列表项会有一个选中项
simple_list_item_single_choice 每个列表项后面会有一个radio按钮
simple_list_item_multiple_choice 每个列表项后面会有一个checkbox按钮

image-20230321164835560

什么是 Adapter

◼ Adapter:称为”适配器”,是用来帮助 UI 组件填充数据的中间桥梁。(也是一种 MVC 体系结构)

image-20230321165101660

常见的 Adapter:

image-20230321165127689

◼ BaseAdapter:是一个抽象类,继承它需要实现较多的方法,所以也就具有较高的灵活性。
◼ ArrayAdapter:支持泛型操作,最为简单,只能展示一行字。
◼ SimpleAdapter:有很好的扩充性,可以自定义出各种效果。
◼ SimpleCursorAdapter:与数据库的简单结合,可以方便地把数据库的内容以列表的形式展示出来。

使用自定义布局:详见示例1

1
2
3
4
5
6
7
8
9
10
List<String> list = new ArrayList<String>();
list.add("软件工程");
list.add("计算机科学");
list.add("网络工程");
list.add("信息安全");
// 自定义布局时,ArrayAdapter 要四个参数,包括自定义布局的 id 和 内部绑定的 TextView 的 id
ArrayAdapter<String> adapter = new ArrayAdapter<String>(当前Activity.this, R.layout.spinner_custom, R.id.tv_item, list);
Spinner spinner = (Spinner)findViewById(R.id.spinner的id);
spinner.setAdapter(adapter);

Spinner 监听器:监听选中项的变化

1
2
3
4
5
6
7
8
9
10
11
spinner.setOnItemSelectedListener( new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
// 获得选中项值:parent.getSelectedItem().toString()
// 或者:parent.getItemAtPosition(position).toString()
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
// 失去焦点时,此处一般不写代码
}
});

其中 onItemSelected 函数四个参数含义:
◼ parent:指 Spinner 对象
◼ view:选中项的视图对象
◼ position:选中项的位置值
◼ id:选中项的行 id 值(从 0 开始)
注:一般情况 position 和 id 值一样

注:Spinner 不要用 setOnItemClickListener 监听器,会闪退

示例1:Spinner1Activity

image-20230321165604053

界面布局代码:activity_spinner1.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Spinner1Activity">
<TextView
android:id="@+id/tv_major"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="52dp"
android:layout_marginTop="104dp"
android:text="专业选择:"
android:textColor="@color/purple_500"
android:textSize="18sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Spinner
android:id="@+id/sp_major"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginStart="52dp"
android:layout_marginTop="12dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_major" />
</androidx.constraintlayout.widget.ConstraintLayout>

Spinner1Activity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class Spinner1Activity extends AppCompatActivity {
Spinner sp_major;
TextView tv_major;
List<String> list;
ArrayAdapter<String> adapter;
AdapterView.OnItemSelectedListener listener = new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
tv_major.setText("专业选择:" + parent.getSelectedItem());
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
};
public void initView(){
tv_major=findViewById(R.id.tv_major);
sp_major=findViewById(R.id.sp_major);
sp_major.setOnItemSelectedListener(listener);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_spinner1);
initView();
list = new ArrayList<String>();
list.add("软件工程");
list.add("计算机科学");
list.add("网络工程");
// adapter = new ArrayAdapter<String>( Spinner1Activity.this,
// android.R.layout.simple_list_item_1, list );
// 下面这个是自定义布局:见下页
adapter = new ArrayAdapter<String>( Spinner1Activity.this,R.layout.spinner_custom, R.id.tv_item, list );
sp_major.setAdapter(adapter);
}
}

自定义布局:在 res/layout 中新建布局资源文件

image-20230321165756101

自定义布局的设计:

image-20230321165813309

自定义布局的代码:sipnner_custom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/spinner_custom"
android:layout_width="match_parent"
android:layout_height="match_parent">

<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="1dp"
android:layout_marginTop="1dp"
android:layout_marginEnd="1dp"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">

<TextView
android:id="@+id/tv_item"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:layout_weight="1"
android:gravity="center_vertical"
android:text="item内容"
android:textColor="@android:color/holo_green_dark"
android:textSize="20sp" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

示例2:Spinner2Activity

image-20230321170136006

界面布局代码:activity_spinner2.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/constrainLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Spinner2Activity">
<Spinner
android:id="@+id/sp_province"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginStart="1dp"
android:layout_marginTop="80dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Spinner
android:id="@+id/sp_city"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="80dp"
app:layout_constraintStart_toEndOf="@+id/sp_province"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

Spinner2Activity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
public class Spinner2Activity extends AppCompatActivity {
Spinner sp_province;
Spinner sp_city;

// 快速初始化
List<String> provinceList = new ArrayList<String>( Arrays.asList("选择省","湖北省","湖南省") );
List<String> cityList = new ArrayList<String>( Arrays.asList("选择市") );
ArrayAdapter<String> adapter;

public void setAdapter( Spinner spinner, List<String> list ) { //封装一下
adapter = new ArrayAdapter<String>( Spinner2Activity.this, android.R.layout.simple_list_item_1, list );
spinner.setAdapter(adapter);
}

public void initView() {
sp_province = (Spinner)findViewById(R.id.sp_province);
sp_city = (Spinner)findViewById(R.id.sp_city);
setAdapter(sp_province,provinceList);
setAdapter(sp_city,cityList);
sp_province.setOnItemSelectedListener( listener );
}

private AdapterView.OnItemSelectedListener listener=new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if ( parent.getId() == R.id.sp_province ) { //判断是哪个spinner被选中
String pName = parent.getSelectedItem().toString(); //省份名
switch (pName) {
case "选择省":
cityList.clear(); //先清空,再添加
cityList.add("选择市");
break;
case "湖北省":
cityList.clear();
cityList.add("武汉");
cityList.add("宜昌");
break;
case "湖南省":
cityList.clear();
cityList.add("长沙");
cityList.add("湘潭");
break;
}
setAdapter(sp_city, cityList); //加载新数据
sp_city.setOnItemSelectedListener(listener);
} else if ( parent.getId() == R.id.sp_city ) {
Toast.makeText(Spinner2Activity.this, "选中的是:" + sp_province.getSelectedItem() +
sp_city.getSelectedItem(), Toast.LENGTH_SHORT).show();
}
}

@Override
public void onNothingSelected(AdapterView<?> parent) {
}
};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_spinner2);
initView();
}
}

10.ListView

image-20230321170400629

常用属性和方法 描述
entries属性 选项的数据来源(静态填充)
setChoiceMode(int) 设置选中模式
◼ 多选:ListView.CHOICE_MODE_MULTIPLE
◼ 单选:ListView.CHOICE_MODE_SINGLE(默认)
getItemAtPosition(int) 根据位置选择某项,使用toString()转为字符串
getCount() 获得选项总数
getCheckedItemCount() 获得选中个数
setSelector(资源id) 设置高亮选中项的背景色或图片

常用布局配合选中模式

image-20230321170503948

ListView数据动态填充:以多选为例

1
2
3
4
5
6
7
8
9
10
11
List<String> list = new ArrayList<String>();
list.add("Java");
list.add("C");
list.add("Python");
ArrayAdapter<String> adapter = new ArrayAdapter<String>(
MainActivity.this,
android.R.layout.simple_list_item_multiple_choice,
list );
ListView listView = (ListView)findViewById(R.id.listView);
listView.setAdapter(adapter);
listView.setChoiceMode( ListView.CHOICE_MODE_MULTIPLE );

image-20230321170818540

ListView 监听器:监听选项单击事件,以多选为例

1
2
3
4
5
6
7
8
9
10
11
12
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
ListView lv = (ListView)parent;
// view需要强转为CheckedTextView类型,才能使用isChecked()
// 为何要强转:因为系统的 simple_list_item_multiple_choice 布局中用的是 CheckedTextView 组件
if ( ((CheckedTextView) view).isChecked() )
// 获得选中项值:lv.getItemAtPosition(position).toString()
else
// 没有选中…
}
});

onItemClick 函数的四个参数含义:
◼ parent:指 ListView 对象
◼ view:击中项的视图对象
◼ position:击中项的位置值
◼ id:击中项的行 id 值(从 0 开始)
注:一般情况 position 和 id 值一样

注:ListView不使用OnItemSelectedListener (Spinner才用)

示例:ListViewActivity

image-20230321171022621

activity_list_view.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ListViewActivity">
<TextView
android:id="@+id/tv_skill"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="选择擅长的技术"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ListView
android:id="@+id/lv_skill"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_marginTop="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_skill" />
</androidx.constraintlayout.widget.ConstraintLayout>

ListViewActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class ListViewActivity extends AppCompatActivity {
ListView listView;
ArrayAdapter<String> adapter;

List<String> skill_list = new ArrayList<>(Arrays.asList("Java", "C", "Python"));
List<String> selected_list = new ArrayList<>(); //存放选中项

// ListView动态填充数据
public void initView() {
listView = findViewById(R.id.lv_skill);
adapter= new ArrayAdapter<String>(
ListViewActivity.this,
android.R.layout.simple_list_item_multiple_choice,
skill_list);
listView.setAdapter(adapter);
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); // 多选模式
listView.setOnItemClickListener(listener);
}
AdapterView.OnItemClickListener listener = new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
ListView lv = (ListView) parent;
if ( ((CheckedTextView) view).isChecked() ) { // 选中时
selected_list.add(lv.getItemAtPosition(position).toString());
} else {
selected_list.remove(lv.getItemAtPosition(position).toString());
}
Log.d("flag", selected_list.toString());
Log.d("flag", "一共选中" + lv.getCheckedItemCount() + "/" + lv.getCount());
}
};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_view);
initView();
}
}

11.AutoCompleteTextView

image-20230321171303664

常用属性 描述
completionHint 设置下拉菜单中的提示标题
completionThreshold 指定用户至少输入多少个字符才会显示提示
singleLine true为单行,false为多行(默认)

用法示例:动态填充

1
2
3
4
5
6
7
List<String> data = new ArrayList<>(Arrays.asList("Apple", "AMD", "Acer", "Intel", "Microsoft"));
AutoCompleteTextView auto = (AutoCompleteTextView) findViewById(R.id.autoCompleteTextView);
// android.R.layout.simple_dropdown_item_1line 为系统下拉列表布局
ArrayAdapter<String> adapter = new ArrayAdapter<String>(当前Activity.this, android.R.layout.simple_dropdown_item_1line, data);
auto.setThreshold(1); //输入1个字符即弹出提示
auto.setCompletionHint("提示信息"); //提示文字
auto.setAdapter(adapter);

示例:AutoCompleteActivity

image-20230321171522375

activity_auto_complete.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".AutoCompleteActivity">
<AutoCompleteTextView
android:id="@+id/autoCompleteTextView"
android:layout_width="250dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="60dp"
android:hint="输入公司名"
android:singleLine="true"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/btn_search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="60dp"
android:backgroundTint="@android:color/holo_green_light"
android:text="搜索"
android:textSize="20sp"
app:layout_constraintStart_toEndOf="@+id/autoCompleteTextView"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

AutoCompleteActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class AutoCompleteActivity extends AppCompatActivity {
AutoCompleteTextView auto;
Button btn;
List<String> data = new ArrayList<>(Arrays.asList("Apple", "AMD", "Acer", "Intel", "Microsoft"));
ArrayAdapter<String> adapter;

View.OnClickListener listener = new View.OnClickListener() {
@Override
public void onClick(View v) {
String input = auto.getText().toString();
if( data.contains(input) ){
Toast.makeText(AutoCompleteActivity.this,"查询中...",Toast.LENGTH_SHORT).show();
}else{
data.add(input); // list更新不能更新adapter
adapter.add(input); // 要用adapter的方法才能更新UI组件
adapter.notifyDataSetChanged(); // 通知UI组件更新数据
Toast.makeText(AutoCompleteActivity.this,"已添加",Toast.LENGTH_SHORT).show();
}
}
};

public void initView() {
btn = findViewById(R.id.btn_search);
btn.setOnClickListener(listener);
auto = (AutoCompleteTextView) findViewById(R.id.autoCompleteTextView);
adapter = new ArrayAdapter<String>(AutoCompleteActivity.this,
android.R.layout.simple_dropdown_item_1line, data);
auto.setThreshold(1); // 输入1个字符即弹出提示
auto.setCompletionHint("公司名称"); // 提示文字
auto.setAdapter(adapter);
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_auto_complete);
initView();
}
}

12.DatePicker和TimePicker

image-20230321171722641

UI 组件代码

注:需手工输入代码

1
2
3
4
5
6
7
8
9
10
11
12
<DatePicker
android:id="@+id/datePicker"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</DatePicker>

<TimePicker
android:id="@+id/timePicker"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</TimePicker>

DatePicker 监听器:监听日期改变

1
2
3
4
5
6
7
DatePicker datePicker=(DatePicker) findViewById(R.id.datePicker);
datePicker.setOnDateChangedListener(new DatePicker.OnDateChangedListener() {
@Override
public void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth) { // 获得设置的年、月、日
//处理日期
}
});

日期和时间选择对话框(常用)

image-20230321171900782

日期选择对话框:

1
2
3
4
5
6
7
8
Calendar data = Calendar.getInstance(); //当前系统日期
DatePickerDialog dpd = new DatePickerDialog( 当前Activity.this, new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, int year, int month, int day) { // 获得设置的时、分
//日期设置完成时触发
}
}, data.get(Calendar.YEAR), data.get(Calendar.MONTH), data.get(Calendar.DAY_OF_MONTH) ); // 日期对话框的初始值
dpd.show();

时间选择对话框:

1
2
3
4
5
6
7
8
Calendar data = Calendar.getInstance(); //当前系统日期
TimePickerDialog tpd = new TimePickerDialog(this, new TimePickerDialog.OnTimeSetListener() {
@Override
public void onTimeSet(TimePicker view, int hourOfDay, int minute) { // 获得设置的年、月、日
//时间设置完成时触发
}
}, calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE), true); // Calendar.HOUR_OF_DAY 表示时间对话框的初始值,true表示24小时制
tpd.show();

示例:日期和时间选择对话框

image-20230321172149075

重要:EditText 单击触发 onclick 事件处理

◼ 默认情况下:EditText 单击只能获得焦点,并不触发 onclick 事件
◼ 如果要直接触发 onclick 事件,EditText 添加两个属性
android:clickable = "true" //允许单击
android:focusableInTouchMode="false" //不获得焦点,此时会触发 onclick 事件

activity_date_time_picker.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".DateTimePickerActivity">
<EditText
android:id="@+id/et_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:ems="10"
android:hint="输入日期"
android:inputType="textPersonName"
android:clickable="true"
android:focusableInTouchMode="false"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/et_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="100dp"
android:ems="10"
android:hint="输入时间"
android:inputType="textPersonName"
android:textSize="20sp"
android:clickable="true"
android:focusableInTouchMode="false"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.497"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

DateTimePickerActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public class DateTimePickerActivity extends AppCompatActivity {
EditText et_date, et_time;
public void initView() {
et_date = findViewById(R.id.et_date);
et_time = findViewById(R.id.et_time);
et_date.setOnClickListener(listener);
et_time.setOnClickListener(listener);
}
View.OnClickListener listener = new View.OnClickListener() {
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.et_date:
getDate(); //设置日期
break;
case R.id.et_time:
getTime(); //设置时间
break;
}
}
};

public void getDate() {
Calendar data = Calendar.getInstance();
DatePickerDialog dpd = new DatePickerDialog(DateTimePickerActivity.this, new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, int year, int month, int day) {
String str;
str = String.valueOf(year) + "-" + String.valueOf(month+1) + "-" + String.valueOf(day);
et_date.setText(str);
}
}, data.get(Calendar.YEAR), data.get(Calendar.MONTH), data.get(Calendar.DAY_OF_MONTH));
dpd.show();
}

public void getTime() {
Calendar calendar = Calendar.getInstance();
TimePickerDialog tpd = new TimePickerDialog(this, new TimePickerDialog.OnTimeSetListener() {
@Override
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
String str;
str = String.valueOf(hourOfDay) + ":" + String.valueOf(minute) ;
et_time.setText(str);
}
}, calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE), true);
tpd.show();
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_date_time_picker);
initView();
}
}

编程示例

模拟登录

基本步骤: app全屏显示
◼ Activity主题和配置
◼ Activity全屏
◼ 界面布局设计
◼ 按钮文字颜色(详见5.2节)
◼ UI编程

image-20230321172634749

1.Activity 主题和配置

◼ 新建Activity: LoginActivity
◼ 在 themes.xml 中添加新主题:

1
2
3
4
5
6
7
<style name="Theme.Login" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@android:color/holo_orange_dark</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/white</item>
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
</style>

image-20230321172757076

修改 Activity 配置

◼ 在 AndroidManifest.xml 修改 LoginActivity 配置:

1
2
3
4
5
6
7
8
9
10
11
<activity
android:name=".LoginActivity"
android:exported="true"
android:icon="@drawable/login"
android:label="用户登录"
android:theme="@style/Theme.Login">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

image-20230321172907373

运行APP:观察主题效果

image-20230321172931721

2.Activity全屏

◼ LoginActivity 添加代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class LoginActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);

//1. 设置为全屏模式(隐藏状态条)
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);

//2. ActionBar显示返回按钮
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
}

//3. 返回按钮的功能在onOptionsItemSelected()中触发 (该函数与onCreate并列)
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch ( item.getItemId() ) {
case android.R.id.home: // ActionBar返回按钮的id值(系统指定)
finish();
}
return super.onOptionsItemSelected(item);
}
}

运行结果:

3.界面布局设计

image-20230321173305585

布局设计:ImageView 组件

image-20230321173329511

布局设计:TextView组件(手机号标签)

image-20230321173351421

布局设计:EditText组件(手机号文本框)

image-20230321173425254

布局设计:TextView组件(密码标签)

image-20230321173449240

布局设计:EditText组件(密码框)

image-20230321173516529

布局设计:Button组件(登录按钮)

image-20230321173535621

最终布局代码:activity_login.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".LoginActivity">
<ImageView
android:id="@+id/photo"
android:layout_width="165dp"
android:layout_height="177dp"
android:layout_marginStart="16dp"
android:layout_marginTop="32dp"
android:layout_marginEnd="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/login" />
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="50dp"
android:text="手机号"
android:textSize="24sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/photo" />
<EditText
android:id="@+id/phone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:ems="10"
android:hint="11位手机号"
android:inputType="phone"
android:maxLength="11"
android:textSize="24sp"
app:layout_constraintBaseline_toBaselineOf="@+id/textView1"
app:layout_constraintStart_toEndOf="@+id/textView1" />

<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="25dp"
android:text="密 码"
android:textSize="24sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView1" />

<EditText
android:id="@+id/password"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:ems="10"
android:hint="不超过10个字符"
android:inputType="textPassword"
android:maxLength="10"
android:textSize="24sp"
app:layout_constraintBaseline_toBaselineOf="@+id/textView2"
app:layout_constraintStart_toEndOf="@+id/textView2" />

<Button
android:id="@+id/login_btn"
android:layout_width="379dp"
android:layout_height="66dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="36dp"
android:backgroundTint="@android:color/holo_green_light"
android:text="登录"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

运行结果:

image-20230321173714959

4.UI编程

wewt

获取输入的数据(LoginActivity代码)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// UI组件对象
private EditText phone;
private EditText password;
private Button login;

// 存放手机号和密码
private String s_phone;
private String s_password;

// 定义按钮监听器
View.OnClickListener listener = new View.OnClickListener() {
@Override
public void onClick(View view)
// 调用登录函数
// 注:只有一个按钮,可不用switch
login();
}
};

public void init() { // 初始化函数
phone = (EditText) findViewById(R.id.phone);
password = (EditText) findViewById(R.id.password);
login = (Button) findViewById(R.id.login_btn);
login.setOnClickListener(listener); // 按钮设置监听器
}
public void login() { // 登录函数
// 获取输入的信息
s_phone = phone.getText().toString();
s_password = password.getText().toString();
String msg = "手机号=" + s_phone + ",密码=" + s_password;
Log.d("flag", msg);
Toast.makeText(LoginActivity.this, "登录成功", Toast.LENGTH_SHORT).show();
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);

init(); // 调用初始化函数
}

模拟验证码重发(10秒倒计时)

倒计时CountDownTimer用法

1
2
3
4
5
6
7
8
9
10
11
//倒计时组件
CountDownTimer countDownTimer = new CountDownTimer(参数1, 参数2) { // 参数1:倒计时总时间(ms),参数2:间隔时间(ms)
@Override
public void onTick(long millisUntilFinished) { //每隔参数2时间调用一次onTick,millisUntilFinished 表示剩余时间

}
@Override
public void onFinish() { //倒计时完成时的回调

}
};

◼ 启动倒计时:countDownTimer.start();
◼ 取消倒计时:countDownTimer.cancel();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class LoginActivity extends AppCompatActivity {
….
private Button btn_send;

public void init() {

btn_send = (Button)findViewById( R.id.btn_send );
btn_send.setOnClickListener( listener );
}

//倒计时(倒计时总时间10秒 间隔时间1秒)
CountDownTimer countDownTimer = new CountDownTimer(10000, 1000) {
//每隔1秒调用一次onTick
@Override
public void onTick(long millisUntilFinished) {
btn_send.setText( millisUntilFinished / 1000 +"秒后可重发" );
}

//倒计时完成时的回调
@Override
public void onFinish() {
btn_send.setEnabled(true); /*按钮启用*/
btn_send.setText("发送验证码");
}
};

View.OnClickListener listener = new View.OnClickListener() {
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.login_btn:
login();
break;
case R.id.btn_send:
btn_send.setEnabled(false); /*按钮失效*/
countDownTimer.start(); /*启动倒计时*/
break;
}
}
};

}

图片查看

◼ 新建 Activity: PicShowActivity

image-20230321174622423

图片准备:本例图片文件存放在 assets 文件夹中

◼ assets 文件夹:
◼ 可以存放如图片、音频、视频等资源
◼ 该目录下的文件在打包后会原封不动的保存在 apk 包中,不会被编译成二进制
◼ assets 可以有目录结构,也就是 assets 目录下可以再建立文件夹
◼ 注意:
◼ assets 文件夹下的文件不会被映射到 R.java 中,访问的时候需要 AssetManager 类

assets文件读取方法:

◼ 读取 assets 下的文件资源:

1
2
String[] fNames = getAssets().list("pic"); //获取assets/pic目录下所有文件和文件夹名
InputStream is = getAssets().open("filename"); //打开指定的文件(输入流方式)

新建 assets 目录

◼ 项目右键→New → Folder → Assets Folder

image-20230321174948443

在assets目录中新建子目录:

◼ assets目录右键 → New → Directory

image-20230321175011714

将图片资源复制到 assets/pic 下

image-20230321175038249

activity_pic_show.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".PicShowActivity">
<TextView
android:id="@+id/tv_pic"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="选择图片查看"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ListView
android:id="@+id/lv_pic"
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_marginTop="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_pic" />
</androidx.constraintlayout.widget.ConstraintLayout>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
public class PicShowActivity extends AppCompatActivity {
ListView listView;
ArrayAdapter<String> adapter;
List<String> pic_list = new ArrayList<>();

// ListView 动态填充数据
public void initView() {
listView = findViewById(R.id.lv_pic);
pic_list = getPic(); //获取assets/pic目录下所有图片名
adapter = new ArrayAdapter<String>(
PicShowActivity.this, android.R.layout.simple_list_item_single_choice,
pic_list);
listView.setAdapter(adapter);
listView.setChoiceMode( ListView.CHOICE_MODE_SINGLE ); // 单选模式
listView.setOnItemClickListener(listener);
}

public List<String> getPic() {
List<String> pList = new ArrayList<>();
try {
String[] fNames = getAssets().list("pic"); //获取assets/pic目录下所有文件名
for (String fn : fNames) {
pList.add(fn);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
return pList;
}

// ListView监听器
AdapterView.OnItemClickListener listener = new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
ListView lv = (ListView) parent;
lv.setSelector(R.color.purple_200); //设置高亮背景色
String pName = parent.getItemAtPosition(position).toString(); //获得选中项图片名称
showPic(pName); //显示图片,见下页
}
};

//显示图片
public void showPic(String pName) {
try {
InputStream is = getAssets().open("pic/" + pName); // 打开assets/pic下指定的文件(输入流方式)
Bitmap bitmap = BitmapFactory.decodeStream(is); // 将输入流转为Bitmap类型

// ①创建全屏对话框窗口
final Dialog dialog = new Dialog(PicShowActivity.this, android.R.style.Theme_Black_NoTitleBar_Fullscreen); // 系统全屏样式
// ②创建一个ImageView组件,该组件显示bitmap内容
ImageView imgView = getView(bitmap); // getView方法在下页
dialog.setContentView(imgView); // dialog窗口加载imgView作为界面内容
dialog.show(); //显示对话框窗口
// ③点击图片关闭对话框
imgView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss(); //关闭对话框
}
});
} catch (IOException e) {
throw new RuntimeException(e);
}
}

// 创建一个ImageView对象
private ImageView getView(Bitmap bitmap) {
ImageView iv = new ImageView( PicShowActivity.this ); //新建对象
//ImageView设置宽高为与屏幕匹配
iv.setLayoutParams(new ActionBar.LayoutParams(
ActionBar.LayoutParams.MATCH_PARENT,
ActionBar.LayoutParams.MATCH_PARENT));
//加载bitmap资源
iv.setImageBitmap(bitmap);
return iv;
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pic_show);
initView();

// 设置为全屏模式(隐藏状态条)
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
//设置标题和返回按钮
ActionBar actionBar = getSupportActionBar();
actionBar.setTitle("图片查看示例");
actionBar.setDisplayHomeAsUpEnabled(true);
}
}

音乐播放器

ExoPlayer+SeekBar+定时器

◼ 新建 Activity: MusicActivity

image-20230321175420856

音乐准备:本例音乐放在 res/raw 目录下

◼ 在 res 中新建 raw 资源文件夹,然后将音乐(例如she.mp3)复制到 raw 文件夹

image-20230321175517789

了解:asset 和 res/raw 文件夹区别

◼ 相同点:
◼ asset 和 res/raw 文件夹下都可以存放如音频、视频等资源
◼ 两者目录下的文件在打包后会原封不动的保存在apk包中,不会被编译成二进制
◼ 不同点:
◼ res/raw 中的文件会被映射到 R.java 文件中,访问的时候直接使用资源 ID,即 R.raw.资源id;
◼ assets 文件夹下的文件不会被映射到 R.java 中,访问的时候需要 AssetManager 类
◼ res/raw 不可以有目录结构,而 assets 则可以有目录结构,也就是 assets 目录下可以再建立文件夹

文件读取的区别
◼ 读取 res/raw 下的文件资源:

1
InputStream is = getResources().openRawResource( R.raw.资源id ); 

◼ 读取 assets 下的文件资源:

1
2
String[] fNames = getAssets().list("music"); //获取assets/music目录下所有文件和文件夹名
InputStream is = getAssets().open("filename"); //打开指定的文件

关于:ExoPlayer 媒体播放器
◼ Google 推出的开源媒体播放器 (可取代 MediaPlayer)
◼ 支持本地音视频的播放,同时也支持网络视频播放
◼ 使用前需要添加依赖:如下:

添加 ExoPlayer 依赖

image-20230321175820596

媒体播放器常用方法

方法 描述
创建ExoPlayer对象 ExoPlayer player = new ExoPlayer.Builder( MusicActivity.this ).build();
setMediaItem() 添加媒体(支持本地和远程资源)
prepare() 在播放前调用此方法完成播放准备工作
start() 开始或继续播放媒体
pause() 暂停播放
stop() 停止播放
release() 释放播放器对象相关资源
isPlaying() 判断当前播放器是否正在播放
seekTo() 从指定位置开始播放
getDuration() 获取媒体文件的时长(毫秒)
getContentPosition() 获取媒体播放的当前位置(毫秒)
addListener() 添加监听器(如onPlaybackStateChanged播放状态监听等,比较多)
setRepeatMode() 设置循环播放模式:ExoPlayer.REPEAT_MODE_ONE 单曲循环 ExoPlayer.REPEAT_MODE_ALL 全部循环

activity_music.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/constrainLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MusicActivity">
<SeekBar
android:id="@+id/seekBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="100dp"
android:layout_marginEnd="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageButton
android:id="@+id/btn_player"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="64dp"
android:backgroundTint="@android:color/holo_orange_light"
android:scaleType="fitCenter"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/seekBar"
app:srcCompat="@android:drawable/ic_media_play" />
<TextView
android:id="@+id/seekBarHint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="当前进度"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/seekBar" />
</androidx.constraintlayout.widget.ConstraintLayout>

MusicActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
public class MusicActivity extends AppCompatActivity {
SeekBar seekBar; //进度条
TextView seekBarHint; //音乐时长提示
ImageButton btn_player; //播放按钮
ExoPlayer player; //播放器
private Timer timer; //定时器
private boolean prepared; //播放器是否准备好

// 定时任务类:定时刷新SeekBar进度条
private class ProgressUpdate extends TimerTask {
@Override
public void run() {
runOnUiThread( new Runnable() {
@Override
public void run() {
// 获取媒体播放的当前位置(毫秒)
long position = player.getContentPosition();
Log.d("flag", "pos=" + position);
// SeekBar设置进度
seekBar.setProgress((int) position);
// 显示当前音乐时间
seekBarHint.setText( format(position) );
}
});
}
}
// 将音乐毫秒数转为"分:秒"格式显示
// import java.text.SimpleDateFormat;
public String format(long position) {
SimpleDateFormat sdf = new SimpleDateFormat("mm:ss"); // "分:秒"格式
String timeStr = sdf.format(position); //会自动将时长(毫秒数)转换为分秒格式
return timeStr;
}
public void initView(){
btn_player = (ImageButton) findViewById(R.id.btn_player);
seekBar = (SeekBar) findViewById(R.id.seekBar);
seekBarHint = (TextView) findViewById(R.id.seekBarHint);
}

public void initExoPlayer() {
// 创建播放器
// import com.google.android.exoplayer2.MediaItem;
player = new ExoPlayer.Builder(MusicActivity.this).build();
MediaItem mediaItem = MediaItem.fromUri(
RawResourceDataSource.buildRawResourceUri( R.raw.she )); // 本地res/raw音乐资源
player.setMediaItem(mediaItem); //加载媒体资源
player.setRepeatMode(ExoPlayer.REPEAT_MODE_ONE); //单曲循环
player.prepare(); //会触发下面的监听器↓
}

// 播放器的监听器
Player.Listener listener1 = new Player.Listener() {
@Override
//播放器状态监听器
public void onPlaybackStateChanged(int playbackState) {
if (playbackState == ExoPlayer.STATE_READY) { //播放器准备好了
prepared = true;
long realDurationMillis = player.getDuration(); // 获取媒体文件的时长(毫秒)
seekBar.setMax((int) realDurationMillis); // 设置SeekBar最大值
}
}
};

// 播放按钮的监听器
View.OnClickListener listener2 = new View.OnClickListener() {
@Override
public void onClick(View v) {
if ( !prepared ) //播放器没有准备好
return;
if ( player.isPlaying() ) { // 是否在播放
player.pause(); // 暂停播放
btn_player.setImageResource(android.R.drawable.ic_media_play);
timer.cancel(); //停止定时器
timer = new Timer(); //新建定时器
} else {
player.play(); // 开始或继续播放
btn_player.setImageResource(android.R.drawable.ic_media_pause);
timer = new Timer();
// 启动定时任务
timer.schedule(new ProgressUpdate(), 300, 500);
}
}
};

// SeekBar的监听器
SeekBar.OnSeekBarChangeListener listener3 =
new SeekBar.OnSeekBarChangeListener() {
@Override
// progress 表示当前进度值
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
if (prepared && fromUser) {
player.seekTo(progress); // 从指定位置开始播放
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
seekBarHint.setText(format(seekBar.getProgress()));
}
};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_music);
initView();
prepared = false; //初始值
initExoPlayer();
//3个监听
player.addListener(listener1);
btn_player.setOnClickListener(listener2);
seekBar.setOnSeekBarChangeListener(listener3);
} //end create

@Override
protected void onDestroy() { // Activity结束前触发
super.onDestroy();
player.stop(); // 停止播放
player.release(); // 释放资源
}
} //end activity

Activity间的跳转

在 Android 中,Activity 跳转是指从一个 Activity 转到另一个 Activity 的过程。可以通过 Intent 来实现 Activity 之间的跳转。一般情况下,使用startActivity() 方法来启动一个新的 Activity,也可以使用 startActivityForResult() 方法来启动一个新的 Activity 并返回结果。在跳转时,需要指定目标 Activity 的类名或 Intent 对象。同时,也可以在 Intent 中传递参数,以便在目标 Activity 中使用。

下面给出一个通过 Intent 来实现 Activity 间跳转的案例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class TestActivity extends AppCompatActivity {
private Intent intent2;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);

intent2=new Intent();
// TestActivity.this 表示当前 Activity 的上下文,LoginActivity.class 表示目标(要跳转的)Activity 类
intent2.setComponent(new ComponentName(TestActivity.this, LoginActivity.class));

startActivity(intent2);
}
}

一个用于跳转到多个 Activity 的案例

image-20230324205953752

activity_test.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".TextViewActivity">
<TextView
android:id="@+id/tv1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="124dp"
android:autoLink="web"
android:text="https://www.wust.edu.cn"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:autoLink="email"
android:text="zhangzhi@wust.edu.cn"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.502"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv1" />
<TextView
android:id="@+id/tv3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:autoLink="phone"
android:text="+8613012345678"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.497"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv2" />
<TextView
android:id="@+id/tv4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:autoLink="map"
android:text="620 Eighth Avenue New York, NY 10018"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.497"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv3" />
<TextView
android:id="@+id/tv5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="60dp"
android:autoLink="map"
android:text="welcome"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.491"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv4" />
<Button
android:id="@+id/btn_change"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="修改welcome"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv5" />
</androidx.constraintlayout.widget.ConstraintLayout>

TestActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
public class TestActivity extends AppCompatActivity {

// 在 BtnClickListener 中处理按钮的点击事件
class BtnClickListener implements View.OnClickListener {
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.activity_auto_complete:
Intent intent0 = new Intent(TestActivity.this, AutoCompleteActivity.class);
startActivity(intent0);
break;
case R.id.activity_button:
Intent intent1 = new Intent(TestActivity.this, ButtonActivity.class);
startActivity(intent1);
break;
case R.id.activity_check_box:
Intent intent2 = new Intent(TestActivity.this, CheckBoxActivity.class);
startActivity(intent2);
break;
case R.id.activity_date_time_picker:
Intent intent3 = new Intent(TestActivity.this, DateTimePickerActivity.class);
startActivity(intent3);
break;
case R.id.activity_edit_text:
Intent intent4 = new Intent(TestActivity.this, EditTextActivity.class);
startActivity(intent4);
break;
case R.id.activity_image_view:
Intent intent5 = new Intent(TestActivity.this, ImageViewActivity.class);
startActivity(intent5);
break;
case R.id.activity_list_view:
Intent intent6 = new Intent(TestActivity.this, ListViewActivity.class);
startActivity(intent6);
break;
case R.id.activity_login:
Intent intent7 = new Intent(TestActivity.this, LoginActivity.class);
startActivity(intent7);
break;
case R.id.activity_music:
Intent intent8 = new Intent(TestActivity.this, MusicActivity.class);
startActivity(intent8);
break;
case R.id.activity_pic_show:
Intent intent9 = new Intent(TestActivity.this, PicShowActivity.class);
startActivity(intent9);
break;
case R.id.activity_radio:
Intent intent10 = new Intent(TestActivity.this, RadioActivity.class);
startActivity(intent10);
break;
case R.id.activity_seek_bar:
Intent intent11 = new Intent(TestActivity.this, SeekBarActivity.class);
startActivity(intent11);
break;
case R.id.activity_spinner1:
Intent intent12 = new Intent(TestActivity.this, Spinner1Activity.class);
startActivity(intent12);
break;
case R.id.activity_spinner2:
Intent intent13 = new Intent(TestActivity.this, Spinner2Activity.class);
startActivity(intent13);
break;
case R.id.activity_switch:
Intent intent14 = new Intent(TestActivity.this, SwitchActivity.class);
startActivity(intent14);
break;
}
}
}


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);

// 创建 BtnClickListener 对象
BtnClickListener btnClickListener = new BtnClickListener();

// 注册 activity_auto_complete 监听器
findViewById(R.id.activity_auto_complete).setOnClickListener(btnClickListener);

// 注册 activity_button 监听器
findViewById(R.id.activity_button).setOnClickListener(btnClickListener);

// 注册 activity_check_box 监听器
findViewById(R.id.activity_check_box).setOnClickListener(btnClickListener);

// 注册 activity_date_time_picker 监听器
findViewById(R.id.activity_date_time_picker).setOnClickListener(btnClickListener);

// 注册 activity_edit_text 监听器
findViewById(R.id.activity_edit_text).setOnClickListener(btnClickListener);

// 注册 activity_image_view 监听器
findViewById(R.id.activity_image_view).setOnClickListener(btnClickListener);

// 注册 activity_list_view 监听器
findViewById(R.id.activity_list_view).setOnClickListener(btnClickListener);

// 注册 activity_login 监听器
findViewById(R.id.activity_login).setOnClickListener(btnClickListener);

// 注册 activity_music 监听器
findViewById(R.id.activity_music).setOnClickListener(btnClickListener);

// 注册 activity_pic_show 监听器
findViewById(R.id.activity_pic_show).setOnClickListener(btnClickListener);

// 注册 activity_radio 监听器
findViewById(R.id.activity_radio).setOnClickListener(btnClickListener);

// 注册 activity_seek_bar 监听器
findViewById(R.id.activity_seek_bar).setOnClickListener(btnClickListener);

// 注册 activity_spinner1 监听器
findViewById(R.id.activity_spinner1).setOnClickListener(btnClickListener);

// 注册 activity_spinner2 监听器
findViewById(R.id.activity_spinner2).setOnClickListener(btnClickListener);

// 注册 activity_switch 监听器
findViewById(R.id.activity_switch).setOnClickListener(btnClickListener);
}
}
 Comments
Comment plugin failed to load
Loading comment plugin
Powered by Hexo & Theme Keep
Unique Visitor Page View