模块2 Android UI界面设计Web安全时,跨站脚本(XSS)漏洞是一个

项目2-1 物联网环境状态值界面设计

学习目标

■ 了解UI界面设计中组件、容器、界面布局和事件等相关概念。

■ 掌握Android基本组件TextView、EditText和Button组件的使用方法。

■ 掌握Android中Button组件的事件处理机制。

■ 掌握Android线性布局技术。

■ 了解strings.xml、colors.xml的作用,学会strings.xml、colors.xml的运用。

■ 了解样式和主题的作用,学会样式和主题的设计。

■ 学会运用Android线性布局的方法来实现物联网环境状态值界面设计。

项目描述

运用Android线性布局技术,设计一个能够对物联网环境状态值中的温度、湿度、光照等值进行设置的UI界面。

知识储备

2.1.1 UI界面的组件和容器

UI 是用户界面(User Interface)的简称,是系统和用户之间进行信息交换的媒介,在设计Android的应用程序时,UI界面设计是非常重要的一部分。由于用户终端屏幕尺寸大小各异,为了确保程序在运行时尽量不受屏幕尺寸大小的影响而产生界面变形,导致不好的用户体验,在UI界面设计中,UI的大小必须适应各类屏幕,并能自动调整而不是由用户去设定。另外, UI的设计和具体功能的实现需要在逻辑上进行分离,从而使UI设计者和程序开发者能够相对独立地工作,以提高工作效率,避免在后期维护时功能的修改对UI设计产生影响。

对于上述两个问题,首先,Android系统采用相对定位的方式,使UI设计者通过相对大小或相对位置来放置所需的组件,从而帮助整个 UI 在不同屏幕尺寸上实现动态调整,并正确地显示在屏幕中。其次,UI 设计和功能实现在逻辑上分离的问题,Android 系统采用 UI 设计,并由特殊的XML文件进行绘制,而具体的功能则是在Java代码中完成,两者之间通过对应的ID号进行关联,从而达到逻辑和物理上的分离。

Android体系中UI的设计采用视图层次(View Hierarchy)结构,而视图层次则是由View (视图)和ViewGroup(容器)组成,如图2-1所示。Android系统会依据视图层次结构从上至下绘制每一个界面元素。

图2-1 Android用户界面视图层次

View在Android中可以理解为视图,它占据屏幕上的一块矩形区域,负责提供组件绘制和事件的处理方法。View 类是所有的 widgets 组件的基类,如文本框(TextView)、编辑框(EditText)和按钮(Button)等都是widgets组件。

ViewGroup在Android中可以理解为容器,ViewGroup类继承自View类,它是View类的扩展,是用来容纳其他组件的容器,但是由于 ViewGroup 是一个抽象类,所以在实际应用中通常是用ViewGroup的子类来作为容器,如在2.1.2小节界面布局中介绍的布局管理器。

在Android中View及其子类的相关属性,既可在XML布局文件中设置,也可以通过成员方法在Java代码中动态设置。其中,ID属性是每个View的唯一标识,在XML中的ID语法如下:

android:id="@+id/id名称"

字符串前的@符号表示XML解析器应该解析和扩展剩下的ID字符串,并把它作为ID资源。+符号表示这是一个新的资源名字,它必须被创建且加入R.java文件。Android框架提供一些其他的ID资源。当引用一个Android资源ID时,不需要+符号,但必须添加Android包名字空间,如android:id="@android:id/empty"。

View常用的XML属性及相关方法如表2-1所示。

表2-1 View常用的XML属性及相关方法

ViewGroup是View的子类,它主要用来充当View的容器,对子View进行管理。它与View的区别在于:ViewGroup能够容纳多个View作为ViewGroup的子组件,同时,View也可以包含ViewGroup作为其子组件,所以,View和ViewGroup是相互包容的关系。当然,在创建UI时,开发人员是直接使用Android所提供的具有不同功能的组件。

注意

Android 用户界面是单线程用户界面,在单线程用户界面中,控制器从队列中获取事件和视图在屏幕上绘制用户界面,使用的都是同一个线程。

2.1.2 界面布局

