Android的布局与基本UI

1 任务1-按钮Button与文本TextView的互动

本任务的演示效果如图 2-1 所示,在该应用中,视图根节点(容器为垂直的线性布局依次放置3 个 Ul:文本框 (TextView,显示你的个人信息)、按钮 (Button,id 为 button实现互动)和文本框 (TextView,id 为 tv resut,显示随机的3 位数)。当按 Button 被点击,tv result 内容更新,显示一个随机的 3 位整数,并且弹出提示信息 (Toast) 显示当前按钮的点击总次数。该任务是个入门引导任务,通过任务掌握 Android 项目的创建、线性布局LinearLayout 的初步使用、按钮 Button 的点击触发事件TextView 文本内容的更新以及 Toast提示信息的使用。

1.1 线性布局 LinearLayout

线性布局 LinearLayout 有两种方向:水平放置 (horizontal)和垂直放置 (vertical)。

水平放置将 UI从左到右的顺序放置,垂直放置则按照从上到下的顺序放置。控制线性布局方向的属性是 android;orientation,属性值 vertical 为垂直放置,反之值为 horizontal 则为水平放置,容器中常用的的属性还有宽度 android:layout_width 和高度 android:layout_height,其中值可以是具体的数值加单位,常用单位有dp、sp、pt、px等,

1.2  按钮Button

 按钮(Button)是 UI编程中最常用的组件之一,它常用的功能是捕提用户的点击事件并在点击事件中处理相应的逻辑。按点击事件在程序中可用 Button 对象的sctOnClickListener(Vicw.OnClickListener l)方法设置点击侦听器,由于侦听器的传参为接口对象,因此设置侦听器又常称为设置接口。侦听器常见的处理方式有两种:
(1)直接匿名实现。例如对 Buton 点击侦听,可通过 new OnClickListener0)生成接口对象来实现。在开发环境里输入 new 以及空格,再用 ctr+alt+space 自动代码弹出下拉列表选择 View.OnClickListener 即可由 Android Studio 自动补全该接口以及对应的需要重写的方法

bt.setOnclickListener(new View.OnclickListener() {    //bt 为 Button对象
    @Override
    public void onClick(View v){
        //在onClick 方法里处理点击事件
    }
});

(2)在 Activity 类里实现接口,并将侦听器的传参设置为 this,指向 Activity 实例。例如,对 Button 点击侦听,可在 MainActivity 中实现 View.OnClickListener 接口,并在setOnClickListener0方法的参数里用 this 指向 MainActivity 实例,具体实现参考代码 2-2。注意在方法 onClick0之前有@Override 注解,表示该方法是重写接口所定义的方法,尤其是在以下代码,若没有@Override 注解,则 onClick 方法仅仅是 MainActivity 类中的一个普通方法,不是 OnClickListener 接口需要改写的方法,将导致点击按钮时,由于找不到对应的方法而产生程序崩溃的错误。

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    @Override 
    protected void onCreate(Bundle savedInstanceState) {
        ...
        bt.setOnClickListener(this);    //this 指向MainActivity实例
        //若该Activity 实现了View.OnClickListener 接口,则回触发该接口的回调方法
    }
    @Override
    public void onClick(View v) {
    //MainActivity 中实现接口View.onClickListener 的回调方法
        //按钮点击事件的处理
    }
}

按钮事件处理还有一种用法是在按钮所在的布局 XML 中,对 Button 标签增加一个android:onClick 属性,并在 MainActivity 类中定义一个 public 方法,该方法必须有传参 View对象,并把XML中android:onClick 的属性值设为 MainActivity 类中的对应方法。这种处理方式避免了在 MainActivity 中需要找 Button 对象并设置对应侦听事件,相比前述两种方法要简洁。在编程技巧上,可利用 Android Studio 快捷实现,先在XML 的 Button 标签中增加如下属性:

    <Button
...
        android:onClick="buttonOnClick"
... />

将鼠标定位到 buttonOnClick(),利用快捷键 alt+enter,弹出提示框如图 所示,选择 CreateonClick event handler,选择布局文件对应的 Activity(例如 MainActivity),则 buttonOnClick0)方法会自动创建到对应类中,具体如代码 所示。

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle saveInstanceState) {
...
    }
    public void buttonOnClick(View view) {
        //按钮的点击处理事件
    }
}

 在XML 中,Button 的 android:text 属性设置的文本即为 Button 上显示的文本,若是英文,在 XML 中不管大小写,在界面中均为大写显示。在JAVA 代码中,可通过 Button 对象的 setText0)方法设置按钮上的文本,以及 getText0方法获取按钮上的文本。

1.3 文本框

文本框分为不可编辑文本框 TextView 和可编辑文本框 EditText,其区别是 TextView 用于显示字符串,不支持用户编辑,而 EditText 则支持用户编辑。在XML 中,其常用的属性有android:textColor 设置字体颜色,android:textSize 设置字体大小。属性 android;autoLink 设置对文字的智能链接,当值为 phone 时,若字符串是电话号码,会形成链接,点击该电话号码会启动拨号程序:当值为 web 时,则若字符串是网址,点击该字符串会启动浏览器访问该网址;当值为 all 时,则字符串若匹配到电话号码、网址、邮箱、地图等数据格式时,会产生链接,用户点击链接会启动对应应用。


EditText 的 XML 属性还有 android;ems,在宽度是 wrap content 时生效,该属性定义EditText 空文本时的宽度为多少字符宽度,但是当 EditText 的宽度是 match parent 时失效此时宽度由父容器的宽度决定。该设计逻辑是合理的,当宽度是包围内容时,若用户没有输入信息,EditText 宽度为 0,将不可见,需要 ems 来定义其宽度;当其宽度与父容器同宽则 ems 的设置没有意义。

