5、常用UI控件(上):TextView文本控件、Button按钮与点击事件、EditText输入框、ImageView图片显示、ProgressBar进度条

各位同学,今天我们来聊聊Android开发里最基础、也最常用的一批UI控件。说实话,不管你现在做的是社交App、电商App还是工具类应用,这几个控件你几乎天天都要打交道。我刚开始学Android那会儿,就是靠这几个控件搭出了第一个能用的界面——虽然丑了点,但那种成就感,嗯,至今还记得。

本章核心知识点一览:

  • TextView —— 显示文本,最基础的输出控件
  • Button —— 可点击的按钮,用户交互的入口
  • EditText —— 接收用户输入,与用户对话的窗口
  • ImageView —— 展示图片,让界面活起来
  • ProgressBar —— 告诉用户“正在加载,别急”
常用UI控件(上)知识体系 5大基础控件 TextView Button + 点击事件 EditText ImageView ProgressBar 文字显示、样式、跑马灯 setOnClickListener 输入监听、hint、密码模式 src、scaleType、加载网络图 圆形、水平、自定义样式 掌握这5个控件,你已经能写出80%的常见界面

5.1 TextView —— 最朴实的文本展示者

TextView是Android里最基础的控件,没有之一。它的任务很简单:把一段文字显示在屏幕上。但你想想看,就这么一个简单的控件,Google给它配了几十个属性——说明什么?说明“显示文字”这件事,其实有很多讲究。

我个人习惯在布局文件里这样定义一个TextView:

<TextView
    android:id="@+id/tv_hello"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="你好,Android!"
    android:textSize="18sp"
    android:textColor="#333333"
    android:textStyle="bold"
    android:gravity="center"
    android:padding="12dp" />

这里有几个属性我想重点说一下:

  • textSize:单位用sp,别用dp。为什么?因为sp会跟随系统字体缩放,照顾视力不好的用户。我在项目里见过有人用dp写死,结果用户把系统字体调大后,界面直接崩了布局。
  • gravity:控制文字在控件内部的对齐方式。注意它和layout_gravity的区别——前者是内部对齐,后者是控件在父容器里的对齐。初学者经常搞混。
  • maxLines / ellipsize:限制行数,超出部分用省略号。做新闻列表时这个很常用。

小技巧:如果你想让TextView实现跑马灯效果(文字滚动显示),需要同时设置:android:singleLine="true"android:ellipsize="marquee"android:marqueeRepeatLimit="marquee_forever",并且TextView必须获取焦点。我曾经踩过这个坑——忘了让控件获取焦点,跑马灯死活不滚。

5.2 Button与点击事件 —— 用户交互的第一步

Button本质上就是TextView加了一个点击背景。但它的核心价值不在于外观,而在于——点击事件。说白了,用户点一下按钮,App得知道该干什么。

在XML里定义一个Button很简单:

<Button
    android:id="@+id/btn_submit"
    android:layout_width="match_parent"
    android:layout_height="48dp"
    android:text="提交"
    android:textAllCaps="false" />

注意textAllCaps="false"这个属性。Android 5.0之后,Button默认会把所有字母转成大写。如果你不想这样,记得加上这个属性。我当年第一次做App时,明明写的是“Submit”,运行出来变成“SUBMIT”,还以为是手机坏了……

处理点击事件,目前最推荐的方式是用Lambda表达式:

Button btnSubmit = findViewById(R.id.btn_submit);
btnSubmit.setOnClickListener(v -> {
    // 在这里写点击后的逻辑
    Toast.makeText(this, "按钮被点击了", Toast.LENGTH_SHORT).show();
});

为什么推荐Lambda?因为它简洁。你想想看,如果用匿名内部类,得写一大坨:

btnSubmit.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // 逻辑代码
    }
});

嗯,两种写法都能跑。但我建议你从现在开始就用Lambda,代码看起来清爽很多。

