6、常用UI控件:TextView、Button、EditText、ImageView、CheckBox、RadioButton的使用与事件监听
说实话,Android开发入门最绕不开的就是这几个基础控件。我刚开始带团队时,发现很多新人上来就追求花哨的自定义View,结果连最基本的TextView属性都没吃透。嗯,今天我们就踏踏实实把这六个控件的用法捋一遍。
6.1 TextView — 不只是显示文字
TextView是Android里最基础的控件,没有之一。说白了,它就是用来展示文本的。但你别小看它,我见过太多人连基本的跑马灯效果都写不对。
我个人习惯在布局里这样配置TextView:
<TextView
android:id="@+id/tvHello"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="你好,Android!"
android:textSize="16sp"
android:textColor="#333333"
android:gravity="center"
android:padding="12dp"/>
TextView的事件监听其实很简单,但它默认是不可点击的。如果你想让它响应点击,需要设置android:clickable="true",或者直接在代码里设setOnClickListener。
TextView tvHello = findViewById(R.id.tvHello);
tvHello.setOnClickListener(v -> {
Toast.makeText(this, "TextView被点击了", Toast.LENGTH_SHORT).show();
});
6.2 Button — 点击事件的灵魂
Button继承自TextView,所以TextView的属性它基本都有。但Button自带一个默认的背景样式,不同Android版本长得还不一样。你想想看,这多坑?
我建议你这样做:
<Button
android:id="@+id/btnSubmit"
android:layout_width="match_parent"
android:layout_height="48dp"
android:text="提交"
android:textAllCaps="false"
android:background="@drawable/btn_bg_rounded"/>
android:textAllCaps="false"。我曾经有个项目上线后,用户反馈按钮文字怎么全是大写的,就是忘了加这个属性。
事件监听最常用的就是点击和长按:
Button btnSubmit = findViewById(R.id.btnSubmit);
btnSubmit.setOnClickListener(v -> {
// 处理点击事件
Log.d("TAG", "按钮被点击了");
});
btnSubmit.setOnLongClickListener(v -> {
// 处理长按事件
Toast.makeText(this, "长按触发", Toast.LENGTH_SHORT).show();
return true; // 返回true表示消费事件
});
6.3 EditText — 用户输入的入口
EditText是用户和App交互的重要通道。我见过很多新手直接把EditText扔上去,既不设输入类型,也不做限制,结果用户什么乱七八糟的内容都能输进去。
来看一个比较规范的配置:
<EditText
android:id="@+id/etPhone"
android:layout_width="match_parent"
android:layout_height="48dp"
android:hint="请输入手机号"
android:inputType="phone"
android:maxLength="11"
android:singleLine="true"
android:background="@drawable/edit_bg"/>
EditText的事件监听主要有两种:
- 文本变化监听 — 用
TextWatcher接口 - 焦点变化监听 — 用
setOnFocusChangeListener
EditText etPhone = findViewById(R.id.etPhone);
etPhone.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// 文本变化前调用
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// 文本变化中调用
String input = s.toString();
// 实时校验输入
}
@Override
public void afterTextChanged(Editable s) {
// 文本变化后调用
}
});
6.4 ImageView — 图片展示的利器
ImageView用来显示图片,支持本地资源、网络图片、Bitmap等多种来源。我个人习惯用android:scaleType来控制图片的缩放方式,这个属性太重要了。
<ImageView
android:id="@+id/ivAvatar"
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@drawable/ic_default_avatar"
android:scaleType="centerCrop"
android:contentDescription="用户头像"/>
| scaleType值 | 效果说明 |
|---|---|
| center | 居中显示,不缩放 |
| centerCrop | 按比例缩放,裁剪多余部分(最常用) |
| fitXY | 拉伸填满,会变形 |
| fitCenter | 按比例缩放,完整显示 |
ImageView的点击监听和Button一样:
ImageView ivAvatar = findViewById(R.id.ivAvatar);
ivAvatar.setOnClickListener(v -> {
// 点击头像,跳转到个人主页
startActivity(new Intent(this, ProfileActivity.class));
});
6.5 CheckBox — 多选场景的标配
CheckBox用于多选场景,比如用户选择兴趣爱好。它继承自CompoundButton,所以有选中状态的概念。
<CheckBox
android:id="@+id/cbAgree"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="我已阅读并同意用户协议"
android:checked="false"/>
监听选中状态变化:
CheckBox cbAgree = findViewById(R.id.cbAgree);
cbAgree.setOnCheckedChangeListener((buttonView, isChecked) -> {
if (isChecked) {
// 用户勾选了
btnSubmit.setEnabled(true);
} else {
// 用户取消了勾选
btnSubmit.setEnabled(false);
}
});
setOnCheckedChangeListener和setOnClickListener不要混用。如果你同时设置了这两个监听器,点击时它们都会触发,但执行顺序可能不是你想要的。我一般只用setOnCheckedChangeListener。
6.6 RadioButton — 单选组的实现
RadioButton必须配合RadioGroup使用,才能实现单选效果。你想想看,如果不用RadioGroup,那每个RadioButton都是独立的,用户就能全选了,那还叫单选吗?
<RadioGroup
android:id="@+id/rgGender"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<RadioButton
android:id="@+id/rbMale"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="男"
android:checked="true"/>
<RadioButton
android:id="@+id/rbFemale"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="女"/>
</RadioGroup>
监听RadioGroup的选择变化:
RadioGroup rgGender = findViewById(R.id.rgGender);
rgGender.setOnCheckedChangeListener((group, checkedId) -> {
if (checkedId == R.id.rbMale) {
// 选择了男
Log.d("TAG", "性别:男");
} else if (checkedId == R.id.rbFemale) {
// 选择了女
Log.d("TAG", "性别:女");
}
});
setOnCheckedChangeListener和RadioButton的setOnCheckedChangeListener是两回事。RadioGroup的监听器会告诉你哪个RadioButton被选中了,而RadioButton自己的监听器会在它自身状态变化时触发。我建议你只用RadioGroup的监听器,逻辑更清晰。
6.7 综合实战:一个简单的注册表单
光说不练假把式。我们把这些控件组合起来,做一个简单的注册表单。这个例子我在实际项目中用过类似的。
// 布局文件 activity_register.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="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="用户名"
android:textSize="14sp"
android:textColor="#666"/>
<EditText
android:id="@+id/etUsername"
android:layout_width="match_parent"
android:layout_height="48dp"
android:hint="请输入用户名"
android:inputType="text"
android:maxLength="20"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="性别"
android:textSize="14sp"
android:textColor="#666"
android:layout_marginTop="12dp"/>
<RadioGroup
android:id="@+id/rgGender"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<RadioButton
android:id="@+id/rbMale"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="男"
android:checked="true"/>
<RadioButton
android:id="@+id/rbFemale"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="女"/>
</RadioGroup>
<CheckBox
android:id="@+id/cbAgree"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="我已阅读并同意用户协议"
android:layout_marginTop="12dp"/>
<Button
android:id="@+id/btnRegister"
android:layout_width="match_parent"
android:layout_height="48dp"
android:text="注册"
android:textAllCaps="false"
android:enabled="false"
android:layout_marginTop="24dp"/>
<ImageView
android:id="@+id/ivLogo"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/ic_logo"
android:scaleType="centerCrop"
android:layout_gravity="center_horizontal"
android:layout_marginTop="24dp"/>
</LinearLayout>
// 注册逻辑 RegisterActivity.java
public class RegisterActivity extends AppCompatActivity {
private EditText etUsername;
private CheckBox cbAgree;
private Button btnRegister;
private RadioGroup rgGender;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_register);
etUsername = findViewById(R.id.etUsername);
cbAgree = findViewById(R.id.cbAgree);
btnRegister = findViewById(R.id.btnRegister);
rgGender = findViewById(R.id.rgGender);
// 监听协议勾选状态
cbAgree.setOnCheckedChangeListener((buttonView, isChecked) -> {
btnRegister.setEnabled(isChecked);
});
// 监听用户名输入
etUsername.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// 实时校验用户名长度
if (s.length() > 0 && s.length() < 3) {
etUsername.setError("用户名至少3个字符");
}
}
@Override
public void afterTextChanged(Editable s) {}
});
// 注册按钮点击
btnRegister.setOnClickListener(v -> {
String username = etUsername.getText().toString().trim();
int selectedGenderId = rgGender.getCheckedRadioButtonId();
RadioButton selectedGender = findViewById(selectedGenderId);
String gender = selectedGender.getText().toString();
Toast.makeText(this,
"注册成功!用户名:" + username + ",性别:" + gender,
Toast.LENGTH_SHORT).show();
});
// 点击Logo跳转
ImageView ivLogo = findViewById(R.id.ivLogo);
ivLogo.setOnClickListener(v -> {
Toast.makeText(this, "欢迎使用本应用", Toast.LENGTH_SHORT).show();
});
}
}
这个例子涵盖了今天讲的所有控件。你仔细看,每个控件都发挥了它该有的作用。TextView展示标签,EditText接收输入,RadioGroup做性别选择,CheckBox控制协议同意,Button执行注册,ImageView展示Logo。各司其职,互不干扰。
好了,这六个控件的基本用法和事件监听就讲到这里。记住一点:基础控件虽然简单,但用好了能解决80%的UI需求。别总想着炫技,先把基础打扎实了。
公众号:蓝海资料掘金营,微信deep3321