可编辑文本框的 android:inputType 设置了该组件的输入类型,当属性值为 textPassword时表示文本框为密码型,输入的文字用密码符显示,不显示明文,当属性值为 phone 时,其输入的键盘会变成对应的号码型键盘以匹配输入类型,属性值还支持或 (“”)操作,使之同时具备多种类型,例如android:inputType=“phone numberDecimal"表示同时支持电话号码和数字键盘。EditText 具有 android:hint 属性,当输入文字清空时,文本框会显示 hint 的属性值所对应的字符串,提示用户该文本框需要输入什么内容,当用户输入1 个以上文字后,文本框的 hint 提示值会自动消失。
在JAVA 代码中,对文本框的操作主要有 setTextSize0方法(改变文本大小)setTextColor()(改变文本颜色)、setText0 (改变文本)等操作。若要获得文本值,TextView 和 EditText略有不同,具体如下:

String et_value = et.getText().toString();    //et为EditText对象
CharSequence tv_value = tv.getText(); //tv为TextView对象

在 Android 中,常用 Toast 来显示提示信息,该信息框弹出显示文字一段时间后会自动消失,图 2-1 中“第 5 次按”是 Toast 的弹出效果(不同版本虚拟机弹出效果不同)。Toast使用静态方法 makeText(设置文本,其函数声明如下:

public static Toast makeText(android,content,Context context, CharSequence text, int duration)

其中,context 是上下文,传调用 Toast 的 Activity 对象,一般情况下,在活动类 Activity 中,可直接用 this,但若在匿名函数中,this 指向的是匿名函数所定义的接口对象,而非 Activity对象,则需要用活动类名称this 指向,例如在 MainActivity 类的匿名函数中,使用的上下文是MainActivitythis。第二个参数 text 是需要显示的文本,第三个参数 duration 是显示的时长,有 2 个选值:ToastLENGTH LONG(显示时间长)和 Tast.LENGTH SHORT (显示时间短)。仅仅调用 Toast 的 makeText0)方法并不能显示提示信息,还需要调用 show0方法才能显示,一般上采用链式表达,直接在 makeText()方法之后调用 show()方法显示信息。

1.4 任务1的具体实现

1.创建布局文件my_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
<!--根节点:垂直的线性布局,占据整个屏幕高度和宽度-->
    <TextView
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="你的信息" />
<!--文本框,宽度与线性容器同宽,等同于与屏幕同宽,由内容决定高度-->
<!-- 注释只能在UI标签之外,可用“ctr+/”快捷键 -->
    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="生成随机数" />
<!-- 按钮 Button,并使用 android;id 属性创建了 id,在代码中可用R.id,button 引用该UI-->
    <TextView
        android:id="@+id/textView2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="" />
<!-- 第二个 TextView 在代码中可用R.id.tv_result 引用 -->
</LinearLayout>

2.代码实现MainActivity

import androidx.appcompat.app.AppCompatActivity;

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

import java.util.Random;

public class MainActivity extends AppCompatActivity {
    int count=0;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.my_main);
        final TextView textView=findViewById(R.id.textView2);

        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int x=new Random().nextInt(1000);
                textView.setText(String.format("%d",x));
                String s="第"+(++count)+"次按钮";
                Toast.makeText(MainActivity.this,s,Toast.LENGTH_LONG).show();
            }
        });
    }
}

2.任务2-布局对齐gravity 与 layout_gravity

本任务的演示效果如图 2-6 所示,根节点为垂直的线性布局 (LinearLayout),有 1 个TextView,显示个人信息,有 2 个按 Button,宽度均为 200dp,高度包围内容。第 1个 Button的显示文字是“Layout gravity”(文字在按钮中是居中对齐),按钮则在线性布局中向右对齐;第2个 Button 的显示文字是“gravity”(文字在按中是右对齐),按钮默认在线性布局中左对齐。

 2.1 任务2相关知识-gravity 与 layout_gravity 的区别

对齐常用的属性有 android;gravity 和 android:layout gravity,其常用属性值有:

  1. left: 左对齐;
  2. right: 右对齐;
  3. start: 取决于语言习惯,若是从左到右的文字顺序则等效于左对齐,反之则右对齐;
  4. end:与 start 相对应,为 start 的相对方向:
  5. top:顶部对齐;
  6. bottom:底部对齐;
  7. center:上下左右居中对齐;
  8. center_horizontal:水平居中对齐;
  9. center_vertical:垂直居中对齐;

属性 gravity 设置的是该 UI内部内容的对齐方式,例如某 Button 的 gravity 属性设置的是该按钮文本对按钮的对齐方式,若是某个容器,例如 LinearLayout,则是该容器内 UI对容器的对齐方式。


属性 layout_gravity 设置的是该 UI相对父视图(父容器)的对齐方式,UI内部的内容对齐方式与 layout_gravity 无关。因此在图 2-6 中,第1个 Buttn 相对线性布局是右对齐若属性是设置在 Button 上,则需使用 layout_gravity,控制该 Button 相对其父容器(LinearLayout)的对齐关系,并且该 Button 中的文本依然保持了默认的居中对齐属性。第2个 Button 的文本是右对齐的,因此需对该 Button 设置 gravity 属性,而该 UI相对其父容器,依然保持了默认的左对齐关系。若是对两个 Button 的父容器 LinearLayout 设置layout_gravity 属性,则由于线性容器已占据整个屏幕,它相对于屏幕的对齐关系无论设置哪种值都看不出区别;若对 LinearLayout 设置 gravity 属性值为右对齐,则两个 Button 均会相对于线性容器右对齐。 

