2 构建交互式应用:真正有用的应用

0 绪言

大多数应用都需要以某种方式响应用户

这一章中,你将了解怎样让你的应用更有交互性。你会看到如何让应用些事情来响应用户,以及如何让活动和布局像朋友一样交谈。在这个过程中,我们还会通过介绍R带你更深入地了解Android具体如何工作,R就像是个秘密宝石,可以把所有这些连接在一起。

1 引入

1.1 需求引入

这一章中,我们会向你展示如何创建与用户交互的应用:这里会创建一个啤酒荐酒师(Beer Adviser)应用。在这个应用中,用户可以选择他们喜欢的啤酒类型,然后单击一个按钮,会得到一个列表,列出用户可以品尝的一组啤酒。

这个应用的结构如下:

1.布局指定应用是什么样

它包括3个GUI组件:

  • 一个值下拉列表,这称为spinner,允许用户选择他们想要的啤酒类型;
  • 一个按钮,单击这个按钮会返回选择的啤酒类型
  • 一个文本域,用来显示啤酒类型

2.文件strings.xml包括布局所需的所有字符串资源,例如,布局中指定的按钮的标签

3.活动指定应用如何与用户交互

根据用户选择的啤酒类型,利用这个信息显示用户可能感兴趣的一组啤酒。这里要借助于一个定制Java类。

4.定制Java类包含应用的应用逻辑

它包括一个方法,这个方法取啤酒类型作为参数,返回一个列表,其中包括这种类型的所有啤酒。活动会调用这个方法,传入啤酒类型,然后使用得到的响应。

1.2 需要完成的工作

1.创建一个工厂

2.更新布局

3.将布局与活动关联:布局只是创建一个可视的组件。要让应用真正聪明起来,还需要把布局与活动中的Java代码关联起来。

4.编写应用逻辑 :要为应用增加一个定制Java类,用它确保用户可以根据选择的啤酒类型得到想要的啤酒。

1.3 更新布局--布局XML与代码讲解

1.3.1 布局XML代码

布局文件代码为:

<RelativeLayout 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:paddingBottom="16dp"
    android:paddingLeft="16dp"
    android:paddingRight="16dp"
    android:paddingTop="16dp"
    tools:context=".MainActivity" >
    <Spinner android:id="@+id/color"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="37dp"
        android:entries="@array/beer_colors" />
    <Button android:id="@+id/find_beer"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/color"
        android:layout_below="@+id/color"
        android:text="@string/find_beer"
        android:onClick="onClickFindBeer" />
    <TextView android:id="@+id/brands"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/find_beer"
        android:layout_below="@+id/find_beer"
        android:layout_marginTop="18dp"
        android:text="@string/brands" />
</RelativeLayout>

下面对这里面的代码进行详解:

1.3.2 常用属性

按钮和文本视图是同一个AndroidView类的子类:

按钮和文本视图之所以会有共同的属性,是因为:他们都继承了同一个Android View类

现在来看常用的属性:

android:id

这个属性为组件指定一个标识名。利用ID属性,可以通过活动代码来控制组件完成工作,另外还可以控制组件在布局中的位置:

android:id="@+id/button" 

android:text

这会告诉Android组件应当显示什么文本。对于<Button>,这就是出现在按钮上的文本。

android:layout_width, android:layout_height

这两个属性指定了组件的基本宽度和高度。"wrap _ content"表示它要足够大,刚好能放下全部内容,表示和自身内容一样的长度。

1.3.3 RelativeLayout元素

布局代码的第一个元素是<RelativeLayout>。<RelativeLayout>元素告诉Android布局中的各个GUI组件要在相对位置上显示

使用相对布局,意味着GUI组件要相对地定位

举例来说,可以用这个元素指出你希望某个组件出现在另一个组件左边,或者希望这些组件以某种方式对齐或者排列。

在这个布局代码中,按钮出现在文本视图下面,因此按钮会相对于文本视图显示。

1.3.4 TextView元素

<RelativeLayout>中的第一个元素是<TextView>。

<TextView android:id="@+id/brands"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/find_beer"
        android:layout_below="@+id/find_beer"
        android:layout_marginTop="18dp"
        android:text="@string/brands" />

这里并没有设置任何属性来指定文本视图显示在布局的什么位置,所以默认地,Android会把它显示在屏幕的左上角。注意,这里为文本视图指定了ID为textView。接下来介绍下一个元素时你会了解为什么需要这个ID。

1.3.5 Button元素