Android UI 界面上显示内容都是用组件实现的,它们都继承自 View 类,布局 Layout也是一种容器组件,继承自ViewGroup类。在Android中,容器组件里面又可以摆放其他组件,组件则是用于实现功能的图形用户界面元素。布局文件主要是设计UI界面,设定容器和组件的属性,规范组件在容器中的显示。布局文件以.XML为扩展名,保存在res/layout/下面。

Android的界面布局设计是通过XML来定义的,每一个组件摆放在窗体中,通过设置属性来调整它们的位置和大小,所有的组件都具有以下两个必需的基本属性。

① 宽度:android:layout_width=“match_parent”

属性的取值:match_parent相对父容器占满整行,wrap_content默认取组件宽度。

② 高度:android:layout_height="50dp"

属性的取值:match_parent相对父容器占满整个高度,wrap_content默认取组件高度。

另外,宽度、高度和大小的取值常用的单位是dp、sp。

注意

宽度、高度和大小可以使用像素单位dp,组件里字体大小的单位用sp。

Android提供了5种布局方式:相对布局RelativeLayout、线性布局LinearLayout、表格布局 TableLayout、帧布局 FrameLayout、绝对布局 AbsoluteLayout(基本已经被淘汰),在4.0版本后还增加了网格布局 GridLayout和碎片布局 Fragment。有关这几种布局的运用将在后面的项目中详细介绍。

2.1.3 事件相关概念

在Android的应用程序中,当用户在程序界面上执行各种操作时,应用程序必须为用户操作提供响应动作,这种响应动作就需要通过事件处理来完成。

Android平台的事件处理机制有以下两种。

1.基于监听的事件处理

对于基于监听的事件处理而言,主要就是为 Android 界面组件绑定特定的事件监听器, Android 提供了 OnClickListener、OnLongClickListener、OnFocusChangeListener、OnKeyListener、OnTouchListener、OnCreateContextMenuListener等基于监听接口的事件处理模型。

在监听器模型中,主要涉及以下3类对象。

① 事件源(Event Source):产生事件的来源,通常是各种组件,如按钮、窗口等。

② 事件(Event):事件封装了界面组件上发生的特定事件的具体信息,如果监听器需要获取界面组件上所发生事件的相关信息,一般通过事件(Event)对象来传递。

③ 事件监听器(Event Listener):负责监听事件源发生的事件,并对不同的事件做相应的处理。

基于监听的事件处理机制是一种委派式Delegation的事件处理方式,事件源将整个事件委托给事件监听器,由监听器对事件进行响应处理。这种处理方式将事件源和事件监听器分离,有利于提供程序的可维护性。

基于监听的事件处理的使用步骤如下。

① 获取普通的界面组件(事件源),也就是被监听的对象。

② 实现事件监听类,该监听类是一个特殊的Java类,必须实现一个XxxListener接口。

③ 调用事件源的setXxxListener方法,将事件监听器对象注册给普通组件(事件源)。

注明:Xxx是指事件名。

事件处理流程如下。

当事件源发生指定的事件时,Android 会触发事件监听器,由事件监听器调用相关的方法(事件处理器)来处理事件。

2.基于回调的事件处理

Android平台中,每个View都有自己处理事件的回调方法,可以通过重写View中的这些回调方法来实现需要的响应事件。当某个事件没有被任何一个 View 处理时,便会调用Activity 中相应的回调方法。Android 提供了 onKeyDown、onKeyUp、onTouchEvent、onTrackBallEvent、onFocusChanged等回调方法供用户使用。

2.1.4 TextView组件

TextView组件是用于显示字符串的文本框组件,其主要功能就是在屏幕中某个区域内显示文本内容。Android 中的文本框组件可以显示单行文本,也可以显示多行文本,而且还可以显示带图像的文本。

在Android中,可以通过两种方法向屏幕中添加TextView组件,一种是通过在XML布局文件中使用<TextView>标记添加,另一种是在Java文件中通过new关键字创建出来。推荐采用第一种方法。

1.在XML文件中添加TextView的基本语法

格式如下:

<TextView

  属性列表

/>

2.TextView组件常用属性及对应方法

在 TextView 组件中包含很多可以在 XML 文件中设置的属性,这些属性同样可以在 Java代码中动态声明。TextView组件的常用属性及对应方法如表2-2所示。

表2-2 TextView组件的常用属性及对应方法

说明