值得注意的是 layout gravity 属性值只有当设置方向与父容器的方向垂直时才能生效即若某 UI的父容器是垂直的线性布局,则该 UI 的 layout_gravity 设置左、右以及水平居中等对齐方式会生效,但是上、下以及垂直居中等对齐方式无效。同理,在一个水平方向的线性布局中,对 UI设置 layout gravity 左、右对齐将无效,此时可通过父容器的 gravity 属性设置水平对齐方式。因此在复杂的布局中,若仅仅使用线性布局,可能需要多个线性布局嵌套,致使 Android 绘图效率变低,此时需要相对布局、约束布局等各种布局来减少布局嵌套。

2.2 任务2的实现

1.创建my_main.xml 布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" 
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="TextView" />

    <Button
        android:id="@+id/button"
        android:gravity="left"
        android:layout_gravity="right"
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        android:text="LAYOUT_GRAVITY" />

    <Button
        android:id="@+id/button2"
        android:gravity="right"
        android:layout_gravity="left"
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        android:text="GRAVITY" />
</LinearLayout>

2.2 代码实现MainActivity

import androidx.appcompat.app.AppCompatActivity;

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

import java.util.Random;

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.my_main);

    }
}

3.任务3-UI的权重控制

本任务的演示效果如图 2-7 所示,根节点是垂直的线性布局 LinearLayout,从上到下依次有3 个可编辑文本框 EditText,1 个 Button 和1个 TxtView,3 个可编辑文本框的暗示信息(清空文本框内容时会显示,有内容时会消失,默认灰色文本)分别为“To”、“Subject和“Message”,并且“T”的文本框键盘默认是号码类型键盘,剩余 2个文本框则为文本输入键盘。“Message”的 EditText 与最底部的 TextView 在高度上将屏幕剩余高度按 3:1分配且“Message”文本框文本顶部对齐。

 

 3.1 任务3相关知识点-layout_weight

权重属性为 android:layout_weight,常用于线性布局 LinearLayout 或者单选框组合RadioGroup 中,其值为数值,例如 3 表示占据剩余空间的 3 份。权重 layout weight 到底是占用宽度还是高度由其所在组件的父容器方向决定,若父容器的方向 (orientation 属性)是水平的 (horizontal),则占据的是宽度空间,若是垂直的 (vertical),则占据的是高度空间。此外,值得注意的是 layout weight 占据的是剩余空间,若某 UI的宽度属性是 match parent匹配父容器的全部宽度,则剩余宽度为 0,此时权重控制不起作用,若几个 I 要严格按权重分配宽度,应将其宽度属性通过 android:layout_width-"0dp"设为0,这样剩余空间就是整个父容器的宽度,可通过权重属性严格按比例分配。权重的分配比例是按某容器下所有 UI的 layout_weight 总和作为分母 (记为 s),某 U的 layout_weight 值作为分子(记为 a),该UI增加的空间就是容器剩余空间的 a/s。

测试两个水平线性布局容器里分别放了两个可编辑文本框 (EditText),但采用不同的宽度属性时,其权重控制的效果。在该布局中,由于要放置两个水平的LinearLayout,若直接放置,没有根容器是放置不了的,所以在根节点上需要一个垂直的线性布局,再放置两个水平的 LinearLayout,并且注意这两个水平 LinearLayout 的高度不能是match_parent 属性,若第 1 个水平 LinearLayout 的高度值为 match parent,将占据整个根容器,使得第 2 个 LinearLayout 不可见。代码对应的布局界面如图所示。

<?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:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <EditText
            android:id="@+id/editTextTextPersonName"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="1234567890" />

        <EditText
            android:id="@+id/editTextTextPersonName2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="1" />
    </LinearLayout>

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

        <EditText
            android:id="@+id/editTextTextPersonName3"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="1234567890" />

        <EditText
            android:id="@+id/editTextTextPersonName4"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="1" />
    </LinearLayout>
</LinearLayout>

 在测试布局中,在第 1个线性布局的 2个文本框的宽度属性是 wrap content,其layout weight 属性值是 1,使得 2 个文本框将线性布局的剩余宽度按 1:1 平分,而线性布局是 match parent 属性值,与屏幕同宽,因此这 2个文本框将屏幕宽度减去文本框包围内容所占宽度后的剩余宽度进行平分。这样就会产生一个现象:对任何一个文本框输入内容,随着内容长度的改变,2个文本框的宽度发生了变化,因为在输入内容的过程中,文本框包围内容属性使其宽度发生变化,进而使得剩余宽度也发生变化,导致不停地进行 UI 宽度重新分配。第 2个线性布局中,两个文本框的宽度均设成了 dp,即0 宽度,使得剩余宽度为整个屏幕宽度,因此 2 个文本框的宽度能严格按照 1:1 分配,不管输入多少内容,其文本框的宽度都不会发生变化。在实际使用中,UI 的尺寸往往按照预期比例设置,此时需要将对应的高度或宽度属性值设置成 0dp,以保证权重控制能按预期的比例进行分配。

1.创建my_main.xml

