首页 » Android程序设计:第2版 » Android程序设计:第2版全文在线阅读

《Android程序设计:第2版》组装图形界面

关灯直达底部

Android UI框架提供了一套完整的绘图工具来构建UI,以及丰富的基于这些工具的预构建的组件组合。正如第8章将介绍的,Android UI框架的图形工具为应用提供了很多支持,以便应用可以方便地创建自己的控制按钮或渲染出特殊的视图。另一方面,很多应用可能只使用工具箱里的视图就可以良好工作。实际上,类MapActivity和类MyLocationOverlay可以支持非常复杂的应用的创建,而不需要执行任何自定义渲染。

我们之前已经使用了术语部件,但没有显式定义它。屏幕是由组件树渲染的。在Android UI框架中,这些组件都是android.view.View的子类。在视图树中,叶子节点或接近叶子节点的节点执行了大部分的实际渲染工作,在应用UI中,这些节点通常被称为widget。

内部节点,有时称为容器视图(container views),是特殊的组件,可以包含其他子组件。在Android UI框架中,容器视图是android.view.ViewGroup的子类,它当然也是View的子类。它们通常很少执行渲染工作。相反,它们主要负责安排其子节点在屏幕上的视图,并且当视图形状、方向等改变时,还保持这些节点的位置排列。这些工作实际上很复杂。

要创建复杂的显示,还需要对应用中要使用的视图的容器树进行组装。例6-1显示了一个包含三个层次的视图树的应用。一个垂直的线性布局中包含了两个水平的线性布局。每个水平布局又分别包含了两个部件。

例6-1:一棵复杂的视图树


package com.oreilly.android.intro;import android.app.Activity;import android.graphics.Color;import android.os.Bundle;import android.view.Gravity;import android.view.ViewGroup;import android.widget.Button;import android.widget.EditText;import android.widget.LinearLayout;public class AndroidDemo extends Activity {    private LinearLayout root;    @Override    public void onCreate(Bundle state) {        super.onCreate(state);        LinearLayout.LayoutParams containerParams            = new LinearLayout.LayoutParams(                ViewGroup.LayoutParams.FILL_PARENT,                ViewGroup.LayoutParams.WRAP_CONTENT,                0.0F);        LinearLayout.LayoutParams widgetParams            = new LinearLayout.LayoutParams(                ViewGroup.LayoutParams.FILL_PARENT,                ViewGroup.LayoutParams.FILL_PARENT,                1.0F);        root = new LinearLayout(this);        root.setOrientation(LinearLayout.VERTICAL);        root.setBackgroundColor(Color.LTGRAY);        root.setLayoutParams(containerParams);        LinearLayout ll = new LinearLayout(this);        ll.setOrientation(LinearLayout.HORIZONTAL);        ll.setBackgroundColor(Color.GRAY);        ll.setLayoutParams(containerParams);        root.addView(ll);        EditText tb = new EditText(this);        tb.setText(R.string.defaultLeftText);        tb.setFocusable(false);        tb.setLayoutParams(widgetParams);        ll.addView(tb);        tb = new EditText(this);        tb.setText(R.string.defaultRightText);        tb.setFocusable(false);        tb.setLayoutParams(widgetParams);        ll.addView(tb);        ll = new LinearLayout(this);        ll.setOrientation(LinearLayout.HORIZONTAL);        ll.setBackgroundColor(Color.DKGRAY);        ll.setLayoutParams(containerParams);        root.addView(ll);        Button b = new Button(this);        b.setText(R.string.labelRed);        b.setTextColor(Color.RED);        b.setLayoutParams(widgetParams);        ll.addView(b);        b = new Button(this);        b.setText(R.string.labelGreen);        b.setTextColor(Color.GREEN);        b.setLayoutParams(widgetParams);        ll.addView(b);        setContentView(root);    }}  

注意,该代码保留了视图树的根节点的引用,在后面会用到它。

这个例子使用了三个LinearLayout视图。LinearLayout视图,正如其名,表示在视图中根据定位属性,以行形式或列形式显示子节点。子视图的显示方式和其插入到LinearLayout的顺序一致(和其创建的顺序无关),其显示方式对于西方读者很熟悉:从左到右、至上而下。例如,标签为Green的按钮在该布局的右下角,因为它是第二个插入到水平LinearLayout视图中的,而这个水平线性视图又是第二个插入到根节点即垂直的LinearLayout中的。

图6-2显示了从用户角度看的可能结果。树中的7个视图是结构化的,如图6-3所示。

图6-2:用户看到的面板

Android框架支持很方便地把数据源和代码进行分离,这一点对于构建视图布局是非常有用的。前一个例子可以被例6-2所示的简单得多的代码以及例6-3所示的视图布局XML定义所替换。

图6-3:视图中的层次

例6-2:使用布局资源的复杂视图


package com.oreilly.android.intro;import android.app.Activity;import android.os.Bundle;/** * Android UI demo program */public class AndroidDemo extends Activity {    private LinearLayout root;    @Override public void onCreate(Bundle state) {        super.onCreate(state);        setContentView(R.layout.main);        root = (LinearLayout) findViewById(R.id.root);    }    }  

例6-3:一个复杂视图布局资源的XML定义


<LinearLayout xmlns:android=/"http://schemas.android.com/apk/res/android/"    android:id=/"@+id/root/"    android:orientation=/"vertical/"    android:background=/"@drawable/lt_gray/"    android:layout_    android:layout_><LinearLayout    android:orientation=/"horizontal/"    android:background=/"@drawable/gray/"    android:layout_    android:layout_><EditText      android:id=/"@+id/text1/"      android:text=/"@string/defaultLeftText/"      android:focusable=/"false/"      android:layout_      android:layout_      android:layout_weight=/"1/"/><EditText      android:id=/"@+id/text2/"      android:text=/"@string/defaultRightText/"      android:focusable=/"false/"      android:layout_      android:layout_      android:layout_weight=/"1/"/></LinearLayout><LinearLayout    android:orientation=/"horizontal/"    android:background=/"@drawable/dk_gray/"    android:layout_    android:layout_><Button      android:id=/"@+id/button1/"      android:text=/"@string/labelRed/"      android:textColor=/"@drawable/red/"      android:layout_      android:layout_      android:layout_weight=/"1/"/><Button      android:id=/"@+id/button2/"      android:text=/"@string/labelGreen/"      android:textColor=/"@drawable/green/"      android:layout_      android:layout_      android:layout_weight=/"1/"/></LinearLayout></LinearLayout>  

该版本的代码和第一个版本的类似,也保留了到视图树的根节点的引用。它保留根节点引用的方式是在XML布局(在这个例子中,即根节点LinearLayout)中给widget打上一个标签android:id,然后使用Activity类的findViewById方法来获取引用。

使用资源来定义视图树的布局结构是一个良好的思路。这种方式使我们能够从代码中分离出视图的可视化布局。修补屏幕布局就不再需要重新编译了。然而,更重要的是,你可以使用一些工具来构建自己的UI,采用这种思路你就可以使用可视化UI编辑器编写屏幕元素。

注意:在Google I/O 2011会议上,Android工具团队介绍了一种新的编辑器,其功能很令人兴奋。它甚至可以预览动画和开发人员创建的视图。大部分开发人员在对视图进行布局时不需要查看XML代码,那些内嵌的代码被查看的可能就更加渺茫了。