<RelativeLayout>的最后一个元素是<Button>

 <Button android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/find_beer"
        android:layout_alignLeft="@+id/textView"
        android:layout_below="@+id/textView"
       />

将按钮增加到布局时,我们指定了按钮的位置,把它放在文本视图下面,让按钮的左边界与文本视图的左边界对齐。这里按钮相对于文本视图放置,这在XML中也有体现:

android:layout_alignLeft="@+id/textView"
android:layout_below="@+id/textView"

可以用很多不同的方式写布局XML来生成同样的视觉效果。举例来说,上面的XML指定了按钮放在文本视图下面。还有一种等价的说法,可以说文本视图放在按钮上面。

1.3.6 对1.3.1中的布局进行解析

1.3.7 使用字符串资源而不是硬编码文本

使用字符串资源,不使用硬编码文本,这是一个很好的习惯。

打开app/src/main/res/values/strings.xml文件,编辑一下代码:

<resources>
    <string name="app_name">Beer Adviser</string>

    <string name="action_settings">Settings</string>
    <string name="find_beer">Find Beer!</string>
    <string name="brands"></string>
    <string-array name="beer_colors">
        <item>light</item>
        <item>amber</item>
        <item>brown</item>
        <item>dark</item>
    </string-array>
</resources>

 编写完字符串资源之后,将代码更新到布局XML文件中。

1.3.8 spinner元素

Spinner元素标签的代码:

<Spinner android:id="@+id/color"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="37dp"
        android:entries="@array/beer_colors" />

目前,布局包括一个spinner,不过其中没有任何内容。使用spinner时,往往要让它显示一个值列表,允许用户选择他们想要的值。

可以像设置按钮和文本视图的文本一样,采用同样的方式为spinner提供一个值列表,也就是使用一个资源。到目前为止,我们已经使用strings.xml指定单个的字符串值。这里要做的就是指定一个字符串值数组,再让spinner引用这个值数组

增加数组资源与增加字符串类似

已知向strings.xml添加string 字符串资源的代码:

<string name="string_name">string_value</string>

其中,string_name为字符串的标识符,string_value是字符串值本身。

增加一个字符串数组,可以使用下列语法:

<string-array name="string_Array_name">
    <item>string_value1</item>
    <item>string_value2</item>
    <item>string_value3</item>
    ...
</string-array>

这里string _ array _ name是数组名,string _ value1、string _value2、string _ value3是组成这个数组的字符串值。

在strings.xml中增加一个字符串数组,内容如1.3.7中所示。

让spinner引用字符串数组

使用语法为:   "@array/array_name"

此处的array_name为数组名。

在布局XML文件中,使用这个数组,需要为spinner增加一个entries属性,然后在进行赋值:

android:entries="@array/beer_colors"

1.4 关联活动

1.4.1 让按钮做事

需要在单击按钮时,让应用根据spinner中选择的值做出响应,我们希望应用能够有一下表现:

1.用户从spinner选择一个啤酒类型  用户单击按钮查找与类型匹配的啤酒

2.布局指定单击按钮时要调用活动中的哪个方法

3.这个方法获取spinner中选择的啤酒类型值,将它传递到一个名为BeerExpert的Java定制类的getBrands()方法

4.BeerExpert的getBrands()方法查找与这个啤酒类型匹配的啤酒品牌,然后作为一个String ArrayList返回给活动

5.活动得到布局中文本视图的一个引用,将这个文本视图的文本值设置为与类型匹配的啤酒列表。这个啤酒列表将显示在设备上。

1.4.2 让按钮调用一个方法

向布局增加一个按钮时,你可能希望当用户单击这个按钮时它能做些什么。为此,要让按钮调用活动中的一个方法。

单击按钮时要让按钮调用活动中的一个方法,这需要对两个文件做出修改:

  • 需要修改布局文件XML  我们要指定单击按钮时调用活动中的那个方法。
  • 需要修改活动文件  要编写所调用的方法。

首先,要使用onClick指定按钮调用哪个方法,只需要在布局文件XML的<button>元素中增加一个android:onClick属性,并指定想要调用的方法名:

android:onClick="method_name"

其中,method_name表示“单击这个组件时,要调用活动中名为method_name的方法”

1.4.3 默认生成的活动代码分析

AS默认创建的活动代码为:

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

//活动类扩展了Android的AppCompatActivity类
public class MainActivity extends AppCompatActivity {

    //onCreate()方法,第一次创建活动时会调用这个方法
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //setContentView告诉Android活动使用哪个布局。在这里,他要是用activity_main布局
        setContentView(R.layout.activity_main);
    }
}