任务3 没有实质性的逻辑代码编程,主要是应用 Android Studio UI 面板和XML 的Code界面进行 UI 放置以及相关的属性设置。其主界面的 XML代码如代码 2-11 所示,可编辑文本框 EditText 使用 hint 属性显示提示信息,并且第1个 EditText 的键盘输入使用android:inputType="phone"设置为电话号码类型键盘,剩余的 EditText 的输入类型则采用text设置为普通的文本输入键盘。由于文本框的宽度设置成与父容器同宽,因此 ems 属性(控制文本框为空时的宽度失效。第3 个 EditText 与 TextView 通过权重属性 layout_weight 控制剩余高度的分配比例为 3:1,此外文本框的文本默认是垂直居中对齐,因此“Message”文本框通过 gravity 属性值 top 控制文本是顶部对齐。EditText 的 hint 属性值只有在文本为空时才能显示,为了显示所有文本框的提示信息,各文本框的 text 属性值为空文本。本任务的逻辑代码只需要在 MainActivityjava 中通过 setContentView(Rlayoutmy main)重新设置布局界面即可运行。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <EditText
        android:id="@+id/et1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="To"
        android:ems="10"
        android:inputType="phone"
        android:text="" />
<!-- android : inputType = "phone" 控制文本框键盘为电话号码型键盘-->

    <EditText
        android:id="@+id/et2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ems="10"
        android:hint="Subject"
        android:inputType="text"
        android:text="" />
    <!-- android : inputType="text" 控制文本框键盘为文本键盘-->

    <EditText
        android:id="@+id/et3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Message"
        android:gravity="top"
        android:ems="10"
        android:inputType="text"
        android:layout_weight="3"
        android:text="" />
    <!-- et3 与 TextView 通过控制权重,按3:1占据线性布局剩余高度-->
    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="send" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="Your name and id" />
</LinearLayout>

4.任务4-单选框RadioButton

本任务的运行效果如图所示,根节点为垂直的线性布局,依次有 1个 TextView;显示个人信息;有3 个单选框 RadioButton,分别显示“爬山”“跑步”和“游泳”,3 个单选框按权重 1::1 等宽分配:1个 TextView 显示单选框选中的结果

 4.1 单选框RaidoButton

在Android 系统里,单选框的组件是 RadioButton,复选框的组件是 CheckBox。单选框顾名思义,几个单选框在同一时刻只能有一个被选中,并且当用户选中某个单选框时,其他单选框不管之前状态如何,均要处于未被选中状态,即被认为是一组的单选框具有相互约束作用,以确保任何时刻只能有一个单选框被选中。复选框(多选框)则无该约束,某个复选框的状态与其他复选框无关。单选框的单选约束通过单选框组 RadioGroup 实现,即在同一个 RadioGroup 内的单选框,具有单选约束,而不在同组的单选框则相互不影响。

 单选框组 RadioGroup 具有 android:orientation 属性,属性值 horizontal 控制组内单选框按水平方向依次放置,值 vertical 则控制组内单选框按垂直方向依次放置。对于水平方向的RadioGroup,往往还需要将组内的各单选框增加 layout weight 属性控制宽度权重
(layout_width 值推荐设为 0dp),使得单选框具有权重宽度。

 在事件处理上,虽然 RadioButton 具有 setOnCheckedChangeListener0)方法侦听选中状态的改变,但在实际编程实践中却很少使用,原因是需要对每个单选框均要实现侦听方法,若单选框的数量繁多,程序将变得臃肿。更常用的方法是对单选框组 RadioGroup 设置setOnCheckedChangeListener0)方法,用于侦听整个组内的选中变化情况,其匿名实现方法如下:

RadioGroup对象.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangelListener() {
    @Override
    public void onCheckedChanged(RadioGroup group,int checkedId) {
        // group:单选框组对象
        // checkedId:被选中的单选框的 id
    }
});

其中 RadioGroup 对象需要在JAVA 代码中声明对象,并通过 findViewByid 方法与XML布局的 RadioGroup 对象挂钩。在 XML 中拖入 RadioGroup 对象,默认是不会创建 id 的,还需要用户手动创建对应 id。在接口回调方法 onCheckedChanged0)中,参数 checkedId 是被选中的单选框的 id,若要获取该 id 对应的单选框对象,同样可以声明 RadioButton 对象,利用findViewByld0方法将 checkedId 作为参数,即可通过该 id 找到对应 RadioButton 对象。

4.2 任务4 的实现

1.创建my_mian.xml文件

在垂直线性布局中,第1个UI为 TextVicw,用于显示个人信息,第2个 UI是一组水平放置的单选框因此需要 RadioGroup组件作为容器将 3 个 RadioButton 纳入组内,在 U界面拖入的 RadioGroup 默认是没有 id 属性和方向属性的,可利用向导按图 2-11 所示进行设置。在组件树界面(图 2-11 左图)选中RadioGroup 对象,在属性界面(图 2-11 右图)id 栏输入需要建的 d 值。3 个单选框为水平放置,因此需要对 RadioGroup 对象设置 android:orientation 属性,并利用权重控制,使得3个单选框的宽度为 1:1:1 均分宽度。值得注意的是 RadioGroup 默认高度属性值是match_parent,这样会使得 RadioGroup 占据剩余所有高度,使得最后一个 TextView 不可见,需要将 RadioGroup 高度设置为 wrap content。为了代码的紧凑性,布局中的 text 属性没有使用 XML 的专用文件 string.xml 管理和引用,而是直接赋值,后续任务均如此,不赘述.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Your name and id" />

    <RadioGroup
        android:orientation="horizontal"
        android:id="@+id/radio_group"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >
<!-- 需要给RadioGroup创建id属性,设置方向属性为水平方向,注意高度是wrap_content-->

        <RadioButton
            android:id="@+id/rb1"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="爬山" />

        <RadioButton
            android:id="@+id/rb2"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:text="跑步" />

        <RadioButton
            android:id="@+id/rb3"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:text="游泳" />
        <!-- 利用layout_width="0dp" 和 android:layout_weight="1" 控制单选框宽度比例-->
    </RadioGroup>

    <TextView
        android:id="@+id/tv_result"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="" />
