Android App开发-简单控件(4)——按钮触控和图像显示

3.4 按钮触控

本节介绍了按钮控件的常见用法,包括:如何设置大小写属性与点击属性,如何响应按钮的点击事件和长按事件,如何禁用按钮又该如何启用按钮,等等。

3.4.1 按钮控件Button

除了文本视图之外,按钮Button也是一种基础控件。因为Button是由TextView派生而来,所以文本视图拥有的属性和方法,包括文本内容、文本大小、文本颜色等,按钮控件均能使用。

不同的是,Button拥有默认的按钮背景,而TextView默认无背景;Button的内部文本默认居中对齐,而TextView的内部文本默认靠左对齐。此外,按钮还要额外注意textAllCaps与onClick两个属性,分别介绍如下:

1.textAllCaps属性

对于TextView来说,text属性设置了什么文本,文本视图就显示什么文本。但对于Button来说,不管text属性设置的是大写字母还是小写字母,按钮控件都默认转成大写字母显示。比如在XML文件中加入下面的Button标签:

xml 复制代码
  <Button
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="Hello World"/>

编译运行后的App界面,按钮上显示全大写的"HELLO WORLD",而非原来大小写混合的"Hello World"。显然这个效果不符合预期,为此需要给Button标签补充textAllCaps属性,该属性默认为true表示全部转为大写,如果设置为false则表示不转为大写。于是在布局文件添加新的Button标签,该标签补充了android:textAllCaps="false",具体内容如下所示:

xml 复制代码
  <Button
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="Hello World"
    android:textAllCaps="false"/>

再次运行App,此时包含新旧按钮的界面如图所示,可见textAllCaps属性果然能够控制大小写转换。

2.onClick属性

按钮之所以成为按钮,是因为它会响应按下动作,就手机而言,按下动作等同于点击操作,即手指轻触屏幕然后马上松开。每当点击按钮之时,就表示用户确认了某个事项,接下来轮到App接着处理了。

onClick属性便用来接管用户的点击动作,该属性的值是个方法名,也就是当前页面的Java代码存在这么一个方法:当用户点击按钮时,就自动调用该方法。

譬如下面的Button标签指定了onClick属性值为doClick,表示点击该按钮会触发Java代码中的doClick方法:

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=".ButtonStyleActivity">
   
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="直接指定点击方法"
        android:textColor="@color/black"
        android:textSize="17sp"
        android:onClick="doClick"/>

    <TextView
        android:id="@+id/tv_result"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="这里查看点击结果"
        android:textColor="@color/black"
        android:textSize="17sp"/>

</LinearLayout>

与之相对应,页面所在的Java代码需要增加doClick方法,方法代码示例如下:

java 复制代码
package com.example.buttoncontrols;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import com.example.buttoncontrols.util.DateUtil;

public class ButtonStyleActivity extends AppCompatActivity {

    private TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_button_style);
        textView = findViewById(R.id.tv_result);
    }
    public void doClick(View view){
        String desc=String.format("%s 您点击了按钮:%s",DateUtil.getNowTime(),((Button)view).getText());
        textView.setText(desc);

    }
}

然后编译运行,并在App界面上点击新加的按钮,点击前后的界面如下面两张图所示。

点击之后效果图:

比较两张图的文字差异,可见点击按钮之后确实调用了doClick方法。

3.4.2 点击事件和长按事件

1. 点击事件

虽然按钮控件能够在XML文件中通过onClick属性指定点击方法,但是方法的名称可以随便叫,既能叫doClick也能叫doTouch,甚至叫它doA或doB都没问题,这样很不利于规范化代码,倘若以后换了别人接手,就不晓得doA或doB是干什么用的。因此在实际开发中,不推荐使用Button标签的onClick属性,而是在代码中给按钮对象注册点击监听器。

所谓监听器,意思是专门监听控件的动作行为,它平时无所事事,只有控件发生了指定的动作,监听器才会触发开关去执行对应的代码逻辑点击监听器需要实现接口View.OnClickListener,并重写onClick方法补充点击事件的处理代码,再由按钮调用setOnClickListener方法设置监听器对象。比如下面的代码给按钮控件btn_click_single设置了一个点击监听器:

java 复制代码
// 定义一个点击监听器,它实现了接口View.OnClickListener
class MyOnClickListener implements View.OnClickListener {
  @Override
  public void onClick(View v) { 
    // 点击事件的处理方法
    String desc = String.format("%s 您点击了按钮:%s",
    DateUtil.getNowTime(), ((Button)v).getText());
    // 设置文本视图的文本内容
    tv_result.setText(desc); 
  }
}

接着运行App,点击按钮之后的界面如图所示,可见点击动作的确触发了监听器的onClick方法

如果一个页面只有一个按钮,单独定义新的监听器倒也无妨,可是如果存在许多按钮,每个按钮都定义自己的监听器,那就劳民伤财了。对于同时监听多个按钮的情况,更好的办法是注册统一的监听器,也就是让当前页面实现接口View.OnClickListener,如此一来,onClick方法便写在了页面代码之内。因为是统一的监听器,所以onClick内部需要判断是哪个按钮被点击了,也就是利用视图对象的getId方法检查控件编号,完整的onClick代码举例如下:

java 复制代码
 // 公共的点击事件监听
    @Override
    public void onClick(View v) {
        if (v.getId()==R.id.btn_click_public){
            String desc=String.format("%s 您点击了按钮:%s", DateUtil.getNowTime(),((Button) v).getText());
            tvResult.setText(desc);
        }
    }

当然该页面的onCreate内部别忘了调用按钮对象的setOnClickListener方法,把按钮的点击监听器设置成当前页面,设置代码如下所示:

java 复制代码
// 从布局文件中获取名为btn_click_public的按钮控件
Button btn_click_public = findViewById(R.id.btn_click_public);
// 设置点击监听器,一旦用户点击按钮,就触发监听器的onClick方法
btn_click_public.setOnClickListener(this);

重新运行App,点击第二个按钮之后的界面如图所示,可见当前页面的onClick方法也正确执行了。

点击实践完整代码如下:

XML布局文件代码:

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=".ButtonClickActivity">

    <Button
        android:id="@+id/btn_click_single"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="指定单独的点击监听器"
        android:textColor="#000000"
        android:textSize="17sp"/>

    <Button
        android:id="@+id/btn_click_public"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="指定公共的点击监听器"
        android:textColor="#000000"
        android:textSize="17sp"/>

    <TextView
        android:id="@+id/tv_result"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="5dp"
        android:textColor="@color/black"
        android:textSize="17sp"
        android:text="这里查看按钮点击的结果"/>
</LinearLayout>

Java 逻辑代码如下:

java 复制代码
package com.example.buttoncontrols;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import com.example.buttoncontrols.util.DateUtil;

/**
 * @author Natural-Pride
 */
public class ButtonClickActivity extends AppCompatActivity implements View.OnClickListener {

    private TextView tvResult;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_button_click);
        Button btnClickSingle = findViewById(R.id.btn_click_single);
        Button btnClickPublic = findViewById(R.id.btn_click_public);

        tvResult = findViewById(R.id.tv_result);
        btnClickSingle.setOnClickListener(new MyOnClickListener(tvResult));
        btnClickPublic.setOnClickListener(this);
    }

    // 公共的点击事件监听
    @Override
    public void onClick(View v) {
        if (v.getId()==R.id.btn_click_public){
            String desc=String.format("%s 您点击了按钮:%s", DateUtil.getNowTime(),((Button) v).getText());
            tvResult.setText(desc);
        }
    }

    // 单独的点击事件监听
    static class MyOnClickListener implements View.OnClickListener {
        private final TextView tvResult;
        public MyOnClickListener(TextView tvResult) {
            this.tvResult=tvResult;
        }

        @Override
        public void onClick(View view) {
            String desc=String.format("%s 您点击了按钮:%s", DateUtil.getNowTime(),((Button)view).getText());
            tvResult.setText(desc);
        }
    }
}

实现效果如图:

点击前:

点击单独的点击监听器:

点击公共的点击监听器

2. 长按实践

除了点击事件,Android还设计了另外一种长按事件,每当控件被按住超过500毫秒之后,就会触发该控件的长按事件。若要捕捉按钮的长按事件,可调用按钮对象的setOnLongClickListener方法设置长按监听器。具体的设置代码示例如下:

java 复制代码
package com.example.buttoncontrols;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import com.example.buttoncontrols.util.DateUtil;

public class ButtonLongActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_button_long);
        TextView tvResult=findViewById(R.id.tv_result);
        Button btnLongClick=findViewById(R.id.btn_long_click);
        btnLongClick.setOnLongClickListener(v -> {
            String desc=String.format("%s 您点击了按钮:%s", DateUtil.getNowTime(),((Button)v).getText());
            tvResult.setText(desc);
            return true;
        });

    }
}

再次运行App,长按按钮之后的界面如图所示,说明长按事件果然触发了onLongClick方法。

值得注意的是,点击监听器和长按监听器不局限于按钮控件,其实它们都来源于视图基类View,凡是从View派生而来的各类控件,均可注册点击监听器和长按监听器。譬如文本视图TextView,其对象也能调用setOnClickListener方法与setOnLongClickListener方法,此时TextView控件就会响应点击动作和长按动作。因为按钮存在按下和松开两种背景,便于提示用户该控件允许点击,但文本视图默认没有按压背景,不方便判断是否被点击,所以一般不会让文本视图处理点击事件和长按事件。

3.4.3 禁用与恢复按钮

尽管按钮控件生来就是给人点击的,可是某些情况希望暂时禁止点击操作,譬如用户在注册的时候,有的网站要求用户必须同意指定条款,而且至少浏览10秒之后才能点击注册按钮。那么在10秒之前,注册按钮应当置灰且不能点击,等过了10秒之后,注册按钮才恢复正常。在这样的业务场景中,按钮先后拥有两种状态,即不可用状态与可用状态,它们在外观和功能上的区别如下:

(1)不可用按钮:按钮不允许点击,即使点击也没反应,同时按钮文字为灰色。

(2)可用按钮:按钮允许点击,点击按钮会触发点击事件,同时按钮文字为正常的黑色。

从上述的区别说明可知,不可用与可用状态主要有两点差异:其一,是否允许点击;其二,按钮文字的颜色。就文字颜色而言,可在布局文件中使用textColor属性设置颜色,也可在Java代码中调用setTextColor方法设置颜色。至于是否允许点击,则需引入新属性android:enabled,该属性值为true时表示启用按钮,即允许点击按钮;该属性值为false时表示禁用按钮,即不允许点击按钮。在Java代码中,则可通过setEnabled方法设置按钮的可用状态(true表示启用,false表示禁用)。

接下来通过一个例子演示按钮的启用和禁用操作。为了改变测试按钮的可用状态,需要额外添加两个控制按钮,分别是"启用测试按钮"和"禁用测试按钮",加起来一共3个按钮控件,注意"测试按钮"默认是灰色文本。测试界面的布局效果如图所示。

与图对应的布局文件内容如下所示:

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=".ButtonEnableActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button
            android:id="@+id/btn_enable"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="启用测试按钮"
            android:textColor="#000000"
            android:textSize="17sp" />

        <Button
            android:id="@+id/btn_disable"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="禁用测试按钮"
            android:textColor="#000000"
            android:textSize="17sp" />

    </LinearLayout>

    <Button
        android:id="@+id/btn_test"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="测试按钮"
        android:textColor="#888888"
        android:textSize="17sp"
        android:enabled="false"/>

    <TextView
        android:id="@+id/tv_result"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="这里查看测试按钮的点击结果"
        android:textColor="@color/black"
        android:textSize="17sp" />
</LinearLayout>

然后在Java代码中给3个按钮分别注册点击监听器,注册代码如下所示:

java 复制代码
package com.example.buttoncontrols;

import androidx.appcompat.app.AppCompatActivity;

import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import com.example.buttoncontrols.util.DateUtil;

public class ButtonEnableActivity extends AppCompatActivity implements View.OnClickListener {

