文章目录
-
- 一、引言
- [二、Android 布局(Layout)](#二、Android 布局(Layout))
-
- [2.1 LinearLayout(线性布局)](#2.1 LinearLayout(线性布局))
- [2.2 RelativeLayout(相对布局)](#2.2 RelativeLayout(相对布局))
- [2.3 ConstraintLayout(约束布局)](#2.3 ConstraintLayout(约束布局))
- [2.4 FrameLayout(帧布局)](#2.4 FrameLayout(帧布局))
- [2.5 布局核心属性必知必会](#2.5 布局核心属性必知必会)
-
- [`layout_width` 与 `layout_height`](#
layout_width与layout_height) - [dp vs px vs sp](#dp vs px vs sp)
- [margin vs padding](#margin vs padding)
- [gravity vs layout_gravity](#gravity vs layout_gravity)
- [`layout_width` 与 `layout_height`](#
- [三、Android 常用控件(Widget)](#三、Android 常用控件(Widget))
-
- [3.1 TextView ------ 文本显示](#3.1 TextView —— 文本显示)
- [3.2 EditText ------ 文本输入](#3.2 EditText —— 文本输入)
- [3.3 Button ------ 按钮](#3.3 Button —— 按钮)
- [3.4 ImageView ------ 图片展示](#3.4 ImageView —— 图片展示)
- [3.5 ListView ------ 列表展示](#3.5 ListView —— 列表展示)
- [3.6 RecyclerView ------ 更强大的列表](#3.6 RecyclerView —— 更强大的列表)
- [3.7 Toast ------ 轻量提示](#3.7 Toast —— 轻量提示)
- [3.8 CheckBox 与 RadioButton](#3.8 CheckBox 与 RadioButton)
- [3.9 Switch(开关)](#3.9 Switch(开关))
- [3.10 SeekBar(滑动条)](#3.10 SeekBar(滑动条))
- [四、ViewHolder 性能优化详解](#四、ViewHolder 性能优化详解)
-
- 为什么需要优化?
- [ViewHolder 的工作原理](#ViewHolder 的工作原理)
- 五、常见事件监听总结
- 六、总结
一、引言
对于刚接触 Android 开发的新手来说,控件(Widget) 和 布局(Layout) 是绕不开的两座大山。它们共同构成了 App 的"脸面"------用户看到的一切界面,都是由布局搭建框架、再由控件填充内容而成的。
本文将从零开始,系统地介绍 Android 中常用的布局和控件,配合实际代码示例,帮助你快速上手 Android UI 开发。
二、Android 布局(Layout)
布局的作用是管理子控件之间的位置关系,相当于一个"容器"。Android 提供了多种布局,各有适用场景。
2.1 LinearLayout(线性布局)
LinearLayout 是最基础、最常用的布局。它会将子控件按照**水平(horizontal)或垂直(vertical)**方向依次排列。
xml
<!-- 垂直排列 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button android:text="按钮1" ... />
<Button android:text="按钮2" ... />
<Button android:text="按钮3" ... />
</LinearLayout>
如果把 orientation 改成 horizontal,三个按钮就会水平排成一行。
适用场景: 简单的列表、表单、工具栏等线性排列的界面。
2.2 RelativeLayout(相对布局)
RelativeLayout 允许子控件通过相对位置来定位,比如"在 A 的右边"、"与 B 底部对齐"等。
xml
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/label"
android:text="用户名:"
android:layout_alignParentLeft="true" />
<EditText
android:id="@+id/input"
android:layout_toRightOf="@id/label"
android:layout_alignBaseline="@id/label" />
<Button
android:text="提交"
android:layout_below="@id/input"
android:layout_centerHorizontal="true" />
</RelativeLayout>
常用相对定位属性:
| 属性 | 含义 |
|---|---|
layout_below |
在指定控件的下方 |
layout_above |
在指定控件的上方 |
layout_toRightOf |
在指定控件的右侧 |
layout_toLeftOf |
在指定控件的左侧 |
layout_alignParentBottom |
与父容器底部对齐 |
layout_centerHorizontal |
在父容器中水平居中 |
适用场景: 需要控件之间有位置依赖关系的复杂界面。
2.3 ConstraintLayout(约束布局)
ConstraintLayout 是 Google 官方推荐的布局,功能最强大。它通过**约束(Constraint)**来描述控件之间的关系,既能实现扁平化布局(避免多层嵌套),又能灵活适配各种屏幕。
xml
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/avatar"
android:layout_width="80dp"
android:layout_height="80dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginStart="16dp" />
<TextView
android:id="@+id/name"
android:text="张三"
app:layout_constraintStart_toEndOf="@id/avatar"
app:layout_constraintTop_toTopOf="@id/avatar"
android:layout_marginStart="12dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
适用场景: 几乎适用所有场景,尤其是复杂界面、需要适配多屏幕的情况。
2.4 FrameLayout(帧布局)
FrameLayout 是最简单的布局,所有子控件默认层叠在左上角,后添加的会覆盖先添加的。
xml
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:src="@drawable/background"
android:scaleType="centerCrop"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<TextView
android:text="层叠在上方的文字"
android:layout_gravity="center"
android:textColor="#FFFFFF" />
</FrameLayout>
适用场景: 单一子控件的占位、悬浮遮罩层、Fragment 容器。
2.5 布局核心属性必知必会
无论用哪种布局,以下属性是每个开发者都必须掌握的:
layout_width 与 layout_height
| 值 | 含义 |
|---|---|
match_parent |
尺寸与父容器一致 |
wrap_content |
根据内容自动调整大小 |
具体数值(如 100dp) |
固定尺寸 |
dp vs px vs sp
| 单位 | 含义 | 使用场景 |
|---|---|---|
| px | 屏幕物理像素 | 不推荐直接使用 |
| dp | 密度无关像素,在不同密度屏幕上物理大小一致 | 控件宽高、间距 |
| sp | 可伸缩像素,受系统字体大小设置影响 | 文字大小 |
xml
android:layout_width="100dp"
android:textSize="16sp"
android:layout_margin="8dp"
margin vs padding
-
margin (外边距):控件与其他控件之间的距离
-
padding (内边距):控件内容与自身边界之间的距离
┌─────────── margin ───────────┐
│ ┌────── padding ──────┐ │
│ │ │ │
│ │ 内容区域 │ │
│ │ │ │
│ └─────────────────────┘ │
└──────────────────────────────┘
xml
android:layout_margin="16dp" <!-- 与其他控件的间距 -->
android:padding="12dp" <!-- 内容与边框的间距 -->
gravity vs layout_gravity
| 属性 | 作用对象 | 含义 |
|---|---|---|
android:gravity |
控件自身内容 | 内容在控件内部的摆放位置 |
android:layout_gravity |
控件在父容器中 | 控件在父容器中的摆放位置 |
xml
<!-- 文字在 TextView 内部居中 -->
<TextView android:gravity="center" ... />
<!-- TextView 本身在父容器中居中 -->
<TextView android:layout_gravity="center" ... />
三、Android 常用控件(Widget)
3.1 TextView ------ 文本显示
TextView 是最基本的控件,用于在屏幕上展示文字。
xml
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello Android"
android:textSize="18sp"
android:textColor="#333333"
android:textStyle="bold"
android:maxLines="2"
android:ellipsize="end" />
常用属性速查:
| 属性 | 说明 |
|---|---|
android:text |
显示的文本内容 |
android:textSize |
文字大小(单位 sp) |
android:textColor |
文字颜色 |
android:textStyle |
样式:normal/bold/italic |
android:maxLines |
最大行数,超出后省略 |
android:ellipsize |
省略位置:end/middle/start |
android:gravity |
文字对齐方式 |
Java 代码动态设置:
java
TextView tv = findViewById(R.id.title);
tv.setText("新的文字");
tv.setTextColor(Color.RED);
tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
3.2 EditText ------ 文本输入
EditText 继承自 TextView,允许用户输入和编辑文字。
xml
<EditText
android:id="@+id/input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入用户名"
android:inputType="text"
android:maxLength="20" />
inputType 常用值:
| 值 | 说明 |
|---|---|
text |
普通文本 |
textPassword |
密码(显示为圆点) |
number |
纯数字 |
phone |
电话号码 |
textEmailAddress |
邮箱地址 |
textMultiLine |
多行文本 |
3.3 Button ------ 按钮
Button 是触发操作的核心控件,用户点击后执行相应逻辑。
xml
<Button
android:id="@+id/btn_submit"
android:text="提交"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onSubmitClick" />
Java 中设置点击事件(两种方式):
java
// 方式一:匿名内部类
Button btn = findViewById(R.id.btn_submit);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "按钮被点击了", Toast.LENGTH_SHORT).show();
}
});
// 方式二:Lambda 表达式(推荐)
btn.setOnClickListener(v -> {
Toast.makeText(MainActivity.this, "按钮被点击了", Toast.LENGTH_SHORT).show();
});
3.4 ImageView ------ 图片展示
ImageView 用于在界面上展示图片资源。
xml
<ImageView
android:id="@+id/image"
android:layout_width="120dp"
android:layout_height="120dp"
android:src="@drawable/sample_image"
android:scaleType="centerCrop"
android:contentDescription="示例图片" />
scaleType 详解:
| 值 | 效果 |
|---|---|
centerCrop |
等比缩放填满控件,超出部分裁剪 ★推荐 |
fitCenter |
等比缩放,居中显示,不裁剪 |
fitXY |
拉伸填满,可能导致变形 |
center |
不缩放,居中显示原图 |
centerInside |
等比缩放至完全显示在控件内 |
Java 代码动态设置:
java
ImageView imageView = findViewById(R.id.image);
imageView.setImageResource(R.drawable.new_image);
// 使用第三方库加载网络图片(如 Glide)
// Glide.with(this).load("https://example.com/image.jpg").into(imageView);
3.5 ListView ------ 列表展示
ListView 是展示大量同类型数据的最经典控件,采用 MVC 架构:
Model(数据) → Adapter(适配器/桥梁) → View(列表控件)
使用 ListView 的四大步骤:
第一步:创建数据模型
java
public class Fruit {
private String name;
private int imageId;
public Fruit(String name, int imageId) {
this.name = name;
this.imageId = imageId;
}
public String getName() { return name; }
public int getImageId() { return imageId; }
}
第二步:编写列表项布局
xml
<!-- fruit_item.xml -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="12dp">
<ImageView
android:id="@+id/fruit_image"
android:layout_width="60dp"
android:layout_height="60dp" />
<TextView
android:id="@+id/fruit_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="12dp"
android:textSize="16sp" />
</LinearLayout>
第三步:自定义适配器
java
public class FruitAdapter extends ArrayAdapter<Fruit> {
private int resourceId;
public FruitAdapter(Context context, int resourceId, List<Fruit> objects) {
super(context, resourceId, objects);
this.resourceId = resourceId;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Fruit fruit = getItem(position);
ViewHolder holder;
if (convertView == null) {
convertView = LayoutInflater.from(getContext())
.inflate(resourceId, parent, false);
holder = new ViewHolder();
holder.image = convertView.findViewById(R.id.fruit_image);
holder.name = convertView.findViewById(R.id.fruit_name);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.image.setImageResource(fruit.getImageId());
holder.name.setText(fruit.getName());
return convertView;
}
static class ViewHolder {
ImageView image;
TextView name;
}
}
第四步:在 Activity 中绑定
java
ListView listView = findViewById(R.id.list_view);
FruitAdapter adapter = new FruitAdapter(this, R.layout.fruit_item, fruitList);
listView.setAdapter(adapter);
// 设置列表项点击事件
listView.setOnItemClickListener((parent, view, position, id) -> {
Fruit fruit = fruitList.get(position);
Toast.makeText(this, "你点击了:" + fruit.getName(), Toast.LENGTH_SHORT).show();
});
3.6 RecyclerView ------ 更强大的列表
RecyclerView 是 ListView 的升级版,Google 官方推荐使用。相比 ListView,它:
- 强制使用 ViewHolder 模式,性能更好
- 支持线性列表、网格、瀑布流等多种布局
- 内置条目动画支持
- 更灵活的局部刷新机制
java
// RecyclerView 的基本使用
RecyclerView recyclerView = findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(this)); // 线性布局
recyclerView.setAdapter(new FruitRecyclerAdapter(fruitList));
3.7 Toast ------ 轻量提示
Toast 是一个纯代码创建的控件,无需在 XML 中声明。
java
Toast.makeText(context, "提示文字", Toast.LENGTH_SHORT).show();
| 时长常量 | 显示时间 |
|---|---|
Toast.LENGTH_SHORT |
约 2 秒 |
Toast.LENGTH_LONG |
约 3.5 秒 |
3.8 CheckBox 与 RadioButton
xml
<!-- 复选框 -->
<CheckBox
android:id="@+id/agree"
android:text="我同意用户协议" />
<!-- 单选按钮(需配合 RadioGroup) -->
<RadioGroup
android:orientation="horizontal">
<RadioButton android:text="男" />
<RadioButton android:text="女" />
</RadioGroup>
3.9 Switch(开关)
xml
<Switch
android:id="@+id/switch_wifi"
android:text="Wi-Fi"
android:checked="true" />
设置监听:
java
Switch sw = findViewById(R.id.switch_wifi);
sw.setOnCheckedChangeListener((buttonView, isChecked) -> {
if (isChecked) {
// 开启
} else {
// 关闭
}
});
3.10 SeekBar(滑动条)
xml
<SeekBar
android:id="@+id/progress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="100"
android:progress="50" />
四、ViewHolder 性能优化详解
在 ListView 或 RecyclerView 的使用中,ViewHolder 模式是必须掌握的性能优化技巧。
为什么需要优化?
findViewById() 会遍历整个 View 树来查找控件,是一个非常耗时 的操作。当用户快速滚动列表时,如果每个 item 都重新执行 findViewById(),就会导致界面卡顿。
ViewHolder 的工作原理
┌─────────────────┐
│ ListView 滑动 │
└────────┬────────┘
│
┌────────────────┼────────────────┐
▼ ▼ ▼
┌────────────┐ ┌────────────┐ ┌────────────┐
│ Item A │ │ Item B │ │ Item C │
│ (可见) │ │ (可见) │ │ (可见) │
└────────────┘ └────────────┘ └────────────┘
│
滑出屏幕的 Item 被回收为 convertView
│
▼
新的 Item 复用 convertView
无需重新 inflate 布局
核心代码逻辑:
java
if (convertView == null) {
// 没有可复用的 View → 创建新的,并缓存控件引用
convertView = inflater.inflate(resourceId, parent, false);
holder = new ViewHolder();
holder.text = convertView.findViewById(R.id.text); // 仅第一次执行
convertView.setTag(holder); // 将 ViewHolder 绑定到 View
} else {
// 有可复用的 View → 直接取出缓存的控件引用
holder = (ViewHolder) convertView.getTag(); // 瞬间取出
}
性能对比:
| 方式 | 每次滑动 | 流畅度 |
|---|---|---|
| 不用 ViewHolder | 重新 findViewById + 重新 inflate |
卡顿 |
| 复用 convertView | 重新 findViewById(但不用 inflate) |
一般 |
| ViewHolder 模式 | 直接从 Tag 取出引用 | 流畅 |
五、常见事件监听总结
| 监听器 | 适用控件 | 触发时机 |
|---|---|---|
View.OnClickListener |
Button、ImageView 等 | 点击 |
View.OnLongClickListener |
大部分控件 | 长按 |
View.OnTouchListener |
大部分控件 | 触摸 |
AdapterView.OnItemClickListener |
ListView 等 | 点击列表项 |
CompoundButton.OnCheckedChangeListener |
CheckBox、Switch | 选中状态改变 |
SeekBar.OnSeekBarChangeListener |
SeekBar | 进度改变 |
TextWatcher |
EditText | 文字内容改变 |
六、总结
本文从零开始,介绍了 Android 开发中最核心的 UI 基础知识:
| 知识模块 | 核心内容 |
|---|---|
| 四大布局 | LinearLayout、RelativeLayout、ConstraintLayout、FrameLayout |
| 核心属性 | match_parent/wrap_content、dp/sp、margin/padding、gravity |
| 基础控件 | TextView、EditText、Button、ImageView |
| 列表控件 | ListView + 自定义 Adapter + ViewHolder 优化 |
| 交互控件 | CheckBox、RadioButton、Switch、SeekBar |
| 事件处理 | 点击、长按、状态改变、文本变化等监听器 |
掌握了这些内容,你就具备了独立搭建 Android App 界面的能力。后续可以进一步学习 Material Design、自定义 View、Jetpack Compose 等更高级的 UI 开发技术。