</LinearLayout>

2.MainActivity.java

逻辑代码在 MainActivityjava 中实现,具体如代码 所示。在程序逻辑中,通过 findViewByld0方法关联布局文件中的 RadioGroup 对象,并通过setOnCheckedChangeListener()方法侦听整个组的单选状态,一旦组内单选框点击触发单选状态变化,会回调 onCheckedChanged(方法,在回调方法中,利用 checkedId 和 findViewByld0)方法找到被选中的单选框,进一步通过 RadioButton 对象的 getText0方法获得该单选框文本赋给文本对象,从而实现单击某个单选框,TextView 显示对应单选框的文本。

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.Toast;

import java.util.Random;

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.my_main);
        RadioGroup rg=findViewById(R.id.radio_group);
        //利用单选框组RadioGroup对选中事件进行侦听
        final TextView tv=findViewById(R.id.tv_result);
        //新版本 Android Studio Canary6中,tv无需声明final,老版本需要final
        rg.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(RadioGroup group, int checkedId) {
                RadioButton rb=findViewById(checkedId);
                //checkedId 是被选中的RadioButton对象的Id
                //利用findViewById的方法和参数checkedId,找到对应RadioButton
                tv.setText(rb.getText());
                //通过RadioButton 对象的getText()方法获取单选框文本并赋值给对象tv中
            }
        });
    }

5.任务5-多选框CheckBox

本任务如图所示,根节点为垂直的线性布局 LiearLayout,依次有 1个 TextView,显示个人信息;3 个水平放置且等宽的多选框 CheckBox,内容分别为“爬山”“跑步”和“游泳”:最后一个是 TextView,显示多选框选中的结果。

 5.1 多选框CheckBox

多选框CheckBox 不同于单选框 RadioButton,CheckBox 之间无约束,某个多选框选中状态不会影响其他多选框。多选框和单选框均继承至 CompoundButton,都具有选中状态改变的侦听 setOnCheckedChangeListener)和回调方法onCheckedChanged)。多选框没有像单选框那样,可由 RadioGroup 统一处理,因为多选的状态是多样的,这样就需要对每个多选框写对应的选中状态侦听和回调处理,一种做法是匿名实现接口:另一种做法是将侦听接口转交给 MainActivity。匿名接口实现具体如下:

setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
    @Overrude
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked){
        //isChecked 是选中的状态,true为选中,false 为未选中
    }
});

在回调方法 onCheckedChanged0中,buttonView 是触发事件的 UI实例,即 CheckBox 实例,isChecked 则是选中状态,true 为选中,false 为未选中。然而在实际编程中,对每个 CheckBox都要写一遍状态侦听和回调也是一件繁琐的事,若每个 CheckBox 的选中处理逻辑相似,不妨交给 CheckBox 所在的Activity 统一处理,此时需要对应的 Activity 使用关键字 implement实现 CheckBox的 OnCheckedChangeListener 接口和对应回调方法,并让每个 CheckBox 对象的 setOnCheckedChangeListener0方法指向 Activity 实例 (this)。

5.2 实现

1.my_mian.xml创建

根节点为垂直的 LinearLayout,依次放入1个 TextView 显示个人信息;1 个水平方向的 LinearLayout,放置 3 个 CheckBox;个TextView,id 设为 tv result,用于显示多选框的选择结果。注意水平方向的 LinearLayout,通过 UI面板拖入时,默认宽高都是 match parent,这样会导致最后1个 TextView 被挤出屏幕,变得不可见,因此该水平 LinearLayout 需要将高度设置为 wrap content。为了使得3 个CheckBox 平分宽度,将其宽度设为 0dp,并用 layout weight 控制宽度比例。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Your name and id" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
<!-- 注意水平LinearLayout 的高度是wrap_content-->
        
        <CheckBox
        android:id="@+id/cb1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="爬山" />
        <CheckBox
            android:id="@+id/cb2"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="跑步" />
        <CheckBox
            android:id="@+id/cb3"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="游泳" />
    </LinearLayout>

    <TextView
        android:id="@+id/tv_result"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="" />

</LinearLayout>

2.MianActivity.java

主程序MainActivity 如代码 2-15 所示。文本对象tv 显示 CheckBox 的选中结果,其程序逻辑是哪几个多选框被选中,就将其文本取出拼接成 1 个字符串显示到 tv 对象上。通过CheckBox 的侦听和回调处理可发现,每个 CheckBox 只能在回调函数中获知自身的选中状态(onCheckedChanged(方法的 isChecked 状态值),无法有效处理本任务的逻辑。不妨利用CheckBox 对象的 isChecked0)方法判断该对象是否选中,并在回调中对每个 CheckBox 的状态进行遍历,若是选中,则取其文本拼接到字符串变量 s 上,并且为了文字美观,对前两个CheckBox 的文本拼接时,拼接结尾加空格隔开文本。

由于在 CheckBox 的回调函数中调用了所封装的 pdateCheckBox0方法,而在该方法中需要访问 3 个 CheckBox 和 TextView,这些变量均在 MainActivity 的 onCreate0)之外,因此需要将这些变量声明为 MainActivity 类的成员变量才能使得各个函数均能访问到。此外,findViewByld0需要在 setContentView0调用生成视图后才能从视图中找到对应 id 的 Ul,而视图生成在 onCreate)中执行,类成员变量声明时直接赋值的话会在所有函数之前完成,因此不能在成员变量声明时直接通过 findViewById0赋值(会得到 null 空对象)。

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.Toast;

import java.util.Random;

