Android给我们提供了大量的UI控件,下面我们就挑选几种常用的控件,详细介绍一下它们的使用方法。首先新建一个UIWidgetTest项目。
1、TextView
TextView可以说是Android中最简单的一个控件了,我们在前面其实也已经和它打过了一些打交道。
它主要用于在界面上显示一段文本信息,比如我们在之前看到的Hello world!
下面我们就来看一看关于TextView的更多用法。
将activity_main.xml中的代码改成如下所示:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" >
<TextView android:id="@+id/tvMessage" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="这是一个文本控件" /> </LinearLayout>
外面的LinearLayout先忽略不看,在TextView中我们使用android:id给当前控件定义了一个唯一标识符。
然后使用android:layout_width指定了控件的宽度,使用android:layout_height指定了控件的高度。
Android中所有的控件都具有这两个属性,可选值有三种match_parent、fill_parent和wrap_content,其中match_parent和fill_parent的意义相同,现在官方更加推荐使用match_parent。
- match_parent(填充父窗口)表示让当前控件的大小和父布局的大小一样,也就是由父布局来决定当前控件的大小。
- wrap_content(内容包裹)表示让当前控件的大小能够刚好包含住里面的内容,也就是由控件内容决定当前控件的大小。
所以上面的代码就表示让TextView的宽度和父布局一样宽,也就是手机屏幕的宽度,让TextView的高度足够包含住里面的内容就行。当然除了使用上述值,你也可以对控件的宽和高指定一个固定的值,但是这样做有时会在不同手机屏幕的适配方面出现问题。接下来我们通过android:text指定了TextView中显示的文本内容,现在运行程序,效果如图所示。
虽然指定的文本内容是正常显示了,不过我们好像没看出来TextView的宽度是和屏幕一样宽的。其实这是由于TextView中的文字默认是居左上角对齐的,虽然TextView的宽度充满了整个屏幕,可是从效果上完全看不出来。现在我们修改TextView的文字对齐方式,如下所示:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/tvMessage" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:text="这是一个文本控件" /> </LinearLayout>
我们使用android:gravity来指定文字的对齐方式(文字在控件中的对齐方式),可选值有top、bottom、left、right、center等,可以用“|”来同时指定多个值(中间不要有空格),这里我们指定的“center”,效果等同于“center_vertical|center_horizontal”,表示文字在垂直和水平方向都居中对齐。现在重新运行程序,效果如图所示。
这也说明了,TextView的宽度确实是和屏幕宽度一样的。
那么有的同学会问,指定的“center”,为什么垂直方向上没有居中呢?
因为我们指定的这个TextView控件的高度是“wrap_content”(内容包裹),这个控件的高度并没有占满整个屏幕,我们把高度修改为“match_parent”,再看看效果。
另外,我们还可以对TextView中文字的大小和颜色进行修改,如下所示:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/tvMessage" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:text="这是一个文本控件" android:textColor="#00ff00" android:textSize="24sp" /> </LinearLayout>
通过android:textSize属性可以指定文字的大小,通过android:textColor属性可以指定文字的颜色。重新运行程序,效果如图所示。
其他属性介绍:
属性 |
说明 |
android:textStyle |
设置字形。属性值:bold、italic,多个时用“|”隔开 |
android:singleLine |
设置单行显示。属性值:true、false,显示不全时后面用“...”来表示。 |
android:maxLength |
限制显示字符数。如设置为8,那么仅可以输入8个汉字/数字/英文字母。 |
android:lines |
设置文本的行数,设置两行就显示两行,即使第二行没有数据。类似android:minLines属性。 |
android:maxLines |
设置文本的最大显示行数,与width或者layout_width结合使用,超出部分自动换行,超出行数将不显示。 |
android:lineSpacingExtra |
设置行间距。例如,"25dp" |
android:lineSpacingMultiplier |
设置行间距的倍数。例如,"1.2" |
2、Button
Button是程序用于和用户进行交互的一个重要控件,相信你对这个控件已经是非常熟悉了,因为我们之前用了太多次Button。
它可配置的属性和TextView是差不多的,我们可以在activity_main.xml中这样加入Button:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/tvMessage" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:text="这是一个文本控件" android:textColor="#00ff00" android:textSize="24sp" /> <Button android:id="@+id/button" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="按钮" /> </LinearLayout>
加入Button之后的界面如图所示。
属性 |
说明 |
android:background |
背景图,background即可以是颜色,也可以是图片。例如,"#ff0000" ,"@drawable/orange_pic" |
android:drawableTop android:drawableBottom android:drawableLeft android:drawableRight |
上下左右的图片。例如,"@drawable/oranger_pic"
|
Button既然要交互,我们就要为Button添加点击事件:
(1)匿名内部类的方式
public class MainActivity extends AppCompatActivity { private Button button; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); button = (Button) findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener() { //匿名类 @Override public void onClick(View v) { // 在此处添加逻辑 } }); } }
(2)实现接口的方式
public class MainActivity extends AppCompatActivity implements View.OnClickListener { //实现接口 private Button button; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); button = (Button) findViewById(R.id.button); button.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.button: // 在此处添加逻辑 break; } } }
(3)在布局文件中显式指定按钮的onClick属性(不推荐使用)
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/tvMessage" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:text="这是一个文本控件" android:textColor="#00ff00" android:textSize="24sp" /> <Button android:id="@+id/button" android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="btnClick" android:text="按钮" /> </LinearLayout>
然后在MainActivity中添加btnClick()方法:
public void btnClick(View v) { // 在此处添加逻辑 }
这样按钮点击时会利用反射的方式调用对应Activity中的btnClick()方法。这里注意,自定义的btnClick()方法一定要有View类型的形式参数。
这三种写法都可以实现对按钮点击事件的监听,至于使用哪一种就全凭你喜好了。
3、EditText
EditText是程序用于和用户进行交互的另一个重要控件,它允许用户在控件里输入和编辑内容,并可以在程序中对这些内容进行处理。
EditText的应用场景应该算是非常普遍了,发短信、发微博、聊QQ等等,在进行这些操作时,你不得不使用到EditText。
那我们来看一看如何在界面上加入EditText吧,修改activity_main.xml中的代码,如下所示:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/tvMessage" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:text="这是一个文本控件" android:textColor="#00ff00" android:textSize="24sp" /> <Button android:id="@+id/button" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="按钮" /> <EditText android:id="@+id/editText" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout>
Android控件的基本上用法都很相似,给控件定义一个id,再指定下控件的宽度和高度,然后再适当加入些控件特有的属性就差不多了。
所以使用XML来编写界面其实一点都不难,完全可以不用借助任何可视化工具来实现。
现在重新运行一下程序,EditText就已经在界面上显示出来了,并且我们是可以在里面输入内容的,如图所示。
细心的你平时应该会留意到,一些做得比较人性化的软件会在输入框里显示一些提示性的文字,然后一旦用户输入了任何内容,这些提示性的文字就会消失。
这种提示功能在Android里是非常容易实现的,我们甚至不需要做任何的逻辑控制,因为系统已经帮我们都处理好了。修改activity_main.xml,如下所示:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/tvMessage" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:text="这是一个文本控件" android:textColor="#00ff00" android:textSize="24sp" /> <Button android:id="@+id/button" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="按钮" /> <EditText android:id="@+id/editText" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="输入文字信息" /> </LinearLayout>
使用android:hint属性来指定了一段提示性的文本,然后重新运行程序,如图所示。
可以看到,EditText中显示了一段提示性文本,然后当我们输入任何内容时,这段文本就会自动消失。
不过随着输入的内容不断增多,EditText会被不断地拉长。
这时由于EditText的高度指定的是wrap_content,因此它总能包含住里面的内容,但是当输入的内容过多时,界面就会变得非常难看。
我们可以使用android:maxLines属性来解决这个问题,修改activity_main.xml,如下所示:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/tvMessage" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:text="这是一个文本控件" android:textColor="#00ff00" android:textSize="24sp" /> <Button android:id="@+id/button" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="按钮" /> <EditText android:id="@+id/editText" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="输入文字信息" android:maxLines="2" /> </LinearLayout>
这里通过android:maxLines指定了EditText的最大行数为两行,这样当输入的内容超过两行时,文本就会向上滚动,而EditText则不会再继续拉伸,如图所示。
另外,EditText还可以通过给android:inputType属性设置"number"、"textPassword"、"datetime"、"date"、"time"等值,设置文本输入的格式。
我们还可以结合使用EditText与Button来完成一些功能,比如通过点击按钮来获取EditText中输入的内容。修改MainActivity中的代码,如下所示:
package com.sdbi.uiwidgettest; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; public class MainActivity extends AppCompatActivity implements View.OnClickListener { // 实现接口 private Button button; private EditText editText; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); button = (Button) findViewById(R.id.button); editText = (EditText) findViewById(R.id.editText); button.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.button: String inputText = editText.getText().toString(); Toast.makeText(MainActivity.this, inputText, Toast.LENGTH_SHORT).show(); break; } } }
首先通过findViewById()方法得到EditText的实例,然后在按钮的点击事件里调用EditText的getText()方法获取到输入的内容,再调用toString()方法转换成字符串,最后仍然还是老方法,使用Toast将输入的内容显示出来。
重新运行程序,在EditText中输入一段内容,然后点击按钮,效果如图所示。
4、ImageView
ImageView是用于在界面上展示图片的一个控件,通过它可以让我们的程序界面变得更加丰富多彩。
使用这个控件需要提前准备好一些图片,由于目前mipmap文件夹下已经有一张ic_launcher.png图片了,那我们就先在界面上展示这张图吧,修改activity_main.xml,如下所示:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/tvMessage" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:text="这是一个文本控件" android:textColor="#00ff00" android:textSize="24sp" /> <Button android:id="@+id/button" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="按钮" /> <EditText android:id="@+id/editText" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="输入文字信息" android:inputType="" android:maxLines="2" /> <ImageView android:id="@+id/imageView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@mipmap/ic_launcher" /> </LinearLayout>
注意:资源文件的文件名只能包含小写a-z,0-9,或者下划线。否则,会报错!
可以看到,这里使用android:src属性给ImageView指定了一张图片,并且由于图片的宽和高都是未知的,所以将ImageView的宽和高都设定为wrap_content,这样保证了不管图片的尺寸是多少都可以完整地展示出来。重新运行程序,效果如图所示。
我们还可以在程序中通过代码动态地更改ImageView中的图片。
这里我准备了另外一张图片,orange_pic.png(桔子),将它复制到res/drawable目录下,然后修改MainActivity的代码,如下所示:
package com.sdbi.uiwidgettest; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.ImageView; import android.widget.Toast; public class MainActivity extends AppCompatActivity implements View.OnClickListener { // 实现接口 private Button button; private EditText editText; private ImageView imageView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); button = (Button) findViewById(R.id.button); editText = (EditText) findViewById(R.id.editText); imageView = (ImageView) findViewById(R.id.imageView); button.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.button: imageView.setImageResource(R.drawable.orange_pic); break; } } }
在按钮的点击事件里,通过调用ImageView的setImageResource()方法将显示的图片改成R.drawable.orange_pic,现在重新运行程序,然后点击一下按钮,就可以看到ImageView中显示的图片改变了,如图所示。
注意:在JAVA文件中使用资源ID,用R.drawable.;
在XML文件中使用资源ID,用@drawable/。
5、ProgressBar
ProgressBar用于在界面上显示一个进度条,表示我们的程序正在加载一些数据。它的用法也非常简单,修改activity_main.xml中的代码,如下所示:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/tvMessage" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:text="这是一个文本控件" android:textColor="#00ff00" android:textSize="24sp" /> <Button android:id="@+id/button" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="按钮" /> <EditText android:id="@+id/editText" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="输入文字信息" android:inputType="" android:maxLines="2" /> <ImageView android:id="@+id/imageView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@mipmap/ic_launcher" /> <ProgressBar android:id="@+id/progressBar" style="?android:attr/progressBarStyleHorizontal" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout>
重新运行程序,会看到屏幕中有一个圆形进度条正在旋转,如图所示。
旋转的进度条表明我们的程序正在加载数据,如何才能让进度条在数据加载完成时消失呢?这里我们就需要用到Android控件的可见属性。
所有的Android控件都具有这个属性,可以通过android:visibility进行指定,另外我们还可以在逻辑代码中通过setVisibility()方法设置控件的可见性,通过getVisibility()方法获取控件的可见性。
android:visibility属性值 |
含义 |
setVisibility()方法参数值 |
visible |
可见,表示控件是可见的,这个值是默认值,不指定android:visibility时,控件都是可见的。 |
View.VISIBLE |
invisible |
透明,表示控件不可见,但是它仍然占据着原来的位置和大小,可以理解成控件变成透明状态了。 |
View.INVISIBLE |
gone |
消失,表示控件不仅不可见,而且不再占用任何屏幕空间。 |
View.GONE |
在逻辑代码中,我们还是通过findViewById(R.id.progressBar)方法获得progressBar对象,然后按钮对象增加控制代码,来控制控件的可见、透明、消失,代码如下:
if (progressBar.getVisibility() == View.VISIBLE) { progressBar.setVisibility(View.GONE); } else { progressBar.setVisibility(View.VISIBLE); }
如果我们要使用水平进度条,我们可以通过在布局文件中,给<ProgressBar>控件指定style属性来设置。style属性的值可以是:
- ?android:attr/progressBarStyleHorizontal
- ?android:progressBarStyleHorizontal
- @style/Widget.AppCompat.ProgressBar.Horizontal
- @style/Base.Widget.AppCompat.ProgressBar.Horizontal
- @android:style/Widget.ProgressBar.Horizontal
这些都可以设置样式为水平进度条,效果会有一些差别。
(1)手动控制进度条
对于水平进度条,我们还可以在逻辑代码中控制进度条的增长和减少,我们先在布局文件中增加两个按钮,activity_main.xml文件代码如下:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/tvMessage" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:text="这是一个文本控件" android:textColor="#00ff00" android:textSize="24sp" /> <Button android:id="@+id/button" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="按钮" /> <EditText android:id="@+id/editText" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="输入文字信息" android:inputType="" android:maxLines="2" /> <ImageView android:id="@+id/imageView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@mipmap/ic_launcher" /> <ProgressBar android:id="@+id/progressBar" style="?android:attr/progressBarStyleHorizontal" android:layout_width="match_parent" android:layout_height="wrap_content" /> <Button android:id="@+id/btnAdd" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="增加" /> <Button android:id="@+id/btnReduce" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="减少" /> </LinearLayout>
然后修改MainActivity中的代码,如下所示:
package com.sdbi.uiwidgettest; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends AppCompatActivity implements View.OnClickListener { // 实现接口 private TextView tvMessage; private Button button; private EditText editText; private ImageView imageView; private Button btnAdd, btnReduce; private ProgressBar progressBar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tvMessage = (TextView) findViewById(R.id.tvMessage); button = (Button) findViewById(R.id.button); editText = (EditText) findViewById(R.id.editText); imageView = (ImageView) findViewById(R.id.imageView); button.setOnClickListener(this); progressBar = (ProgressBar) findViewById(R.id.progressBar); btnAdd = (Button) findViewById(R.id.btnAdd); btnReduce = (Button) findViewById(R.id.btnReduce); btnAdd.setOnClickListener(this); btnReduce.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.button: imageView.setImageResource(R.drawable.orange_pic); break; case R.id.btnAdd: progressBar.incrementProgressBy(10); progressBar.setSecondaryProgress(progressBar.getProgress() + 30); break; case R.id.btnReduce: progressBar.incrementProgressBy(-10); progressBar.setSecondaryProgress(progressBar.getProgress() + 30); break; } tvMessage.setText("第一进度:" + progressBar.getProgress() * 100.0 / progressBar.getMax() + "%;第二进度:" + progressBar.getSecondaryProgress() * 100.0 / progressBar.getMax() + "%"); } }
我们看到上述代码中用到进度条的一些方法,我们在这里说明一下:
- incrementProgressBy():增加第一进度的进度值,参数可以是负数,表示减少;
- setProgress():设置第一进度的进度值;
- getProgress():获取第一进度的进度值;
- incrementSecondaryProgressBy():增加第二进度的进度值,参数可以是负数,表示减少;
- setSecondaryProgress():设置第二进度的进度值;
- getSecondaryProgress():获取第二进度的进度值。
(2)自动控制进度条
首先,建立子线程,在子线程中让进度条每次增加10%,超过100%后重新归0。
子线程中操作主线程UI,使用runOnUiThread在UI主线程空闲的时候设置progressBar进度条和tvMessage文本控件,Thread.sleep延时200ms,别忘了使用线程的start()方法启动线程。
package com.sdbi.uiwidgettest; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends AppCompatActivity implements View.OnClickListener { // 实现接口 private TextView tvMessage; private Button button; private EditText editText; private ImageView imageView; private Button btnAdd, btnReduce; private ProgressBar progressBar; private int iProgress = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tvMessage = (TextView) findViewById(R.id.tvMessage); button = (Button) findViewById(R.id.button); editText = (EditText) findViewById(R.id.editText); imageView = (ImageView) findViewById(R.id.imageView); button.setOnClickListener(this); progressBar = (ProgressBar) findViewById(R.id.progressBar); btnAdd = (Button) findViewById(R.id.btnAdd); btnReduce = (Button) findViewById(R.id.btnReduce); btnAdd.setOnClickListener(this); btnReduce.setOnClickListener(this); new Thread(new Runnable() { @Override public void run() { while (iProgress <= 100) { iProgress += 10; if (iProgress > 100) { iProgress = 0; } runOnUiThread(new Runnable() { @Override public void run() { progressBar.setProgress(iProgress); tvMessage.setText("进度:" + iProgress + "%"); } }); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.button: imageView.setImageResource(R.drawable.orange_pic); break; case R.id.btnAdd: progressBar.incrementProgressBy(10); progressBar.setSecondaryProgress(progressBar.getProgress() + 30); break; case R.id.btnReduce: progressBar.incrementProgressBy(-10); progressBar.setSecondaryProgress(progressBar.getProgress() + 30); break; } tvMessage.setText("第一进度:" + progressBar.getProgress() * 100.0 / progressBar.getMax() + "%;第二进度:" + progressBar.getSecondaryProgress() * 100.0 / progressBar.getMax() + "%"); } }
另外,我们在使用水平进度条,但是又不确定进度时,我们就可以将属性android:indeterminate设置为true,这时的水平进度条就可以不断的循环往复。
6、AlertDialog
AlertDialog可以在当前的界面弹出一个对话框,这个对话框是置顶于所有界面元素之上的,能够屏蔽掉其他控件的交互能力,因此一般AlertDialog都是用于提示一些非常重要的内容或者警告信息。比如为了防止用户误删重要内容,在删除前弹出一个确认对话框。
下面我们先来了解一下AlertDialog的大体创建顺序。与TextView、Button这些控件不同,AlertDialog并不是初始化(findViewById)之后就直接调用各种方法了。我们试想一下AlertDialog的使用场景,它并不像TextView和Button控件似的一般都是固定在界面上,而是在某个时机才会触发出来(比如用户点击了某个按钮或者断网了)。所以AlertDialog并不需要到布局文件中创建,而是在逻辑代码中通过构造器(AlertDialog.Builder)来构造,然后为其设置标题、图标和按钮等内容的。步骤如下:
(1)创建构造器AlertDialog.Builder的对象;
(2)通过构造器的对象调用setTitle、setMessage等方法设置对话框的标题、信息和图标等内容;
(3)根据需要,设置正面按钮、负面按钮和中立按钮;
(4)调用create()方法创建AlertDialog的对象;
(5)AlertDialog的对象调用show()方法,让对话框在界面上显示。
注意:AlertDialog.Builder自己也有一个show()方法,可以显示对话框,所以上面的第(4)、(5)步可以简化为一步。
修改MainActivity中的代码,如下所示:
public class MainActivity extends AppCompatActivity implements View.OnClickListener { …… @Override public void onClick(View v) { switch (v.getId()) { case R.id.button: AlertDialog.Builder dialog = new AlertDialog.Builder(MainActivity.this); dialog.setTitle("提示"); dialog.setMessage("确定退出吗?"); dialog.setCancelable(false); //给对话框添加"确定"按钮 dialog.setPositiveButton("确定", new DialogInterface. OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // 确定按钮逻辑代码 } }); //对话框添加"取消"按钮 dialog.setNegativeButton("取消", new DialogInterface. OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // 取消按钮逻辑代码 } }); dialog.show(); // 显示对话框 break; } } }
首先通过AlertDialog.Builder创建出一个AlertDialog的实例,然后可以为这个对话框设置标题、内容、可否取消等属性,接下来调用setPositiveButton()方法为对话框设置确定按钮的点击事件,调用setNegativeButton()方法设置取消按钮的点击事件,最后调用show()方法将对话框显示出来。重新运行程序,点击按钮后,效果如图所示。
(1)如果要三个按钮呢?
我们来试一下,并且还要通过代码改变了对话框的图标。
@Override public void onClick(View v) { switch (v.getId()) { case R.id.button: AlertDialog.Builder dialog = new AlertDialog.Builder(MainActivity.this); dialog.setIcon(android.R.drawable.btn_star); // 系统自带图标 dialog.setTitle("Android系统欢迎度调查"); dialog.setMessage("你喜欢使用Android系统吗??"); dialog.setCancelable(false); // 对话框添加"喜欢"按钮 dialog.setPositiveButton("喜欢", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }); // 对话框添加"不喜欢"按钮 dialog.setNegativeButton("不喜欢", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }); // 给对话框添加普通按钮 dialog.setNeutralButton("一般", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }); dialog.show(); break; } }
(2)类似ListView的AlertDialog
用setItems(CharSequence[] items, final OnClickListener listener)方法来实现类似ListView的AlertDialog。
第一个参数是要显示的数据的数组,第二个参数是点击某个item的触发事件。
@Override public void onClick(View v) { switch (v.getId()) { case R.id.button: final String[] arrayFruit = new String[]{"苹果","橘子","草莓","香蕉"}; AlertDialog.Builder dialog = new AlertDialog.Builder(MainActivity.this); dialog.setIcon(android.R.drawable.btn_star); dialog.setTitle("你喜欢吃哪种水果?"); dialog.setCancelable(false); dialog.setItems(arrayFruit, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Toast.makeText(MainActivity.this, arrayFruit[which], Toast.LENGTH_SHORT).show(); } }); // 对话框添加"取消"按钮 dialog.setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }); dialog.show(); break; default: break; } }
(3)类似RadioButton的AlertDialog
用setSingleChoiceItems(CharSequence[] items, int checkedItem, final OnClickListener listener)方法来实现类似RadioButton的AlertDialog。
第一个参数是要显示的数据的数组,第二个参数是初始值(初始被选中的item),第三个参数是点击某个item的触发事件,在这个例子里面我们设了一个selectedFruitIndex用来记住选中的item的index。
private int selectedFruitIndex = 0; @Override public void onClick(View v) { switch (v.getId()) { case R.id.button: final String[] arrayFruit = new String[] { "苹果", "橘子", "草莓", "香蕉" }; AlertDialog.Builder dialog = new AlertDialog.Builder(MainActivity.this); dialog.setIcon(android.R.drawable.btn_star); dialog.setTitle("你喜欢吃哪种水果?"); dialog.setCancelable(false); dialog.setSingleChoiceItems(arrayFruit, selectedFruitIndex, new DialogInterface.OnClickListener(){ @Override public void onClick(DialogInterface dialog, int which) { selectedFruitIndex = which; } }); // 对话框添加"确认"按钮 dialog.setPositiveButton("确认", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Toast.makeText(MainActivity.this, arrayFruit[selectedFruitIndex], Toast.LENGTH_SHORT).show(); } }); // 对话框添加"取消"按钮 dialog.setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }); dialog.show(); break; default: break; } }
(4)类似CheckBox的AlertDialog
用setMultiChoiceItems(CharSequence[] items, boolean[] checkedItems, final OnMultiChoiceClickListener listener)方法来实现类似CheckBox的AlertDialog。
第一个参数是要显示的数据的数组,第二个参数是选中状态的数组,第三个参数是点击某个item的触发事件。
@Override public void onClick(View v) { switch (v.getId()) { case R.id.button: final String[] arrayFruit = new String[] { "苹果", "橘子", "草莓", "香蕉" }; final boolean[] arrayFruitSelected = new boolean[] { true, true, false, false }; AlertDialog.Builder dialog = new AlertDialog.Builder(MainActivity.this); dialog.setIcon(android.R.drawable.btn_star); dialog.setTitle("你喜欢吃哪种水果?"); dialog.setCancelable(false); dialog.setMultiChoiceItems(arrayFruit, arrayFruitSelected, new DialogInterface.OnMultiChoiceClickListener() { @Override public void onClick(DialogInterface dialog, int which, boolean isChecked) { arrayFruitSelected[which] = isChecked; } }); // 对话框添加"确认"按钮 dialog.setPositiveButton("确认", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < arrayFruitSelected.length; i++) { if (arrayFruitSelected[i] == true) { stringBuilder.append(arrayFruit[i] + "、"); } } Toast.makeText(MainActivity.this, stringBuilder.toString(), Toast.LENGTH_SHORT).show(); } }); // 对话框添加"取消"按钮 dialog.setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }); dialog.show(); break; } }
(5)自定义View的AlertDialog
有时候我们不能满足系统自带的AlertDialog风格,就比如说我们要实现一个Login画面,有用户名和密码,这时我们就要用到自定义View的AlertDialog。
先创建登录画面的布局文件login.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:orientation="horizontal"> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="right" android:text="用户名:" /> <EditText android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="3" android:hint="请输入用户名" android:singleLine="true" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:orientation="horizontal"> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="right" android:text="密码:" /> <EditText android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="3" android:hint="请输入密码" android:inputType="textPassword" /> </LinearLayout> </LinearLayout>
然后在Activity里面把login.xml的布局文件添加到AlertDialog上
@Override public void onClick(View v) { switch (v.getId()) { case R.id.button: // 取得自定义View LayoutInflater layoutInflater = LayoutInflater.from(this); View myLoginView = layoutInflater.inflate(R.layout.login, null); AlertDialog.Builder dialog = new AlertDialog.Builder(MainActivity.this); dialog.setIcon(android.R.drawable.btn_star); dialog.setTitle("用户登录"); dialog.setCancelable(false); dialog.setView(myLoginView); // 对话框添加"登录"按钮 dialog.setPositiveButton("登录", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }); // 对话框添加"取消"按钮 dialog.setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }); dialog.show(); break; } }
7、ProgressDialog
ProgressDialog和AlertDialog有点类似,都可以在界面上弹出一个对话框,都能够屏蔽掉其他控件的交互能力。
不同的是,ProgressDialog会在对话框中显示一个进度条,一般是用于表示当前操作比较耗时,让用户耐心地等待。
ProgressDialog的创建方式有两种,一种是new ProgressDialog(),一种是调用ProgressDialog的静态方法ProgressDialog.show()。
(1)new ProgressDialog()方式
它的用法和AlertDialog也比较相似,修改MainActivity中的代码,如下所示:
public class MainActivity extends AppCompatActivity implements View.OnClickListener { …… @Override public void onClick(View v) { switch (v.getId()) { case R.id.button: ProgressDialog progressDialog = new ProgressDialog(MainActivity.this); progressDialog.setTitle("进度对话框"); progressDialog.setMessage("正在加载..."); progressDialog.setCancelable(true); progressDialog.show(); break; } } }
可以看到,这里也是先构建出一个ProgressDialog对象,然后同样可以设置标题、内容、可否取消等属性,最后也是通过调用show()方法将ProgressDialog显示出来。重新运行程序,点击按钮后,效果如图所示。
注意:如果在setCancelable()中传入了false,表示ProgressDialog是不能通过Back键取消掉的,这时你就一定要在代码中做好控制,当数据加载完成后必须要调用ProgressDialog的dismiss()方法来关闭对话框,否则ProgressDialog将会一直存在。
ProgressDialog的样式也有两种,一种是圆形不明确状态,一种是水平进度条状态,类似于ProgressBar。
我们来看一下水平进度条的用法,水平进度条也分为两种进度。
public class MainActivity extends AppCompatActivity implements View.OnClickListener { …… @Override public void onClick(View v) { switch (v.getId()) { case R.id.button: final ProgressDialog progressDialog=new ProgressDialog(MainActivity.this); progressDialog.setTitle("进度对话框"); progressDialog.setMessage("正在加载..."); progressDialog.setCancelable(false); // 设置水平进度条 progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); progressDialog.setMax(100); progressDialog.show(); new Thread(new Runnable() { @Override public void run() { int i = 0; while (i < 100) { try { Thread.sleep(200); // 更新进度条的进度,可以在子线程中更新进度条进度 progressDialog.incrementProgressBy(1); progressDialog.incrementSecondaryProgressBy(progressDialog.getProgress() + 5);//二级进度条更新方式 i++; } catch (Exception e) { } } if (i == 100) { // 进度完成 // 在进度条走完时删除Dialog progressDialog.dismiss(); } } }).start(); break; } } }
(2)调用ProgressDialog的静态方法ProgressDialog.show()方式
@Override public void onClick(View v) { switch (v.getId()) { case R.id.button: ProgressDialog progressDialog = ProgressDialog.show(MainActivity.this, "进度对话框", "正在加载..."); break; } }
ProgressDialog.show()方法有多种重载形式,通过查看你会发现,其实show()方法也是把new ProgressDialog()和其他的一些set属性方法做了封装。
8、CheckBox复选框组件
CheckBox复选框,可以同时选中多个值。
CheckBox继承自CompoundButton(Compound,复合),CompoundButton继承自Button。
CompoundButton提供了两种状态:已选中、未选中。
CompoundButton是抽象类,因此在实际开发中不能直接使用,要使用它的几个子类,主要有CheckBox、Switch、RadioButton等。
CompoundButton相比Button多了一个监听事件接口CompoundButton.OnCheckedChangeListener。
当复合按钮的检查状态发生变化时调用。需要实现的方法是:
@Override public void onCheckedChanged(CompoundButton compoundButton, boolean b) { }
第一个参数compoundButton是控件对象,第二个参数b是复合按钮的新状态。
CompoundButton提供了下面的方法对复合按钮进行属性的使用:
- setChecked(boolean checked):设置按钮的状态
- isChecked():获取按钮的状态
我们先在布局文件中添加3个CheckBox。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> ...... <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <CheckBox android:id="@+id/cbApple" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="苹果" /> <CheckBox android:id="@+id/cbOrange" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="橘子" /> <CheckBox android:id="@+id/cbBanana" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="香蕉" /> </LinearLayout> </LinearLayout>
给这3个CheckBox绑定事件。
import androidx.appcompat.app.AppCompatActivity; import android.app.ProgressDialog; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.EditText; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; public class MainActivity extends AppCompatActivity implements View.OnClickListener, CompoundButton.OnCheckedChangeListener { // 实现接口 private TextView tvMessage; private Button button; private EditText editText; private ImageView imageView; private Button btnAdd, btnReduce; private ProgressBar progressBar; private CheckBox cbApple, cbOrange, cbBanana; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tvMessage = (TextView) findViewById(R.id.tvMessage); ...... cbApple = (CheckBox) findViewById(R.id.cbApple); cbOrange = (CheckBox) findViewById(R.id.cbOrange); cbBanana = (CheckBox) findViewById(R.id.cbBanana); cbApple.setOnCheckedChangeListener(this); cbOrange.setOnCheckedChangeListener(this); cbBanana.setOnCheckedChangeListener(this); } @Override public void onCheckedChanged(CompoundButton compoundButton, boolean b) { String strMsg = ""; if (b) { strMsg = "复选框" + compoundButton.getText() + "[" + compoundButton.getId() + "]被选中"; } else { strMsg = "复选框" + compoundButton.getText() + "[" + compoundButton.getId() + "]被取消"; } tvMessage.setText(strMsg); } @Override public void onClick(View v) { ...... } }
9、Switch开关组件
Switch开关控件,也是经常使用的一个比较重要的控件,也是可以有选中和未选中的两种状态。
Switch也是要绑定CompoundButton.OnCheckedChangeListener监听器。
在布局文件中添加Switch开关控件。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> ...... <Switch android:id="@+id/swConnect" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="接通" /> </LinearLayout>
绑定事件。
import androidx.appcompat.app.AppCompatActivity; import android.app.ProgressDialog; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.EditText; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.Switch; import android.widget.TextView; public class MainActivity extends AppCompatActivity implements View.OnClickListener, CompoundButton.OnCheckedChangeListener { // 实现接口 private TextView tvMessage; private Button button; private EditText editText; private ImageView imageView; private Button btnAdd, btnReduce; private ProgressBar progressBar; private CheckBox cbApple, cbOrange, cbBanana; private Switch swConnect; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ...... cbApple = (CheckBox) findViewById(R.id.cbApple); cbOrange = (CheckBox) findViewById(R.id.cbOrange); cbBanana = (CheckBox) findViewById(R.id.cbBanana); cbApple.setOnCheckedChangeListener(this); cbOrange.setOnCheckedChangeListener(this); cbBanana.setOnCheckedChangeListener(this); swConnect = (Switch) findViewById(R.id.swConnect); swConnect.setOnCheckedChangeListener(this); } @Override public void onCheckedChanged(CompoundButton compoundButton, boolean b) { String strMsg = ""; if (b) { strMsg = "复选框" + compoundButton.getText() + "[" + compoundButton.getId() + "]被选中"; } else { strMsg = "复选框" + compoundButton.getText() + "[" + compoundButton.getId() + "]被取消"; } tvMessage.setText(strMsg); } @Override public void onClick(View v) { ...... } }
10、RadioButton圆形单选框组件
RadioButton是单选按钮,允许用户在一个组中选择一个选项。同一组中的单选按钮有互斥效果。
RadioButton的特点:
- RadioButton是圆形单选框;
- RadioGroup是个可以容纳多个RadioButton的容器;
- 在RadioGroup中的RadioButton控件可以有多个,但同时有且仅有一个可以被选中。
使用RadioButton必须和单选框RadioGroup一起使用,在RadioGroup中放置RadioButton,也是通过setOnCheckedChangeListener( )来响应按钮的事件。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> ...... <RadioGroup android:id="@+id/rgSex" android:layout_width="match_parent" 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="男" /> <RadioButton android:id="@+id/rbFeMale" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="女" /> <RadioButton android:id="@+id/rbPrivary" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="保密" /> </RadioGroup> </LinearLayout>
可以通过给每个RadioButton绑定CompoundButton.OnCheckedChangeListener监听器来监听选项动作。
package com.sdbi.uiwidgettest; import androidx.appcompat.app.AppCompatActivity; import android.app.ProgressDialog; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.EditText; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.RadioButton; import android.widget.RadioGroup; import android.widget.Switch; import android.widget.TextView; public class MainActivity extends AppCompatActivity implements View.OnClickListener, CompoundButton.OnCheckedChangeListener { // 实现接口 ...... private RadioGroup rgSex; private RadioButton rbMale, rbFemale, rbPrivary; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ...... rgSex = (RadioGroup) findViewById(R.id.rgSex); rbMale = (RadioButton) findViewById(R.id.rbMale); rbFemale = (RadioButton) findViewById(R.id.rbFeMale); rbPrivary = (RadioButton) findViewById(R.id.rbPrivary); rbMale.setOnCheckedChangeListener(this); rbFemale.setOnCheckedChangeListener(this); rbFemale.setOnCheckedChangeListener(this); } @Override public void onCheckedChanged(CompoundButton compoundButton, boolean b) { String strMsg = ""; if (b) { strMsg = "复选框" + compoundButton.getText() + "[" + compoundButton.getId() + "]被选中"; } else { strMsg = "复选框" + compoundButton.getText() + "[" + compoundButton.getId() + "]被取消"; } tvMessage.setText(strMsg); } @Override public void onClick(View v) { ...... } }
也可以通过给RadioGroup绑定RadioGroup.OnCheckedChangeListener监听器来监听选项动作。
import androidx.appcompat.app.AppCompatActivity; import android.app.ProgressDialog; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.EditText; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.RadioButton; import android.widget.RadioGroup; import android.widget.Switch; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends AppCompatActivity implements View.OnClickListener, CompoundButton.OnCheckedChangeListener { // 实现接口 ...... private RadioGroup rgSex; private RadioButton rbMale, rbFemale, rbPrivary; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ...... rgSex = (RadioGroup) findViewById(R.id.rgSex); rbMale = (RadioButton) findViewById(R.id.rbMale); rbFemale = (RadioButton) findViewById(R.id.rbFeMale); rbPrivary = (RadioButton) findViewById(R.id.rbPrivary); rgSex.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { @Override public void onCheckedChanged(RadioGroup radioGroup, int i) { // 选中状态改变时被触发 switch (i) { case R.id.rbMale: // 当用户选择男性时 Toast.makeText(MainActivity.this, "当前用户选择" + rbMale.getText().toString(), Toast.LENGTH_SHORT).show(); break; case R.id.rbFeMale: // 当用户选择女性时 Toast.makeText(MainActivity.this, "当前用户选择" + rbFemale.getText().toString(), Toast.LENGTH_SHORT).show(); break; case R.id.rbPrivary: // 当用户选择男性时 Toast.makeText(MainActivity.this, "当前用户选择" + rbPrivary.getText().toString(), Toast.LENGTH_SHORT).show(); break; } } }); } @Override public void onCheckedChanged(CompoundButton compoundButton, boolean b) { String strMsg = ""; if (b) { strMsg = "复选框" + compoundButton.getText() + "[" + compoundButton.getId() + "]被选中"; } else { strMsg = "复选框" + compoundButton.getText() + "[" + compoundButton.getId() + "]被取消"; } tvMessage.setText(strMsg); } @Override public void onClick(View v) { ...... } }
【扩展提高】
如果有一组单选按钮,初始化时任何选项未选中,点击选项可以选中一个,也可以将选中的取消,这样该怎么设置?
activity_mail.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".activity.MainActivity"> <RadioGroup android:id="@+id/rgFruit" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <RadioButton android:id="@+id/rbApple" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="苹果" /> <RadioButton android:id="@+id/rbBanana" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="香蕉" /> </RadioGroup> </LinearLayout>
MainActivity.java
import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.RadioButton; import android.widget.RadioGroup; public class MainActivity extends AppCompatActivity implements View.OnClickListener { private static final String TAG = "MainActivity"; private RadioGroup rgFruit; private RadioButton rbApple, rbBanana; private boolean isApple, isBanana; @Override public void onClick(View view) { // View 控件 switch (view.getId()) { case R.id.rbApple: rgFruit.clearCheck(); // 清除RadioGroup的选中状态 // 根据选中标识变量来设置选中状态 if (isApple == false) { rbApple.setChecked(true); isApple = true; rbBanana.setChecked(false); isBanana = false; } else { rbApple.setChecked(false); isApple = false; } break; case R.id.rbBanana: rgFruit.clearCheck(); // 清除RadioGroup的选中状态 // 根据选中标识变量来设置选中状态 if (isBanana == false) { rbBanana.setChecked(true); isBanana = true; rbApple.setChecked(false); isApple = false; } else { rbBanana.setChecked(false); isBanana = false; } break; } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); rgFruit = findViewById(R.id.rgFruit); rbApple = findViewById(R.id.rbApple); rbBanana = findViewById(R.id.rbBanana); rbApple.setOnClickListener(this); rbBanana.setOnClickListener(this); } }