注意:千万不要在XML里用android:onClick="方法名"这种方式。虽然它也能用,但会让代码耦合严重,而且方法签名必须严格匹配——我曾经因为这个方式导致一个线上bug,排查了半天才发现是方法名拼写错了。

5.3 EditText —— 让用户输入内容

EditText是用户和App对话的窗口。用户打字进来,App读取处理。看似简单,但坑不少。

先看一个标准的输入框定义:

<EditText
    android:id="@+id/et_username"
    android:layout_width="match_parent"
    android:layout_height="48dp"
    android:hint="请输入用户名"
    android:inputType="text"
    android:maxLines="1"
    android:background="@drawable/bg_edittext" />

几个关键点:

  • hint:提示文本,用户输入后自动消失。别用text属性来当提示,那不会消失。
  • inputType:控制键盘类型。输入密码用textPassword,输入数字用number,输入邮箱用textEmailAddress。这个属性直接影响用户体验——你总不想让用户输数字时弹出全键盘吧?
  • maxLines:限制行数。单行输入设成1,多行输入可以设成3或5。

获取用户输入的内容,代码是这样:

EditText etUsername = findViewById(R.id.et_username);
String username = etUsername.getText().toString().trim();

注意一定要调toString(),因为getText()返回的是Editable对象,不是String。另外trim()去掉首尾空格——用户有时候会不小心多打空格,这个处理能省很多麻烦。

监听输入变化:如果你想实时知道用户输入了什么(比如搜索框的自动补全),可以用addTextChangedListener。我记得有一次做登录界面,需要实时检测密码长度是否达标,就是用这个监听器实现的。

5.4 ImageView —— 一图胜千言

一个没有图片的App,就像一本没有插图的教科书——干巴巴的。ImageView就是用来展示图片的。

最基础的使用方式:

<ImageView
    android:id="@+id/iv_avatar"
    android:layout_width="80dp"
    android:layout_height="80dp"
    android:src="@drawable/ic_avatar"
    android:scaleType="centerCrop" />

scaleType这个属性,我建议你花点时间搞明白。它决定了图片怎么适配到ImageView的尺寸里:

scaleType值 效果 适用场景
centerCrop 按比例缩放,裁剪多余部分,填满控件 头像、封面图(最常用)
fitCenter 按比例缩放,完整显示,可能有留白 展示完整图片
fitXY 拉伸填满,不保持比例 背景图(但会变形,慎用)
center 不缩放,居中显示 小图标

在代码里动态设置图片也很常见:

ImageView ivAvatar = findViewById(R.id.iv_avatar);
ivAvatar.setImageResource(R.drawable.ic_avatar);
// 或者从网络加载(需要Glide或Picasso等库)
Glide.with(this).load("https://example.com/avatar.jpg").into(ivAvatar);

内存警告:直接加载大图到ImageView,很容易OOM(内存溢出)。我曾经在一个列表里直接加载了高清壁纸,结果App在低端机上秒崩。解决方案是用Glide或Picasso这类图片加载库,它们会自动做压缩和缓存。

5.5 ProgressBar —— 给用户一点耐心

网络请求、文件下载、数据加载……这些操作都需要时间。如果界面一动不动,用户会以为App卡死了。ProgressBar就是用来告诉用户:“别急,正在干活呢。”

Android提供了两种进度条样式:

  • 圆形(不确定进度):不知道还要等多久,就用它。比如加载数据时。
  • 水平(确定进度):知道具体进度百分比,比如下载文件时。

XML定义:

<!-- 圆形进度条 -->
<ProgressBar
    android:id="@+id/progress_circular"
    android:layout_width="48dp"
    android:layout_height="48dp"
    android:visibility="gone" />

<!-- 水平进度条 -->
<ProgressBar
    android:id="@+id/progress_horizontal"
    style="?android:attr/progressBarStyleHorizontal"
    android:layout_width="match_parent"
    android:layout_height="12dp"
    android:max="100"
    android:progress="0"
    android:visibility="gone" />