public class MainActivity extends AppCompatActivity {
    CheckBox cb1,cb2,cb3;
    //onCreate 函数之外访问,定义成员变量更合适
    TextView tv;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.my_main);
        tv=findViewById(R.id.tv_result);
        cb1=findViewById(R.id.cb1);
        cb2=findViewById(R.id.cb2);
        cb3=findViewById(R.id.cb3);

        cb1.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            //多选框的选中侦听和事件回调
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                updateCheckBox();
            }
        });
        cb2.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            //多选框的选中侦听和事件回调
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                updateCheckBox();
            }
        });
        cb3.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            //多选框的选中侦听和事件回调
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                updateCheckBox();
            }
        });

    }

    private void updateCheckBox() {
        //讲3个多选框选中状态更新道TextView的处理程序,封装成函数,方便调用
        String s="";
        if(cb1.isChecked()){    //判断cb1是否被选中,true为选中
            s+=cb1.getText()+" ";
            //如果某个多选框选中,取对应文本,拼接道s变量,且前2个字符串加空格间隔
        }
        if(cb2.isChecked()){
            s+=cb2.getText()+" ";
        }
        if(cb3.isChecked()){
            s+=cb3.getText();
        }
        tv.setText(s);
    }
}

 另一种实现方法是通过对 MainActivity 类实现 OnCheckedChangeListener 接口和回调。由于 CheckBox 是继承至 CompoundButton 类,接口OnCheckedChangeListener 是在 CompoundButton 类中定义的,因此 MainActivity 类通过implements CompoundButton.OnCheckedChangeListener 来实现多选框的选中状态改变侦听,不过读者不用担心 CheckBox 是否继承至 CompoundButton,只需在 Android Studio 中输入CheckBox.OnCheckedChangeListener,开发环境会自动帮你转成对应类的接口。开发过程中,若仅仅输入implements CompoundButton.OnCheckedChangeListener,开发环境会有标红和感叹号标记提示错误和修正方法,其原因是在 MainActivity 中并没有真正完成相关接口的实现方法,点击感叹号(或者alt+enter)按提示增加接口需要改写的方法onCheckedChanged0),注意该方法之前有@Override 关键词,表示改写方法,若没有该关键词,则onCheckedChanged()仅仅是 MainActivity 类的一个普通方法,和 OnCheckedChangeListener接口没有任何关系,相关事件触发不会对该方法产生回调。在 onCheckedChanged0方法中调用自定义方法 updateCheckBox(处理多选框逻辑,最后对每个 CheckBox 对象使用setOnCheckedChangeListener(this)即可设置选中状态侦听,这里 this 指向的是 MainActivity实例,当用户点击 CheckBox 使得多选框选中状态发生改变,其事件会传到 this,而 this 指向的 MainActivity 实例具有 OnCheckedChangeListener 接口,与多选框的侦听器匹配,因此触发该接口的回调方法 onCheckedChanged0),进而通过 updateCheckBox()方法实现了预期的逻辑处理。

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.Toast;

import java.util.Random;

public class MainActivity extends AppCompatActivity implements CompoundButton.OnCheckedChangeListener{
    CheckBox cb1,cb2,cb3;
    //onCreate 函数之外访问,定义成员变量更合适
    TextView tv;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.my_main);
        tv=findViewById(R.id.tv_result);
        cb1=findViewById(R.id.cb1);
        cb2=findViewById(R.id.cb2);
        cb3=findViewById(R.id.cb3);

        cb1.setOnCheckedChangeListener(this);
        cb2.setOnCheckedChangeListener(this);
        cb3.setOnCheckedChangeListener(this);

/*        cb1.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            //多选框的选中侦听和事件回调
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                updateCheckBox();
            }
        });
        cb2.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            //多选框的选中侦听和事件回调
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                updateCheckBox();
            }
        });
        cb3.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            //多选框的选中侦听和事件回调
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                updateCheckBox();
            }
        });*/

    }

    private void updateCheckBox() {
        //讲3个多选框选中状态更新道TextView的处理程序,封装成函数,方便调用
        String s="";
        if(cb1.isChecked()){    //判断cb1是否被选中,true为选中
            s+=cb1.getText()+" ";
            //如果某个多选框选中,取对应文本,拼接道s变量,且前2个字符串加空格间隔
        }
        if(cb2.isChecked()){
            s+=cb2.getText()+" ";
        }
        if(cb3.isChecked()){
            s+=cb3.getText();
        }
        tv.setText(s);
    }

    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        updateCheckBox();
    }
}

6.任务6-获取并显示可编辑文本框文本

本任务演示效果如图 2-13 所示,视图根节点为垂直的线性布局 LinearLayout,依次放置个 TextVicw,显示个人信息;1 个可编辑文本框 EditText,当内容为空时,显示提示信息“输入你的姓名”1个按钮 Button 和1个回显的 TextView,当按钮按下,则最后一个TextView显示 EditText 中输入的内容。

 1.实现

1.my_mian.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Your name and ID" />

    <EditText
        android:id="@+id/editText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="输入你的姓名"
        android:ems="10"
        android:inputType="textPersonName"
        android:text="" />

    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="获取编辑文本框" />

    <TextView
        android:id="@+id/tv_result"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="" />
</LinearLayout>

2.MainActivity.java

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.Toast;
import java.util.Random;

public class MainActivity extends AppCompatActivity{
    TextView tv;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.my_main);
        tv=findViewById(R.id.tv_result);
        final EditText et=findViewById(R.id.editText);
        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                tv.setText(et.getText().toString());
            }
        });
    }

}

7.任务7-文本颜色的控制以及UI边距