    private Button btnTest;
    private TextView tvResult;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_button_enable);
        Button btnEnable = findViewById(R.id.btn_enable);
        Button btnDisable = findViewById(R.id.btn_disable);
        btnTest = findViewById(R.id.btn_test);
        tvResult = findViewById(R.id.tv_result);

        btnEnable.setOnClickListener(this);
        btnDisable.setOnClickListener(this);
        btnTest.setOnClickListener(this);

    }

    @Override
    public void onClick(View v) {
        int id = v.getId();
        if (id == R.id.btn_enable) {
            // 启用当前控件
            btnTest.setEnabled(true);
            // 设置按钮的文字颜色
            btnTest.setTextColor(Color.BLACK);
        } else if (id == R.id.btn_disable) {
            // 禁用当前控件
            btnTest.setEnabled(false);
            btnTest.setTextColor(Color.GRAY);
        } else {
            String desc = String.format("%s 您点击了按钮:%s", DateUtil.getNowTime(), ((Button) v).getText());
            tvResult.setText(desc);
        }
    }
}

最后编译运行App,点击了"启用测试按钮"之后,原本置灰的测试按钮btn_test恢复正常的黑色文本,点击该按钮发现界面有了反应,具体效果如图所示

对比两图,观察按钮启用前后的外观及其是否响应点击动作,即可知晓禁用按钮和启用按钮两种模式的差别。

3.5 图像显示

本节介绍了与图像显示有关的几种控件用法,包括:专门用于显示图片的图像视图以及若干缩放类型效果,支持显示图片的按钮控件------图像按钮,如何在按钮控件上同时显示文本和图标等。

3.5.1 图像视图ImageView

显示文本用到了文本视图TextView,显示图像则用到图像视图ImageView。由于图像通常保存为单独的图片文件,因此需要先把图片放到res/drawable目录,然后再去引用该图片的资源名称。比如现在有张图片名为laugh.png,那么XML文件通过属性android:src设置图片资源,属性值格式形如"@drawable/不含扩展名的图片名称"。添加了src属性的ImageView标签示例如下:

xml 复制代码
  <ImageView
    android:id="@+id/iv_scale"
    android:layout_width="match_parent"
    android:layout_height="220dp"
    android:src="@drawable/laugh" />

若想在Java代码中设置图像视图的图片资源,可调用ImageView控件的setImageResource方法,方法参数格式形如"R.drawable.不含扩展名的图片名称"。仍以上述的苹果图片为例,给图像视图设置图片资源的代码例子如下所示:

java 复制代码
package com.example.imagedisplay;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.widget.ImageView;

public class ImageScaleActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_image_scale);
        ImageView ivScale= findViewById(R.id.iv_scale);
        ivScale.setImageResource(R.drawable.laugh);
    }
}

运行测试App,展示图片的界面效果如图所示

观察效果图发现图片居中显示,而非文本视图里的文字那样默认靠左显示,这是怎么回事?

原来ImageView本身默认图片居中显示,不管图片有多大抑或有多小,图像视图都会自动缩放图片,使之刚好够着ImageView的边界,并且缩放后的图片保持原始的宽高比例,看起来图片很完美地占据视图中央。

这种缩放类型在XML文件中通过属性android:scaleType定义,即使图像视图未明确指定该属性,系统也会默认其值为fitCenter,表示让图像缩放后居中显示。添加了缩放属性的ImageView标签如下所示:

xml 复制代码
  <ImageView
    android:id="@+id/iv_scale"
    android:layout_width="match_parent"
    android:layout_height="220dp"
    android:src="@drawable/laugh"
    android:scaleType="fitCenter"/>

在Java代码中可调用setScaleType方法设置图像视图的缩放类型,其中fitCenter对应的类型为ScaleType.FIT_CENTER,设置代码示例如下:

java 复制代码
// 将缩放类型设置为"保持宽高比例,缩放图片使其位于视图中间"
iv_scale.setScaleType(ImageView.ScaleType.FIT_CENTER);

除了居中显示,图像视图还提供了其他缩放类型,详细的缩放类型取值说明见表

3.5.2 图像按钮ImageButton

常见的按钮控件Button其实是文本按钮,因为按钮上面只能显示文字,不能显示图片,ImageButton才是显示图片的图像按钮。虽然ImageButton号称图像按钮,但它并非继承Button,而是继承了ImageView,所以凡是ImageView拥有的属性和方法,ImageButton统统拿了过来,区别在于ImageButton有个按钮背景。