getText()可获得TextView对象的文本。Length可获得TextView中文本长度。

下面通过【例2-1】来说明TextView属性可在XML文件中直接设置,也可在Java文件中动态设置。

【例2-1】在Android Studio中新建一个Android项目,实现在屏幕上显示两行文字,要求第1行文字是通过XML布局文件进行属性设置,而第2行文字则是通过Java代码进行动态设置。

第一种方法,通过XML布局文件进行属性设置。

启动Android Studio,新建一个Android项目,修改res/layout目录下的activity_main.xml布局文件,将默认添加的相对布局(RelativeLayout)修改成线性布局(LinearLayout),并设置线性布局中的 android:orientation="vertical",即垂直方向对齐,并为默认添加的 TextView组件设置文本框属性以显示“物联网环境状态值设置”文字。另外,再添加一个 TextView 组件,此TextView组件中设置了ID属性。其他属性将通过Java代码进行动态设置。程序清单的代码如下:

<?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="com.zzhn.myapplication.MainActivity">

  <TextView

    android:layout_width="match_parent"

    android:layout_height="wrap_content"

    android:gravity="center"

    android:textSize="30sp"

    android:background="@color/colorAccent"

    android:text="物联网环境状态值设置" />

  <TextView

    android:layout_width="match_parent"

    android:layout_height="wrap_content"

    android:id="@+id/tv1"/>

</LinearLayout>

第二种方法,通过Java代码进行动态设置。

修改MainActivity.java程序,在onCreate方法中完成TextView的属性设置,代码如下:

protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_main);

    //获取ID为tv1的TextView组件

     TextView textView = (TextView)findViewById(R.id.tv1);

     //设置字体颜色

     textView.setTextColor(Color.WHITE);

     //设置字体大小

     textView.setTextSize(20);

     //设置组件背景色

     textView.setBackgroundColor(Color.BLUE);

     //显示的文字

     textView.setText("请输入数据");

     //设置为可见

     textView.setVisibility(View.VISIBLE);

     //设置文字居中

     textView.setGravity(Gravity.CENTER);

}

运行效果如图2-2所示。

图2-2 TextView运行效果

2.1.5 EditText组件

在Android中,EditText是文本输入框,它与TextView的功能基本类似,它们之间的主要区别在于 EditText 提供了可编辑的文本框。Android 中的 EditText 组件不仅可以输入单行文本,也可以输入多行文本,并且还可以输入指定格式的文本,如密码、电话号码、电子邮件地址等。

1.在XML文件中添加EditText组件的基本语法

格式如下:

<EditText

    属性列表

/>

示例:设置在EditText组件中输入密码,并且用小点“.”显示密码的文本。

<EditText

    android:layout_width="wrap_content"

    android:layout_height="wrap_content"

    <!---设置输入密码--->

    android:inputType="textPassword"

    android:hint="输入密码"

    <!---设置用小点“.”显示密码--->

    android:password="true"

    android:id="@+id/editText1"

/>

2.EditText组件常用属性和常用方法

EditText组件常用属性和常用方法的说明如表2-3和表2-4所示。

表2-3 EditText组件常用属性

续表

表2-4 EditText组件常用方法

2.1.6 Button组件

在Android中,Button是一种按钮组件,用户能够在该组件上点击,并引发相应的事件处理函数,或为Button组件设置View.OnClickListener监听器,并在监听器的实现代码中开发按钮按下事件的处理代码。

在Android中,可以通过两种方法向屏幕中添加Button组件,一种是通过在XML布局文件中使用<Button>标记添加,另一种是在Java文件中,通过new关键字创建出来。推荐采用第一种方法。

1.在XML文件中添加Button的基本语法

格式如下:

<Button

    属性列表

/>

2.Button组件常用属性和方法

Button组件常用属性和方法的说明如表2-5和表2-6所示。

表2-5 Button组件常用属性

表2-6 Button组件常用方法

下面通过【例2-2】来说明Button属性可在XML文件中直接设置,也可在Java文件中动态设置。

【例2-2】在Android Studio中新建一个Android项目,实现在屏幕上创建一个注册按钮和一个登录按钮,要求注册按钮是通过XML布局文件进行属性设置,而登录按钮则是通过Java代码进行动态设置。