本任务演示效果如图2-14所示,根节点为垂直的线性布局 LinearLayout,依次放置1个TextView(显示个人信息)和1个水平方向的线性布局LinearLayout,在水平线性布局里有3个等宽的按钮Button(内容分别为Red、Blue和Other),且按左右各有5dp的边距点击按钮,TextView的文本颜色变成按钮指向的对应颜色。

UI的边距分为外边距和内边距两种,具体区别如图 所示,外边距称为argin,是UI轮廓之外的边距,若设定了外边距,则在  之外还形成假想的边框,外部假想边框与UI之间的间距即为外边距;内边距称为 padding,是UI真实边框内部与UI实体内容之间的间距,例如一个 Button,其内边距是按钮所见边框与按钮内文本的边距。

 

 外边距的具体属性有 android:layout margin ,设置上下左右外边距,例如android:layout_margin="5dp"表示该 UI 上下左右外边距均为 5dp; android:layout marginStart设置文字起始外边距(默认是左边); android:layout marginEnd 设置文字结束外边距(默认是右边); android:layout marginHorizontal 设置左右外边距,相当于上述的 layout marginStart和 layout_marginEnd 同时取相同的值; android:layout marginTop 设置 UI 的上外边距:android:layout marginBottom 设置 UI 的下外边距;android:layout marginVertical设置 UI的上下外边距。同理,对内边距的设置,也有 android:padding 设置上下左右内边距,android:paddingLet 设置左边距,android;paddingRight 设置右边距等,不赘述。

1.实现

1.my_main.xml

使用内边距无法使得各个按钮隔开空隙,内边距只能控制按钮内文本离按钮边框的距离,因此需要使用外边距,并且每个按钮需要设置左右外边距,此时更方便的设置方式是通过 android:layout marginHorizontal 属性设置,具体的布局如代码 2-19 所示,3个按钮通过宽度为0dp 和权重值 1 实现等宽分配,并利用 android:layout_marginHorizontal值为5dp 设置了 5dp 的左右外边距,实际效果中,第 1个 Button 离屏幕左边有 5p 边距,第1个和第 2 个 Button 以及第 2 个 Button 和第 3 个 Button 之间均有 10dp 的外边距,第 3 个 Button离屏幕右边有 5dp 的外边距。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Your name and ID" />

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

        <Button
            android:id="@+id/bt_red"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:layout_marginHorizontal="5dp"
            android:text="Red" />
<!-- 使用android: layout_marginHorizontal 设置左右外边距 -->
        <!-- 若使用padding 属性设置内边距无法是的按钮形成隔开空隙-->
        <Button
            android:id="@+id/bt_blue"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:layout_marginHorizontal="5dp"
            android:text="Blue" />

        <Button
            android:id="@+id/bt_other"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:layout_marginHorizontal="5dp"
            android:text="Other" />
    </LinearLayout>
</LinearLayout>

2.控制颜色属性

文本对象的颜色设置,既可以在 XML 布局中通过 android;textColor 属性进行设置,也可以在JAVA 中通过文本对象的 setTextColor(@ColorlInt int color)方法设置。若是在 XML 中设置,可以直接使用颜色值,也可以引用颜色值。直接使用颜色值是用“#”开头的,后面是 16 进制值,有 4 种格式:

  1.  #RGB,分别用 1位 16 进制数分别表示红色(R: Red)、绿色(G: Green)和蓝色(B: Blue),值越大,对应通道颜色值越大,例如#F00 表示红色;
  2. #RRGGBB,分别用 2 位 16 进制数表示对应通道颜色,例如#F00000 表示红色通道值=0xFOh,其他通道颜色值为 0的颜色,#F00 与#FFO000 等效:
  3. #ARGB,在 RGB 的基础上增加了 1位 16 进制数表示 Apha 通道,即透明度,值越大越不透明,值为0 则全透明:
  4. #AARRGGBB,在#RRGGBB 基础上增加了2 位 16 进制数的 AIha 通道,用于控制透明度属性。

一旦在XML中设置了颜色属性,即可在左边预览到颜色效果,具体如图2-16所示,点击预览的颜色还可以调出取色表盘,如图2-17 所示,以方便颜色的可视化赋值。若在XMI中使用引用值,则普遍的做法是将颜色定义在res/values/colors.xml文件中,项目创建好后默认已有该文件并预先定义了若干个与主题相关的颜色。颜色在 colors.xml 中定义,一般定义在<resources>节点下,用<color>标签表示颜色,name属性是该颜色的名称,以方便引用值则定义在标签内。 

 

 在本例中,对 colors.xml 增加了一个自定义颜色,在 XML 中可用@color/other_color 引用到该颜色,在JAVA 中,则需要先通过 getResources0得到资源对象再通过 getColor(R.color.other color)得到颜色值,事实上返回值是 int 类型,其 16 进制值与#AARRGGBB 相同。若要在 XML 中将 TextView 文本颜色设置为 colorsxml 所定义的other color 颜色,可在 TextView 中增加如下属性:

android:textColor="@color/other_color"

 res/values/colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#008577</color>
    <color name="colorPrimaryDark">#00574B</color>
    <color name="colorAccent">#D81B60</color>

    <color name="red">#CC0129</color>
    <color name="blue">#025CAA</color>
    <color name="other_color">#068E81</color>

</resources>

3.MainActivity.java