在代码里控制进度条:

// 显示/隐藏圆形进度条
ProgressBar progressCircular = findViewById(R.id.progress_circular);
progressCircular.setVisibility(View.VISIBLE);  // 显示
progressCircular.setVisibility(View.GONE);     // 隐藏

// 更新水平进度条
ProgressBar progressHorizontal = findViewById(R.id.progress_horizontal);
progressHorizontal.setProgress(50);  // 设置到50%

使用建议:我个人习惯在请求网络数据时,先显示圆形进度条,数据回来后再隐藏。如果是文件下载,就用水平进度条实时更新进度。另外,别忘了设置android:visibility="gone"——默认隐藏,需要时再显示。不然一进页面就看到一个转圈圈,用户会懵的。

5.6 综合小案例:登录界面

学完了这几个控件,我们来把它们串起来。做一个简单的登录界面,包含:用户名输入框、密码输入框、登录按钮、加载进度条。

XML布局:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="24dp"
    android:gravity="center">

    <ImageView
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:src="@drawable/ic_logo"
        android:layout_marginBottom="32dp" />

    <EditText
        android:id="@+id/et_username"
        android:layout_width="match_parent"
        android:layout_height="48dp"
        android:hint="请输入用户名"
        android:inputType="text"
        android:maxLines="1"
        android:background="@android:drawable/editbox_background"
        android:layout_marginBottom="16dp" />

    <EditText
        android:id="@+id/et_password"
        android:layout_width="match_parent"
        android:layout_height="48dp"
        android:hint="请输入密码"
        android:inputType="textPassword"
        android:maxLines="1"
        android:background="@android:drawable/editbox_background"
        android:layout_marginBottom="24dp" />

    <Button
        android:id="@+id/btn_login"
        android:layout_width="match_parent"
        android:layout_height="48dp"
        android:text="登录"
        android:textAllCaps="false" />

    <ProgressBar
        android:id="@+id/progress_loading"
        android:layout_width="32dp"
        android:layout_height="32dp"
        android:layout_marginTop="16dp"
        android:visibility="gone" />

</LinearLayout>

Java代码:

public class LoginActivity extends AppCompatActivity {

    private EditText etUsername, etPassword;
    private Button btnLogin;
    private ProgressBar progressLoading;

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

        etUsername = findViewById(R.id.et_username);
        etPassword = findViewById(R.id.et_password);
        btnLogin = findViewById(R.id.btn_login);
        progressLoading = findViewById(R.id.progress_loading);

        btnLogin.setOnClickListener(v -> {
            String username = etUsername.getText().toString().trim();
            String password = etPassword.getText().toString().trim();

            if (username.isEmpty() || password.isEmpty()) {
                Toast.makeText(this, "用户名和密码不能为空", Toast.LENGTH_SHORT).show();
                return;
            }

            // 显示加载进度条
            progressLoading.setVisibility(View.VISIBLE);
            btnLogin.setEnabled(false);

            // 模拟网络请求
            new Handler().postDelayed(() -> {
                progressLoading.setVisibility(View.GONE);
                btnLogin.setEnabled(true);
                Toast.makeText(this, "登录成功", Toast.LENGTH_SHORT).show();
            }, 2000);
        });
    }
}

这个案例虽然简单,但包含了本章所有控件的使用。你想想看,实际项目中的登录界面,无非就是在这个基础上加一些校验、加密、网络请求的封装。核心逻辑是一样的。

本章总结:TextView负责展示文字,Button负责接收点击,EditText负责收集输入,ImageView负责展示图片,ProgressBar负责反馈进度。这五个控件组合起来,已经能搭建出大部分常见的界面了。我建议你动手写一遍上面的登录案例,把每个控件的属性都调一调、改一改,看看效果变化。实践出真知,光看代码是记不住的。


公众号:蓝海资料掘金营,微信deep3321