第一种方法,通过XML布局文件进行属性设置。

启动Android Studio,新建一个Android项目,修改res/layout目录下的activity_main.xml布局文件,将默认添加的相对布局(RelativeLayout)修改成线性布局(LinearLayout),并设置线性布局中的 android:orientation="vertical",即垂直方向对齐,并将默认添加的 TextView组件删除。添加Button组件,设置Button组件的文本属性为“这是注册按钮,请单击。”文字。另外,再添加Button组件,此Button组件中设置了ID属性。其他属性将通过Java代码进行动态设置。程序清单的代码如下:

<?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="com.zzhn.zheng.mytest.MainActivity">

   <Button

     android:layout_width="wrap_content"

     android:layout_height="wrap_content"

     android:textColor="#0000FF"

     android:text="这是注册按钮,请单击。"

     android:id="@+id/zhuce"

   />

   <Button

     android:layout_width="wrap_content"

     android:layout_height="wrap_content"

     android:id="@+id/denglu"

   />

</LinearLayout>

第二种方法,通过Java代码进行动态设置。

修改MainActivity.java程序,在onCreate方法中完成Button的属性设置,程序代码如下:

protected void onCreate(Bundle savedInstanceState) {

      super.onCreate(savedInstanceState);

      setContentView(R.layout.activity_main);

      //获取ID为denglu的Button组件

      Button btn1 = (Button)findViewById(R.id.denglu);

      //设置按钮上的文本

      btn1.setText("这是登录按钮,请单击");

      //设置按钮宽度

      btn1.setWidth(800);

      //设置按钮高度

      btn1.setHeight(123);

      //设置按钮文字颜色

      btn1.setTextColor(Color.WHITE);

      //设置按钮字体大小

      btn1.setTextSize(30);

      //设置按钮组件背景色

      btn1.setBackgroundColor(Color.BLUE);

}

运行效果如图2-3所示。

图2-3 Button设置效果图

3.Button组件的单击事件处理方法

第一种方法,首先在Activity组件的XML文件中设置Button组件的onClick属性,通过该属性指定当点击Button组件时,将引发相应事件处理的方法名,然后,在Java程序代码中编写onClick属性所指定的Button组件单击事件的方法。示例如下。

XML文件设计:

<Button

    android:layout_width="wrap_content"

    android:layout_height="wrap_content"

    android:textColor="#0000FF"

    android:text="这是注册按钮,请单击。"

    android:id="@+id/btn1"

    android:onClick="zhuce" />

Java代码设计:

public class MainActivity extends Activity {

    @Override

    protected void onCreate(Bundle savedInstanceState) {

      super.onCreate(savedInstanceState);

      setContentView(R.layout.activity_main);

    }

    //单击事件的处理方法

    public void zhuce(View view){

       ……  //单击事件的处理程序

    }

第二种方法,接口实现事件处理模型。

实现方法:首先在Activity中实现OnClickListener接口,获取Activity界面上Button组件(事件源),然后,绑定接口在Button按钮上,并编写onClick单击事件的处理方法。

示例代码如下:

public class MainActivity extends Activity implements OnClickListener {

    @Override

    protected void onCreate(Bundle savedInstanceState) {

       super.onCreate(savedInstanceState);

       setContentView(R.layout.activity_main);

       Button btn1 = (Button)findViewById(R.id.btn1);

       btn1.setOnClickListener(this);

    }

    //单击事件的处理方法

    public void onClick(View v) {

        switch(v.getId()){

        case R.id.btn1:

          …… //单击事件的处理程序

        }

    }

}

第三种方法,内部类事件处理模型。示例代码如下:

public class MainActivity extends Activity {

     @Override

     protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        //获取界面上Button组件

        Button btn1 = (Button)findViewById(R.id.btn1);

        //将事件监听器对象注册给Button组件

        btn1.setOnClickListener(new Clicklistener());

     }

     //实现事件监听类

     class Clicklistener implements OnClickListener {

         @Override

         public void onClick(View v) {

           switch (v.getId()) {

           case R.id.btn1:

             //单击事件的处理程序

             ……

             break;

            }

         }

      }

第四种方法,用匿名内部类事件处理模型。示例代码如下:

public class MainActivity extends Activity {

    @Override