3 个按的点击触发直接在 fndViewByld 方法所返回的 View 对象上实现,因此采用链式写法。在JAVA 中可直接使用 android.graphics.Color类预定义的值作为颜色值,例如,Color.RED 即为红色,其代表的 int 值 16 进制即为#FFFF0000,实际编程中直接输入 Color 的部分内容选择该类可实现自动导入相应包。文本对象 setTextColor(@ColorInt int color)所需的参数实际上就是 int 值,因此也可以直接用 16进制值设置颜色,例如 tvsetTextColor(0xf0000)和 tvsetTextColor(Color.BLUE)所设的颜色相同。本例中还使用了 res/values/colorsxml 中的自定义颜色 other color,此为资源数据,需要先得到资源对象。资源对象在 MainActivity 中,可通过 getResources0获得,再利用资源对象提供的 getColor()方法 (参数是 R.color.xxx 形式,xxx 为该颜色在 XML 中的名称)即可取得颜色

import androidx.appcompat.app.AppCompatActivity;

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

public class MainActivity extends AppCompatActivity{
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.my_main8);
        final TextView tv=findViewById(R.id.textView);
        findViewById(R.id.bt_red).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                tv.setTextColor(Color.RED);
                //TextView 对象的 setTextColor 可设置文本颜色
                //Color 类是 android 提供的颜色类,预先定义了若干种常用颜色值
                // Color.RED=0xFFFF0000,转换回 int 值即=-0010000=-65536 (补码规则)
            }
        });

        findViewById(R.id.bt_blue).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //tv.setTextColor(Color.BLUE);
                tv.setTextColor(0xff0000ff);
            }
        });
        findViewById(R.id.bt_other).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int otherColor =getResources().getColor(R.color.other_color);
                //变量声明可先使用方法调用,再利用 ctr+alt+v,将返回值生成局部变量
                tv.setTextColor(otherColor);
            }
        });
    }
}

8.大作业

编写一个程序,在一个垂直布局 LinearLayout 里有4 个水平布局的 LinearLayout 和3个TextView。

  • 第一个水平布局的 LinearLayout 里面有 1个 TextView 部件和 EditText 部件,其中 TextView和 EditText 按1:3 分布,TextView 文字右对齐;
  • 第二个水平布局的 LinearLayout 里面依次放有 1个 Button 和1个 TextView 部件,Button 点击后能把第一个水平布局里的 EditText 的内容更新到 Button 右边的 TextView 部件上:
  • 第三个水平布局的 RadioGroup 里有一组 RadioButton,三个组件所占空间平均分配;
  • 第四个水平布局的 LinearLayout 里有三个 Checkbox,三个组件所占空间平均分配;
  • 第五个部件为 TextView,字体红色,显示 RadioButton 选中项(单选);
  • 第六个部件为 TextView,字体蓝色,显示CheckBox 选中项(多选):
  • 第七个部件为 TextView,显示你的学号和姓名。

实现:

1.my_main.xml:

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

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

        <TextView
            android:id="@+id/tv1"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="right"
            android:text="Name" />

        <EditText
            android:id="@+id/editText"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="3"
            android:ems="10"
            android:hint="Please input your name"
            android:inputType="textPersonName"
            android:text="" />

    </LinearLayout>

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

        <Button
            android:id="@+id/button"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="3"
            android:text="get name" />

        <TextView
            android:id="@+id/tv_ed"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="7"
            android:text="" />

    </LinearLayout>

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

        <RadioGroup
            android:id="@+id/rg"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="horizontal">

            <RadioButton
                android:id="@+id/rb1"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="Running" />

            <RadioButton
                android:id="@+id/rb2"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="Swimming" />

            <RadioButton
                android:id="@+id/rb3"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="Basketball" />
        </RadioGroup>
    </LinearLayout>

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

        <CheckBox
            android:id="@+id/cb1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Red" />

        <CheckBox
            android:id="@+id/cb2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Green" />

        <CheckBox
            android:id="@+id/cb3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Blue" />
    </LinearLayout>

    <TextView
        android:id="@+id/tv_rb"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textColor="#FFC00829"
        android:text="For RadioButton"
        />

    <TextView
        android:id="@+id/tv_cb"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textColor="#FF1B44D8"
        android:text="For CheckButton" />

    <TextView
        android:id="@+id/tv2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Your name and Id" />

</LinearLayout>

 2.MainActivity.java:

import androidx.appcompat.app.AppCompatActivity;

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.RadioButton;
import android.widget.RadioGroup;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    TextView tv1,tv_ed,tv_rb,tv_cb;
    EditText et;
    CheckBox cb1,cb2,cb3;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.my_mian);
        onBt();
        onCb();
        onRg();
    }
    private void onBt(){
        tv1=findViewById(R.id.tv1);
        tv_ed=findViewById(R.id.tv_ed);
        et=findViewById(R.id.editText);
        Button bt=findViewById(R.id.button);
        bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String s=et.getText().toString();
                tv_ed.setText(s);
            }
        });
    }
    private void onRg(){
        RadioGroup radioGroup=findViewById(R.id.rg);
        tv_rb=findViewById(R.id.tv_rb);
        radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(RadioGroup radioGroup, int i) {
                RadioButton tb=findViewById(i);
                tv_rb.setText(tb.getText());
            }
        });
    }
    private  void onCb(){
        cb1=findViewById(R.id.cb1);
        cb2=findViewById(R.id.cb2);
        cb3=findViewById(R.id.cb3);
        tv_cb=findViewById(R.id.tv_cb);
        cb1.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
                updateCHeckBox();
            }
        });
        cb2.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
                updateCHeckBox();
            }
        });
        cb3.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
                updateCHeckBox();
            }
        });
    }
    private void updateCHeckBox() {
        String s="";
        if(cb1.isChecked()){
            s+=cb1.getText()+" ";
        }
        if(cb2.isChecked()){
            s+=cb2.getText()+" ";
        }
        if(cb3.isChecked()){
            s+=cb3.getText()+" ";
        }
        tv_cb.setText(s);
    }
}

 3.实验展现

 

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值