尽管ImageButton源自ImageView,但它毕竟是个按钮呀,按钮家族常用的点击事件和长按事件,ImageButton全都没落下。不过ImageButton和Button之间除了名称不同,还有下列差异:

  • Button既可显示文本也可显示图片(通过setBackgroundResource方法设置背景图片),而ImageButton只能显示图片不能显示文本。

  • ImageButton上的图像可按比例缩放,而Button通过背景设置的图像会拉伸变形,因为背景图采取fitXY方式,无法按比例缩放。

  • Button只能靠背景显示一张图片,而ImageButton可分别在前景和背景显示图片,从而实现两张图片叠加的效果。

从上面可以看出,Button与ImageButton各有千秋,通常情况使用Button就够用了。但在某些场合,比如输入法打不出来的字符,以及特殊字体显示的字符串,就适合先切图再放到ImageButton。

举个例子,数学常见的开平方运算,由输入法打出来的运算符号为"√",但该符号缺少右上角的一横,正确的开平方符号是带横线的,此时便需要通过ImageButton显示这个开方图片。不过使用ImageButton得注意,图像按钮默认的缩放类型为center(保持原始尺寸不缩放图片),而非图像视图默认的fitCenter,倘若图片尺寸较大,那么图像按钮将无法显示整个图片。为避免显示不完整的情况,XML文件中的ImageButton标签必须指定fitCenter的缩放类型,详细的标签内容示例如下:

xml 复制代码
  <ImageButton
    android:layout_width="match_parent"
    android:layout_height="80dp"
    android:src="@drawable/sqrt"
    android:scaleType="fitCenter" />

打开演示界面如图所示,可见图像按钮正确展示了开平方符号

3.5.3 同时展示文本与图像

现在有了Button可在按钮上显示文字,又有ImageButton可在按钮上显示图像,照理说绝大多数场合都够用了。然而现实项目中的需求往往捉摸不定,例如客户要求在按钮文字的左边加一个图标,这样按钮内部既有文字又有图片,乍看之下Button和ImageButton都没法直接使用。若用LinearLayout对ImageView和TextView组合布局,虽然可行,XML文件却变得冗长许多。

其实有个既简单又灵活的办法,要想在文字周围放置图片,使用按钮控件Button就能实现。原来Button悄悄提供了几个与图标有关的属性,通过这些属性即可指定文字旁边的图标,以下是有关的图标属性说明。

  • drawableTop:指定文字上方的图片。

  • drawableBottom:指定文字下方的图片。

  • drawableLeft:指定文字左边的图片。

  • drawableRight:指定文字右边的图片。

  • drawablePadding:指定图片与文字的间距。

譬如下面是个既有文字又有图标的Button标签例子:

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=".ImageTextActivity">

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="图标在左"
        android:drawableStart="@drawable/error"
        android:background="#FFFFFF"
        android:drawablePadding="5dp"/>

</LinearLayout>

效果如下图:


本章节其他文章
Android App开发-简单控件(1)------ 文本显示
Android App开发-简单控件(2)------ 视图基础
Android App开发-简单控件(3)------ 常用布局
Android App开发-简单控件(4)------ 按钮触控和图像显示

本笔记参考于[B站动脑学院],仅作学习用途,方便随时查看。

参考资料:2022 最新Android基础教程,从开发入门到项目实战,看它就够了

相关推荐
幻雨様5 小时前
UE5多人MOBA+GAS 45、制作冲刺技能
android·ue5
Jerry说前后端6 小时前
Android 数据可视化开发:从技术选型到性能优化
android·信息可视化·性能优化
Meteors.7 小时前
Android约束布局(ConstraintLayout)常用属性
android
alexhilton8 小时前
玩转Shader之学会如何变形画布
android·kotlin·android jetpack
whysqwhw12 小时前
安卓图片性能优化技巧
android
风往哪边走12 小时前
自定义底部筛选弹框
android
Yyyy48213 小时前
MyCAT基础概念
android
Android轮子哥13 小时前
尝试解决 Android 适配最后一公里
android
雨白14 小时前
OkHttp 源码解析:enqueue 非同步流程与 Dispatcher 调度
android
风往哪边走15 小时前
自定义仿日历组件弹框
android