    protected void onCreate(Bundle savedInstanceState) {

       super.onCreate(savedInstanceState);

       setContentView(R.layout.activity_main);

       Button btn1 = (Button)findViewById(R.id.btn1);

       btn1.setOnClickListener(new OnClickListener(){

       @Override

         public void onClick(View v) {

             //单击事件的处理程序

               ……

         }

       });

    }

   }

2.1.7 线性布局

线性布局是最常见的一种布局方式,在线性布局中,所有的子元素都按照垂直或水平的顺序在界面上排列,线性布局可以分为水平线性布局和垂直线性布局两种。

在Android中,可以使用XML布局文件定义线性布局管理器,也可以使用Java来创建,但推荐使用XML布局文件定义线性布局管理器。在XML布局文件中,定义线性布局管理器需要使用LinearLayout标记,其基本语法格式如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

   属性列表>

</LinearLayout>

线性布局中的几个重要属性介绍如下。

① android:orientation用来设置线性布局中各组件的排列方向,其可选值为horizontal和vertical,默认值为vertical。其中,vertical为垂直排列,horizontal为水平排列。

② android:padding表示在View的顶部、底部、左侧和右侧的填充像素,它也被称为内边距。它设置的是内容与View边缘的距离,它分为上(padding-top)、右(padding-right)、下(padding-bottom)、左(padding-left)和padding。

③ android:layout_margin 是组件的顶部、底部、左侧和右侧的空白区域,称为外边距。它设置的是组件与其父容器的距离,它分为上(margin-top)、右(margin-right)、下(margin-bottom)、左(margin-left)和margin。

④ android:gravity用来设置View本身的内容应该显示在View的什么位置,默认值是左侧。它也可以用来设置布局中的组件位置。

⑤ android:layout_width 用来设置组件的基本宽度,其可选值为 match_parent 和wrap_content 。

⑥ android:layout_height 用来设置组件的基本高度,其可选值为 match_parent 和wrap_content 。

⑦ android:id用来为当前组件指定一个ID属性。

⑧ android:background用来为该组件设置背景。

⑨ android:layout_gravity 是相对于包含该元素的父元素来说的,设置该元素在父元素的什么位置。比如 TextView:android:layout_gravity 表示 TextView 在界面上的位置, android:gravity表示TextView文本在TextView的什么位置,默认值是左侧。

⑩ android:layout_weight 用来控制各个组件在布局中的相对大小,线性布局会根据该组件的layout_weight值与其所处布局中所有组件的layout_weight值之和的比值为该组件分配占用的区域。在水平布局的LinearLayout中有两个Button,这两个Button的layout_weight属性值都为1,那么这两个按钮都会被拉伸到整个屏幕宽度的一半。如果layout_weight值为0,组件会按原大小显示,不会被拉伸;对于其余layout_weight属性值大于0的组件,系统将会减去layout_weight属性值为0的组件的宽度或者高度,再用剩余的宽度或高度按相应的比例来分配每一个组件显示的宽度或高度。

【例2-3】在Android Studio中新建一个Android项目,设计一个水平方向排列两个按钮和垂直方向排列两个按钮的线性布局。

启动Android Studio,新建一个Android项目,修改res/layout目录下的activity_main.xml布局文件,将默认添加的相对布局(RelativeLayout)修改成线性布局(LinearLayout),并设置线性布局中的 android:orientation="vertical",即垂直方向对齐,并将默认添加的 TextView组件删除。添加LinearLayout组件,在LinearLayout组件中添加Button组件,通过线性布局的嵌套实现。程序清单的代码如下:

<?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="com.zzhn.zheng.mytest.MainActivity">

  <LinearLayout

    android:layout_width="match_parent"

    android:layout_height="wrap_content"

    android:orientation="horizontal">

    <Button

      android:layout_width="wrap_content"

      android:layout_height="wrap_content"

      android:textColor="#0000FF"

      android:text="注册"

      android:id="@+id/zhuce"

      android:layout_weight="1"/>

    <Button

      android:layout_width="wrap_content"

      android:layout_height="wrap_content"

      android:text="登录"

      android:id="@+id/denglu"

      android:layout_weight="1"/>

  </LinearLayout>

    <Button

      android:layout_width="wrap_content"

      android:layout_height="wrap_content"