以上,是创建一个基本活动所需的全部代码。

这个类是扩展自 androidx.appcompat.app.AppCompatActivity 的类,而且实现了一个onCreate()方法。

所有的活动都必须扩展AppCompatActivity类。AppCompatActivity包含一组方法,这是这组方法为你的Java类赋予了Android声明,把它从一个普通的Java类变成了一个功能完备的正式的Android活动

另外所有活动都需要实现o nCreate ()方法。创建活动对象时会调用onCreate()方法,这个方法用来完成一些基本设置,如这个活动与哪个布局关联。这要使用setContentvie w()方法来设置。在上面的示例中,setContentview(R.layout.activity_main)告诉Android这个活动会使用activity_main作为它的布局。

1.4.4 活动代码加入单击方法

在1.4.2中为布局中的按钮增加了一个onClick属性,并指定为onClickFindBeer,现在要为活动增加这个方法,使得单击按钮时能调用这个方法。这样的话,用户触摸用户界面中的按钮时,活动就能做出响应。

onClickFindBeer()方法需要有一个特定的签名,否则单击布局中指定的按钮时将无法调用这个方法。这个方法要有以下形式:

  1. 1.方法一定要是 公共的 
  2. 2.方法的返回值一定要是 void
  3. 3.方法的形参一定要有个类型为 View的参数

 如果方法未采用这种形式,用户触摸按钮时这个方法不会有任何响应这是因为在后台Android会查找一个有void返回值的公共方法,而且方法名要与布局XML中指定的方法匹配。

方法中的View参数乍一看可能有些奇怪,不过这个参数的存在是有道理的。这个参数指示触发这个方法的GUI组件(在这里就是按钮)。前面已经提到过,GUI组件(如按钮和文本视图)都是某种类型的View

现在将这个方法添加到活动类MainActivity.java中。然后需要让这个方法运行时做一些具体的工作。要让应用显示与用户所选啤酒类型匹配的一组啤酒。

除此之外,也可以通过获取按钮的id,然后获取Button对象之后,使用Button类中的setOnClickListener()方法来进行单击事件的监听。代码形如:

Button button1 =(Button) findViewById(R.id.button_1);
button1.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                Toast.makeText(FirstActivity.this,"You click Button 1",
                        Toast.LENGTH_SHORT).show();
          }
});

1.4.5 探究findViewById()与R.java

为了达到这个目的,首先需要得到布局中spinner以及文本视图GUI组件的引用。这样一来,我们就能从spinner获取所选啤酒类型的值,另外可以在文本视图中显示文本。

使用findViewByld)得到视图的引用

可以使用一个名为findviewById()的方法得到这两个GUI组件的句柄

findviewById()方法取GUI组件的ID作为参数,返回一个view对象。然后把这个返回值转换为正确的GUI组件类型(例如,TextView或Button)。

可以如下使用findviewById()得到ID为brands的文本视图的一个引用:

 仔细查看如何指定文本视图的ID。这里并不是传入文本视图的名字而是传入了一个形如R.id.brands的ID。这到底是什么意思?什么是R

 R.java是一个特殊的Java类,利用这个类可以获取应用中不同资源的引用。

 R.java是一个特殊的Java文件,只要你创建或构建应用,Android工具就会生成这个文件。它位于工程app\build\generated\not_namespace_xxx_source\r文件夹下的一个包中,这个包与应用包同名。Android使用R跟踪应用中使用的资源,它有很多作用,例如允许在活动代码中得到GUI组件的引用

如果打开R.java,可以看到其中包含乙烯类内部类,分别对应不同类型的资源。可以在内部类中引用各种类型的资源。 

举例来说,R中有一个名为id的内部类,这个内部类包含一个static final brands.利用一下代码行:

/**R.java**/

public static final class id {
        //...
        public static final int brands=0x7f080022;
        //...
}


/**MainActivity.java**/
(TextView)findViewById(R.id.brands)

可以由这个值得到brands文本视图的引用.

一旦有了View,就能访问他的方法

findviewById()方法会为你提供GUI组件的一个Java版本。这说明,你可以使用Java类提供的方法获取和设置GUI组件的属性

1.4.6 通过id设置组件的各种属性值

findviewById()方法会为你提供GUI组件的一个Java版本。这说明,你可以使用Java类提供的方法获取和设置GUI组件的属性

1.设置TextView中的文本

先获取TextView对象brands,然后在这个TextView对象上调用方法。比如想设置brands文本视图中显示的文本内容,TextView类中包含一个setText()方法,用来修改text属性,因此可以通过以下代码完成设置:

TextView brands = (TextView) findViewById(R.id.brands);
brands.setText("Gottle of geer");

2.获取spinner中选取的值

就像得到文本视图的引用一样,可以采用类似的方式得到spinner的引用。像前面一样使用findviewById()方法,只不过这一次要把结果强制转换为一个Spinner:

Spinner color = (Spinner) findViewById(R.id.color);

这会得到一个Spinner对象,现在就能访问这个对象的方法了。来看一个例子,可以如下获取spinner中当前选中的列表项,把它转换为一个String:

String.valueOf(color.getSelectedItem());

因为:

color.getSelectedItem();

 实际上会返回一个通用的Java对象。这是因为,spinner值可能不是String,比如有可能是一个图像。在这里,我们知道这些值肯定是String,所以可以使用string.valueof()把选中的列表项从Object转换为string。

1.4.7 完整的活动代码V1.0

public class MainActivity extends AppCompatActivity {

    //onCreate()方法,第一次创建活动时会调用这个方法
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //setContentView告诉Android活动使用哪个布局。在这里,他要是用activity_main布局
        setContentView(R.layout.activity_main);
    }

    public void onClickFindBeer(View view){
        TextView brands = (TextView) findViewById(R.id.brands);
        brands.setText("Gottle of geer");
        Spinner color = (Spinner) findViewById(R.id.color);
        String  beerType=String.valueOf(color.getSelectedItem());
        brands.setText(beerType);
    }
}

测试:

 1.5 构建定制JAVA类

1.5.1 构建定制Java类---BeerExpert

这一章开始时我们说过,这个啤酒荐酒师(Beer Adviser)应用要在一个定制Java类的帮助下推荐啤酒。这个定制Java类用普通的Java编写,根本不知道它将用于一个Android应用

定制java类的格式要求

  • 与活动类在同一个包下面。
  • 类名应当是BeerExpert。
  • 要提供一个方法getBrands(),它取一个期望的啤酒颜色(表示为一个String),返回一个List<String>(包含所推荐的啤酒)。
     

 构建和测试Java类,这是一个纯Java代码,不涉及任何有关Android的内容

public class BeerExpert {
    List<String> getBrands(String color){
        List<String> brands=new ArrayList<>();
        if (color.equals("amber")){
            brands.add("Jack Amber");
            brands.add("Red Moose");
        }else{
            brands.add("Jail Pale Ale");
            brands.add("Gout Stout");
        }
        return brands;
    }
}

1.5.2 改进活动调用定制Java类来得到真正的建议

在活动的第二个版本中,我们要改进onclickFindBeer()方法调用BeerExpert类来得到推荐的啤酒。这里只需要修改普通的Java代码。

自写代码:

public class MainActivity extends AppCompatActivity {
    private BeerExpert beerExpert=new BeerExpert();//设置为私有成员变量
    //onCreate()方法,第一次创建活动时会调用这个方法
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //setContentView告诉Android活动使用哪个布局。在这里,他要是用activity_main布局
        setContentView(R.layout.activity_main);
    }

    public void onClickFindBeer(View view){
        TextView brands = (TextView) findViewById(R.id.brands);
        brands.setText("Gottle of geer");
        Spinner color = (Spinner) findViewById(R.id.color);
        String  beerType=String.valueOf(color.getSelectedItem());
        List<String> beerTypes=beerExpert.getBrands(beerType);
        StringBuilder sb=new StringBuilder();
        for (String  s:beerTypes){
            sb.append(s+"\n");
        }
        brands.setText(sb.toString());
    }
}

输出:

 2.总结

  • Button元素用来增加按钮。
  • Spinner元素用来增加spinner。spinner是一个值下拉列表。所有GUI组件都是某种类型的视图。它们都继承自Android View类。
  • 使用以下代码增加字符串值数组:
<string-array name="array">
<item>stringl</item>...
</string-array>
  • 使用以下代码在布局中引用string-array:"@array/array name"
  • 在布局中增加以下代码,单击按钮时就会让按钮调用一个方法:
android: onClick="clickMethod"

活动中需要有一个相应的方法:
 

public void clickMethod (View view){}
  • 会为你自动生成R.java。利用这个文件,可以在Java代码中得到布局、GUI组件、字符串和其他资源的引用。
  • 使用findviewById()可以得到一个视图的引用。
  • 使用setText()可以设置视图中的文本。
  • 使用getSelectedItem()可以得到一个spinner中所选择的列表项。
  • 可以通过菜单File→New...→Java Class为Android工程增加一个定制类。
     
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值