      android:textColor="#0000FF"

      android:text="注册"

      android:id="@+id/zhuce1" />

    <Button

      android:layout_width="wrap_content"

      android:layout_height="wrap_content"

      android:text="登录"

      android:id="@+id/denglu1" />

</LinearLayout>

运行效果如图2-4所示。

图2-4 线性布局示例效果图

2.1.8 strings.xml和colors.xml的运用

在Android项目的res/values文件夹中存放了一些资源文件的信息,用于读取文本资源,在该文件夹中有一些约定的文件名称,如arrays.xml(定义数组数据)、colors.xml(定义表示颜色的数据)、dimens.xml(定义尺度大小)、strings.xml(定义字符串)和 styles.xml(定义显示的样式文件)等,并且这些资源文件在Android项目开发中都有一定的作用。

1.strings.xml的运用

在Android项目开发中,Android建议将在屏幕上显示的文字定义在strings.xml中,然后,在布局文件或java文件中调用strings.xml资源文件中的信息,而不提倡在布局文件的text属性中直接写文字。

运用strings.xml文件的目的如下。

一是便于实现国际化,当需要国际化时,只需要再提供一个strings.xml文件,把里面的汉语信息都修改为对应的语言(如English),再运行程序时,Android操作系统会根据用户手机的语言环境和国家来自动选择相应的strings.xml文件,这时手机界面就会显示出外文。

二是为了减少应用项目的体积,降低数据的冗余。如果将文字定义在strings.xml文件中,每次使用到的地方只需要通过Resources类来引用文字就可,而不需要将文字重复写多次,以达到降低应用项目体积的目的。

strings.xml文件的格式:

<resources>

   <string name="app_name">My Application</string>

</resources>

在布局文件中引用strings.xml文件中字符的方法:

android:text="@string/app_name"

在Activity中引用strings.xml文件中字符的方法:

String appName=(String)this.getResources().getText(R.string.app_name);

Log.i("test", "appName="+appName);

或者:

String appName=(String)this.getResources().getString(R.string.app_name);

Log.i("test", "appName="+appName);

2.colors.xml的运用

colors.xml的作用是定义颜色,文件格式如下:

<?xml version="1.0" encoding="utf-8"?>

<resources>

   <color name="colorPrimary">#3F51B5</color>

   <color name="colorPrimaryDark">#303F9F</color>

   <color name="colorAccent">#FF4081</color>

</resources>

在布局文件中引用colors.xml文件中颜色的方法如下:

android:text Color="@color/color Primary"

2.1.9 样式和主题

Android中的样式用于为界面元素定义显示风格,它是一个包含一个或者多个View组件属性的集合。例如,通过样式定义View组件的字体颜色和大小。

在Android项目的res/values/styles.xml文件中添加以下内容:

<?xml version="1.0" encoding="utf-8"?>

<resources>

  <style name=“itcast”> <!-- 为样式定义一个全局唯一的名字 -->

   <!-- name属性的值为使用了该样式的View组件的属性的值 -->

   <item name="android:textSize">18px</item>

   <item name="android:textColor">#0000CC</item>

  </style>

</resources>

在layout文件中可以像下面这样使用上面的Android样式:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" ....>

   <TextView

    style="@style/itcast"

    ……

    />

</LinearLayout>

样式(Style)和主题(Theme)是一个包含一种或者多种格式化属性的集合,并且样式和主题都是资源,存放在res/values 文件夹下即可,Android提供了很多这样的默认资源,可以供用户来使用。同时,用户也可以自定义样式和主题,只需要在res/values/这个路径里面新建一个 XML 文件,而且它的根节点必须是<resources>。对每一个样式和主题,给<style>增加一个全局唯一的名字,也可以选择增加一个parent父类属性,那么样式和主题就会继承这个父类的属性。

样式和主题定义格式相同,它们的区别为:样式是针对View,如TextView、EditText等;而主题必须针对整个 Activity 或者整个 Application,必须在 AndroidManifest.xml 中的<application>或<activity>中定义。

主题需要在 AndroidManifest.xml 中注册。如果想整个程序都使用这个主题,可以写为<application android:theme="@style/AppTheme">,如果只需要在某个Activity中使用主题,只要在 Activity 标签中写入 android:theme="@style/AppTheme"就可以了。Android 有很多好的默认主题,如<activity android:theme="@android:style/Theme.Dialog">,该主题将使整个Activity变成一个对话框形式。

项目实施

1.项目分析

运用 Android 线性布局的设计方法,设计物联网环境状态值设置的 UI 界面,物联网环境状态值设置效果如图2-5所示。

图2-5 物联网环境状态值设置效果

环境状态值设置UI界面设计特点:

① 有5行垂直方向排列的组件。

② 在每一行中又有水平方向排列的组件。

分析结果:

① 整体是由5行垂直方向的线性布局组成的。

② 其中每行又嵌套了水平方向的线性布局。

③ UI界面中有5个TextView组件、5个EditText组件和3个Button组件。

④ EditText 组件要求输入的数据是数字格式。

2.项目实现

(1)新建Android项目。

启动 Android Studio,在 Android Studio 起始页选择【Start a new Android Studio project】,或在Android Studio主页选择菜单栏上【File】→【New】→【New Project】,新建 Android 工程。在 New Project 页面上输入应用程序的名称(MyTest)、公司域名(com.zzhn.zheng)和存储路径,单击【Next】按钮。然后,选择工程的类型以及支持的最低版本,单击【Next】按钮。之后选择是否创建Activity以及创建Activity的类型,选择【Empty Activity】,单击【Finish】按钮。

(2)创建strings.xml文件。

在 res/values 文件夹中,将物联网环境状态值设置的 UI 界面中所有组件所需要显示的文字添加到strings.xml文件中。

操作方法:展开【res】→【values】文件夹,双击【strings.xml】文件,打开右侧strings.xml文件编辑窗口,如图2-6所示。

图2-6 strings.xml文件编辑窗口

在strings.xml文件编辑窗口中输入strings.xml文件代码,如下:

<resources>

   <string name="app_name">MyText</string>

   <string name="tv1">温度范围</string>

   <string name="tv2">湿度范围</string>

   <string name="tv3">光照强度</string>

   <string name="btn1">保持</string>

   <string name="btn2">重置</string>

   <string name="btn3">取消</string>

   <string name="title">设置</string>

   <string name="initial">起始值</string>

   <string name="stop">终止值</string>

   <string name="tv4">"至</string>

</resources>

说明

Android Studio可自动保存文件,不需要开发人员按<Ctrl>+<S>组合键保存文件。

(3)设计布局文件。

在res/layout文件夹中,打开布局的activity_main.xml文件,使用线性布局,添加界面组件,设置布局和组件属性调整界面。

操作方法:展开【res】→【layout】文件夹,双击【activity_main.xml】文件,打开右侧布局文件text编辑窗口,在编辑窗口中输入activity_main.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:id="@+id/activity_main"

  android:layout_width="match_parent"

  android:layout_height="match_parent"

  android:orientation="vertical"

  tools:context="com.zzhn.zheng.mytest.MainActivity">

  <TextView

    android:layout_width="match_parent"

    android:layout_height="wrap_content"

    and android:gravity="center"

    android:textSize="30sp"

    android:background="@color/colorAccent"

    android:text="@string/title" />

  <LinearLayout

    android:layout_width="match_parent"

    android:layout_height="wrap_content"

    android:layout_margin="20dp"

    android:orientation="horizontal">

    <TextView

      android:layout_width="wrap_content"

      android:layout_height="wrap_content"

      android:textSize="20sp"

      android:padding="10dp"

      android:text="@string/tv1"/>

    <EditText

      android:layout_width="wrap_content"

      android:layout_height="wrap_content"

      android:padding="10dp"

      android:inputType="number"

      android:layout_weight="1"

      android:hint="@string/initial"

      android:id="@+id/iedt1"/>

    <TextView

      android:layout_width="wrap_content"

      android:layout_height="wrap_content"

      android:textSize="20sp"

      android:padding="10dp"

      android:text="@string/tv4"/>

    <EditText

      android:layout_width="wrap_content"

      android:layout_height="wrap_content"

      android:padding="10dp"

      android:inputType="number"

      android:layout_weight="1"

      android:hint="@string/stop"

      android:id="@+id/sedt1"/>

  </LinearLayout>

  <LinearLayout

    android:layout_width="match_parent"

    android:layout_height="wrap_content"

    android:layout_margin="20dp"

    android:orientation="horizontal">

    <TextView

      android:layout_width="wrap_content"

      android:layout_height="wrap_content"

      android:textSize="20sp"

      android:padding="10dp"

      android:text="@string/tv2"/>

    <EditText

      android:layout_width="wrap_content"

      android:layout_height="wrap_content"

      android:padding="10dp"

      android:inputType="number"

      android:layout_weight="1"

      android:hint="@string/initial"

      android:id="@+id/iedt2"/>

    <TextView

      android:layout_width="wrap_content"

      android:layout_height="wrap_content"

      android:textSize="20sp"

      android:padding="10dp"

      android:text="@string/tv4"/>

    <EditText

      android:layout_width="wrap_content"

      android:layout_height="wrap_content"

      android:padding="10dp"

      android:inputType="number"

      android:layout_weight="1"

      android:hint="@string/stop"

      android:id="@+id/sedt2"/>

  </LinearLayout>

  <LinearLayout

    android:layout_width="match_parent"

    android:layout_height="wrap_content"

    android:layout_margin="20dp"

    android:orientation="horizontal">

    <TextView

      android:layout_ width="wrap_content"

      android:layout_height="wrap_content"

      android:textSize="20sp"

      android:padding="10dp"

      android:text="@string/tv3"/>

    <EditText

      android:layout_width="wrap_content"

      android:layout_height="wrap_content"

      android:padding="10dp"

      android:inputType="number"

      android:layout_weight="1"

      android:id="@+id/edt3" />

  </LinearLayout>

  <LinearLayout

    android:layout_width="match_parent"

    android:layout_height="wrap_content"

    android:layout_margin="20dp"

    android:orientation="horizontal">

    <Button

      android:layout_width="wrap_content"

      android:layout_height="wrap_content"

      android:text="@string/btn1"

      android:layout_weight="1"

      android:padding="10dp

      android:id="@+id/btn1"/>

    <Button

      android:layout_width="wrap_content"

      android:layout_height="wrap_content"

      android:text="@string/btn2"

      android:layout_weight="1"

      android:padding="10dp"

      android:id="@+id/btn2"/>

    <Button

      android:layout_width="wrap_content"

      android:layout_height="wrap_content"

      android:text="@string/btn3"

      android:layout_weight="1"

      android:padding="10dp"

      android:id="@+id/btn3"/>

  </LinearLayout>

</LinearLayout>

(4)调试运行。

① 单击工具栏上的 AVD Manager图标,打开虚拟设备对话框,在虚拟设备对话框中单击启动虚拟设备的命令按钮,打开Android Studio模拟器。

② 单击工具栏上的“三角形”运行按钮,运行本项目。

说明

每次修改代码,都需要重新运行才能观察到新效果。

项目总结

通过本项目的学习,读者应学会进行UI界面设计的基本思路。

① 首先分析UI界面由哪些组件组成,在本项目中运用的是TextView、EditText和Button组件,了解这些组件的常用属性,特别是EditText组件中inputType属性的作用。

② 根据 UI 界面中组件的排列方式,确定采用线性布局,掌握线性布局中 orientation、layout_weight、padding、layout_margin属性的运用。

另外,重点了解事件处理的基本概念,特别是 Button 组件事件处理的4种方法和strings.xml、colors.xml、样式和主题的运用。

项目训练——用户管理系统的用户登录界面

用线性布局设计一个用户管理系统的用户登录界面,要求如下。

① UI界面上显示的标题为“用户管理系统”;

② 输入栏为用户名和密码,用户名输入为普通字符,长度小于12,密码输入是密码长度小于7,并以小点“.”显示;

③ UI界面上要显示“登录”和“注册”两个按钮;

④ 要求设置UI界面的背景图片。

练习题

2-1-1 运用样式简化物联网环境状态值设置的UI界面activity_main.xml文件设计。

2-1-2 Android平台的事件处理机制有哪些?基于监听的事件处理的步骤是什么?

2-1-3 Android的UI界面布局有哪些?线性布局的特点是什么?

2-1-4 在UI界面设计中为什么要使用strings.xml、colors.xml、样式和主题?它们各自的作用是什么?