【翻译】使用Flash,Flex Builder和AS3创建自适应的用户界面

原文地址 http://www.adobe.com/devnet/flash/articles/liquid_gui.html
原作 James O’Reilly (http://jamesor.com)
翻译 Tangbin (http://tangbin.cn)
翻译完成时间 2007年2月27日


一、概述
1.1 关于作者
James O’Reilly,Adobe认证专家,SynergyMedia公司(一家位于纽约的Flash咨询和培训公司)的首席技术官(CTO)。他的Blog(jamesor.com)中收集了许多他本人关于Flash和Flex开发的经验和思考。

随着用户体验需求的提高,越来越多的开发者在思考和探索如何在web中实现如同桌面应用那样丰富体验的方法。而本文正是关于这方面的内容,它将要告诉你如何创建动态的、自动根据屏幕范围调整显示大小的图形用户界面。

众所周知,液体(liquid)是一个分子的集合体,这些分子互相自由的运动并且紧密结合不分离。而在web开发中,“自适应页面”就如同“liquid”一样,自适应页面中的内容将自动而独立的调整大小来适应不同的web浏览器窗口的或者其他给定的宽度,而让整个页面看起来就想专门为这个大小而设计的一样。这和“定宽页面”形成很鲜明的对比。所谓“定宽页面”,是指按照特定的宽度来设计的页面,多出来的地方则直接用空白或其他背景填充。如今,自适应页面在很多地方已经渐渐地被定宽页面所代替。

不管自适应页面的前途如何,很多用户依旧希望自己所使用的桌面应用具有一个能够自适应的界面,这让能使应用程序界面看起来更人性化。当你打开一个应用程序并改变它的大小,你希望看到所有的图形化界面的内容能自动排列来适应新的大小,而不是出现空白或显示不完整。

为了表述得更清楚,图1显示了两个Gaim(一种及时通讯工具)的消息窗口的截图。你可以看到,无论如何改变Gaim的大小,界面都会自动的适应窗口的大小。用户已经渐渐了习惯了桌面应用中的自适应大小功能。而目前,越来越多的桌面应用已经有了基于web的RIA(rich internet application 富网络应用)实现,因此,相信大部分用户都希望RIA能看起来和用起来如同桌面应用一样。
fig01.gif
图1,两种不同大小下的Gaim及时消息窗口
1.2 看看我们要做的东西
在此教程中,我将通过Flash中Stage对象的一些特性,来创建一个自适应的应用界面。我将做一个简单的、传统的图片库作为列子,这个例子可以放在网页上以供浏览查看。当然,将这个例子中将在一个新的浏览器窗口中探出来,可以令其看起来更象是一个桌面应用而不是网页的一部分。

这个图片库将包含三个部分:头部,主体和底部。头部部分将包含应用的名称和一些按钮,包括让用户改变背景的按钮,以及在“原始大小”和“最合适大小”之间切换的按钮。主体部分允许用户查看所选择的图片。底部部分包含一个有多张图片的队列提供给用户选择要查看的图片。总之,我们要做的东西,你肯定在曾经在哪儿看见过的,或者你也许已经做过类似的东西。

fig02.jpg
图2,在改大小的窗口中的非拉伸界面

在图2中,图片库被设置成具有一个不可以拉的伸界面,在这个情况下,无论怎么拉伸窗口,应用程序的界面看起来都没有错误。如果不使用非拉伸界面而让应用程序跟随显示窗口直接拉伸,在浏览器窗口被拉伸到一个和原始SWF文件的长宽比不一样的大小的时候,应用程序的界面看起来就是扭曲的,如图3所示。
fig03.jpg
图3,应用程序界面的大小和浏览器窗口一样的例子

这些情况会让用户感觉很不友好。如果应用程序使用如图2的不可拉伸界面,用户将无法把窗口拉得更大一些。假如用户的显示器有1600 x 1200或者更高的分辨率,而只能看到如此小的一个图片,是很令人郁闷的。同样,如果一个应用程序的界面一拉伸就变得扭曲和比例失衡,也同样难以给用户留下好的印象。

看看图4,我们想要做的就是这样的。如同桌面应用一样,使用浏览器打开的应用程序可以自动的根据浏览器的大小而从新调整大小。用户会很乐意的使用这样的应用程序,并将其拉伸到最适合自己使用的大小。用户甚至可能忘记自己使用的是一个从浏览器中打开的应用程序。
fig04.jpg
图4,应用程序自适应浏览器窗口

1.3 读者需求
如果需要测试本教程中的例子,你需要下面的软件和文件:

Flash Professional 9 ActionScript 3.0 Preview
http://labs.adobe.com/technologies/flash9as3preview/

Flex Builder 2
http://www.adobe.com/go/devcenter_flex_try

例子文件
liquid_gui_source.zip (ZIP, 60 KB)
http://download.macromedia.com/pub/developer/liquid_gui_source.zip

知识准备:
需要了解AS3和熟悉AS3语法

二、准备开始
用Flash创建自适应的GUI有4个基本的方面。在本文中,我将创建一个拥有自适应界面的例子程序来详细的介绍这4个基本方面的内容:

1,确定应用程序的界面划分,确定如何调整其大小;
2,将HTML页面设置为100%显示内容;
3,将Flash影片设置为不可以自己改变大小;
4,添加内容让应用程序可以自己什么时候需要改变大小以及如何改变大小。

2.1 确定应用程序的界面划分
我要做的图片库有三个很区分很明确的划分。三个部分的调整大小的方式也都各自不相同。头部和底部只在横向上有大小的调整,而主体部分在横向和纵向上都将会有调整。从布局上来说,只有底部是一直锁定在窗口在最下面,而头部和主体部分都有固定的x坐标和y坐标。

头部可以分成3个小部分:标题,一组按钮和背景图片。背景图片将通过改变宽度来适应窗口的大小,而标题和按钮部分,在改变大小的时候不会受到任何影响。

主体部分可以分成两个部分:一个空的影片剪辑(MovieClip,以下简称MC)用来加载和显示图片,和一个背景填充。背景填充部分需要自动的修改长和宽来适应窗口。图片容器MC需要通过一些计算将图片居中的显示出来,并根据用户的设置,将图片显示为原始大小或者最合适的大小。

最后,底部也是由两部分组成:一组缩略图和背景填充。背景填充通过改变宽度来适应窗口的宽度,而缩略图组是不受大小调整的影响的。实际上,很多正式的软件中的缩略图组中,可能有非常多的缩略图,而需要一些按钮或者滚动条来帮助用户可以滚动浏览,不过这个和我们今天要讲的内容没有大的关系,这里就不考虑照样的情况了

2.2 在HTML页面中将应用程序的显示设置为100%
自适应的界面中很重要的一点,使需要应用程序能够100%的填满浏览器窗口的高度和宽度。

为了让应用程序完全填满浏览器窗口,窗口页面的margin属性必须设置为0,margin的默认值是10,如果没有将其设置为0,应用程序的周边将有10象素的空白。在镶嵌应用程序的页面中加入下面的代码:

要让SWF填充整个浏览器窗口的方法非常简单,只用在SWF的发布设置中稍微修改一下即可。

在Flash9预览版中打开FLA文件,选择“文件 ->发布设置”。确保HTML(.html)的复选框是选中的。然后点击HTML标签。在尺度下拉菜单重选择“百分比”,然后输入宽度和高度都为100。这样,SWF将在浏览器窗口中满屏填充。

下面的两个发布属性可以通过修改Object和embed标签的属性来修改,不过在发布设置面板中的HTML标签中,也可以设置:

1,从缩放弹出菜单中选择“不缩放”;
2,在影片对齐选项中,水平方向选择左,垂直方向上选择顶部。

一般来说,我更喜在影片中使用AS来设定这两个参数,这样在Flash编辑环境下的测试中,就可以让播放器使用这两个属性来达到最需要的效果。

2.3 将Flash影片设置为不要自动改变内容的大小
要使用AS代码来设置上面说的到两个属性,可以通过设置Stage对象的两个属性来实现:

Stage.scaleMode = “noScale”;
Stage.align = “TL”;

scaleMode属性表示不自动拉伸flash影片,而align属性设置为TL表示影片以左上角为对齐点(top and left)。

2.4 如何让应用程序知道什么时候需要调整大小
使用AS代码来禁止SWF文件自动调整大小的目的是要所有的大小按照我们自己的需要来调整。

本文下面的部分将具体的讲述怎么来创建这个图片库,并将分成四个版本来制作。每个版本将比其前一个版本更复杂和完善。

版本1,创建一个基本的框架来监听窗口的调整大小事件;
版本2,创建继承MovieClip类的用户界面,处理调整大小时间并将其放在一个图形界面容器中;
版本3,通过实现自定义的IResizable接口来实现多态的调整大小;
版本4,图片库的其他一些特性和实现方式。

三、打基础
在这一部分,我们将通过两个方式来编写这个应用程序。第一种方法是通过Flash9预览版开发,可以做到尽量的简单。随后,将通过AS3编程,在Flash9预览版和Flex Builder2里面实现更复杂的功能。我将用Flash来制作资源库,用Flex builder来编写代码和编译SWF文件。

版本1

打开Flash9预览版,在舞台上创建三个MC,分别用来包含三个部分:顶部,主体和底部。将三个MC放在不同的层里面,顶部在最上,底部第二层,主体在最下。将主体部分放在最下面的原因是,如果加载的图片大小超过了主体部分能显示的范围,将会被顶部和底部遮住。分别将MC的实例名称命名为“header_mc”“body_mc”“footer_mc”。

在时间轴上,加入下面的代码:

import flash.display.StageScaleMode;
import flash.display.StageAlign;
import flash.events.Event;

stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
stage.addEventListener(Event.RESIZE, resizeHandler);

// 初始化调整大小事件
resizeHandler (null);

function resizeHandler (event:Event):void

{
var sw:Number = stage.stageWidth;
var sh:Number = stage.stageHeight;
header_mc.width = body_mc.width = footer_mc.width = sw;
body_mc.height = sh-header_mc.height-footer_mc.height;
footer_mc.y = sh-footer_mc.height;
}

上面的代码实现了下面几个内容:首先,通过代码将SWF设置成不可以自动随浏览器窗口改变大小。其次,将作坐标点的原点设置为左上角。然后,创建了一个监听器,当舞台的大小发生改变的时候触发事件。在用户改变窗口大小的时候,Resize事件将会被触发多次。

版本2

现在,我们已经有了一个最简单的版本。下面我们将使用Flex Builder2来将其中引入更多的和更复杂的功能。除了是用flex builder2的actionscript工程构造以外,版本2和版本1没有其他的区别。

在Flex Builder中,选择File -> New -> ActionScript Project。在对话框中,输入工程名称LiquidGUI_v2并选择使用默认的路径。Flex Builder将自动的创建HTML模板用来测试,因此你不需要担心和考虑HTML设置的问题。

然后,将版本1中的FLA文件重命名蔚library.fla,并将其放置于LiquidGUI_v2工程路径下的assets文件夹内。在Flash中打开此FLA文件,并将舞台上所有的原件和你创建出来的层删除掉。在库中,将3个部分的MC的连接类名称分别改为HeaderBG,BodyBG和FooterBG。在Flash9预览版中,将不再使用连接标识符(linkage identifier),而是使用了连接类(linkage class)。

现在,这个FLA文件的库中应该有3个MC,而舞台上没有任何东西。使用Flash9预览版的ActionScript3.0将此FLA文件发布为SWF文件,并将此SWF文件保存中assets文件夹内。
fig05.jpg
图5,Flash9的发布设置中AS3编译设置

应用程序的主类文件已经被创建名为LiquidGUI_v2.as。此类将继承Sprite类。在Flex Builder中打开此文件并用下面的代码代替:

package
{
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
//
public class LiquidGUI_v2 extends Sprite
{
public static var ow:Number = 550; // 初始舞台高度
public static var oh:Number = 400; // 初始舞台宽度
public static var hh:Number = 54; // 顶部高度
public static var fh:Number = 75; // 底部高度
public static var hfh:Number = 129; // 顶部和底部的高度
// 顶部代码
[Embed(source="assets/library.swf", symbol="HeaderBG")]
private var HeaderBG:Class;
private var _header:Sprite;
// 主体部分代码
[Embed(source="assets/library.swf", symbol="BodyBG")]
private var BodyBG:Class;
private var _body:Sprite;
// 底部代码
[Embed(source="assets/library.swf", symbol="FooterBG")]
private var FooterBG:Class;
private var _footer:Sprite;
/**
* 构造器
*/
public function LiquidGUI_v2 ()
{
// 让播放器不要自动拉伸
stage.scaleMode = StageScaleMode.NO_SCALE;
// 让播放器将左上角作为舞台的坐标原点
stage.align = StageAlign.TOP_LEFT;
// 设置改变大小事件的监听器
stage.addEventListener(Event.RESIZE, onResize);
// 创建主体部分并将其添加到显示列表中
_body = new BodyBG ();
addChild (_body);
// 创建底部并将其添加到显示列表中
_footer = new FooterBG ();
addChild (_footer);
// 创建顶部并将其添加到显示列表中
_header = new HeaderBG ();
addChild (_header);
// 设置位置
_body.y = _header.height;
// 初始化位置设置
onResize (null);
}
/**
* onResize
* 大小改变的监听器的事件处理器。
* @param event
*/
public function onResize (event:Event):void
{
// 获取新的舞台大小
var sw:Number = stage.stageWidth;
var sh:Number = stage.stageHeight;
// 将各部分的大小调整到新的值
_header.width = _body.width = _footer.width = sw;
_body.height = sh-hfh;
_footer.y = sh-fh;
}
}
}

大部分的代码和版本1中的代码是差不多的。LiguidGUI_v2.as类既是主类,也是应用程序的入口。

在这个类中,我定义了一些全局变量,这些变量在应用程序的整个生存周期中都一直有效并不会被改变。因此我将其定义成静态变量以便调用。

接下来的代码是将一个外部的SWF文件作为扩展的库文件直接导入到当前的应用程序中来:

[Embed(source="assets/library.swf", symbol="FooterBG")]

上 面的代码申明了在当前的应用程序中使用什么符号来引用需要嵌入的SWF文件。在申明了嵌入符号后,需要将此符号名称定义成一个类,如下:

private var FooterBG:Class;

在此应用程序中,一旦FooterBG被定义成了一个类,你可以使用new关键字来实例化这个类。在我的例子中不打算使用时间轴,因此我将这里的对象类型定义为Sprite,如下:

private var _footer:Sprite;
_footer = new FooterBG ();

在创建了FooterBG类的实例后,必须将其加入到显示队列中才能显示出来。因此这里需要用到Sprite的addChild()方法:

addChild (_footer);

最终,实现一个onResize方法来作为事件对象的处理器。

四、快完成了
前两个版本都是基本内容的实现。现在需要创建调整大小事件的处理器。

版本3

在版本3中,我将要创建一个名为LiquidGUI_v3的新工程,不过你也可以直接在版本2的项目上继续做。在本版3中,我将减少主类中的功能,因为主类实际上并不需要知道如何去调整每个部分的大小。主类的功能是计算和设置每个部分的位置并将告诉每个部分其应该的大小,然后由每个部分自己来调整显示大小。因此,主类中在调整大小时处理的,仅仅是_footer的y坐标。而其他的部分,只要设置好了就不用再修改。

首先,创建一些文件夹来放置需要编写的类文件。这些文件夹的名字同类的包定义路径要吻合。关于AS3类的包定义,请查看其他相关手册。

我这里使用的包名称为com.jor。在com目录内创建一个名称为jor的目录,是“James O’Reilly”的简称。然后需要创建了一些不同的目录来放置不同的类。在这里,我创建了两个不同的目录:“controls”和“examples”。在examples目录中,我创建了一个目录名称为“liquidgui”,然后在其中创建了一个目录名称为“ui”。目录结构如下:

LiquidGUI_v3/
LiquidGUI_v3/assets/
LiquidGUI_v3/bin/
LiquidGUI_v3/com/jor/examples/liquidgui/ui
LiquidGUI_v3/bin/html-template/

然后,为三个不同的部分创建三个继承Sprite的类:

LiquidGUI_v3/com/jor/examples/liquidgui/ui/HeaderUI.as
LiquidGUI_v3/com/jor/examples/liquidgui/ui/BodyUI.as
LiquidGUI_v3/com/jor/examples/liquidgui/ui/FooterUI.as

每一个部分用一个独立的类来实现,而每个类需要在内部实现自己的调整大小的方法,因此需要在每个类中定义一个名称为setSize()方来,用来调用以调整大小。现在,我创建一个接口,让每一个需要调整大小的类都来实现这个接口。我将这个接口命名为IResizable.as,然后写入下面的代码:

package com.jor.examples.liquidgui {
public interface IResizable {
function setSize (w:Number, h:Number):void;
}
}

创建接口比创建类要容易得多,因为接口中是没有代码的。关于AS3中接口的更多介绍,请查看相关手册。

每个部分的类中都需要实现这个接口。打开HeaderUI.as并加入下面的代码:

package com.jor.examples.liquidgui.ui
{
import com.jor.examples.liquidgui.IResizable;
import flash.display.Sprite;
public class HeaderUI extends Sprite implements IResizable
{
public static var _instance:HeaderUI;
private var _parent:Sprite;
// 背景资源
[Embed(source="/assets/library.swf", symbol="HeaderBG")]
private var HeaderBG:Class;
public var bg:Sprite;
// 顶部资源
[Embed(source="/assets/library.swf", symbol="HeaderTitle")]
private var HeaderTitle:Class;
public var title:Sprite;
public function HeaderUI (p:Sprite)
{
_parent = p;
// 创建并添加背景到显示队列
bg = new HeaderBG ();
addChild (bg);
// 创建并添加顶部到显示队列
title = new HeaderTitle ();
addChild (title);
title.x = 23;
}
public static function getInstance (p:Sprite):HeaderUI
{
if (_instance == null)
_instance = new HeaderUI (p);
return _instance;
}
public function setSize (w:Number, h:Number):void
{
bg.width = w;
}
}
}

这是HeaderUI类的代码。在开始的几行中,你可以看到此类继承了Sprite类并实现了IResizable接口。后面的代码则显示界面和实现了setSize()方法。

另外两个类,BodyUI和FooterUI,类似的加入下面的代码:

package com.jor.examples.liquidgui.ui
{
import com.jor.examples.liquidgui.IResizable;
import flash.display.Sprite;
public class BodyUI extends Sprite implements IResizable
{
public static var _instance:BodyUI;
// 背景资源
[Embed(source="/assets/library.swf", symbol="BodyBG")]
private var BodyBG:Class;
public var bg:Sprite;
// 私有内容
private var _parent:Sprite;
public function BodyUI (p:Sprite)
{
_parent = p;
bg = new BodyBG ();
addChild (bg);
}
public static function getInstance (p:Sprite):BodyUI
{
if (_instance == null)
_instance = new BodyUI (p);
return _instance;
}
public function setSize(w:Number, h:Number):void
{
bg.width = w;
bg.height = h;
}
}
}

package com.jor.examples.liquidgui.ui
{
import com.jor.examples.liquidgui.IResizable;
import flash.display.Sprite;
public class FooterUI extends Sprite implements IResizable
{
public static var _instance:FooterUI;
// UI对象的私有引用
[Embed(source="/assets/library.swf", symbol="FooterBG")]
private var FooterBG:Class;
public var bg:Sprite;
private var _parent:Sprite;
public function FooterUI (p:Sprite)
{
_parent = p;
__configUI ();
}
private function __configUI ():void
{
bg = new FooterBG ();
addChild (bg);
}
public static function getInstance (p:Sprite):FooterUI
{
if (_instance == null)
_instance = new FooterUI (p);
return _instance;
}
public function setSize (w:Number, h:Number):void
{
bg.width = w;
}
}
}

最后,你需要修改一下主类来使用上面写的这几个类。代码如下:

package
{
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import com.jor.examples.liquidgui.ui.BodyUI;
import com.jor.examples.liquidgui.ui.FooterUI;
import com.jor.examples.liquidgui.ui.HeaderUI;
public class LiquidGUI_v3 extends Sprite
{
public static var hh:Number = 54; // 顶部的高度
public static var fh:Number = 75; // 底部的高度
public static var hfh:Number = 129; // 顶部和底部高度之和
private var _header:HeaderUI;
private var _body:BodyUI;
private var _footer:FooterUI;
public function LiquidGUI_v3 ()
{
// 不拉伸显示
stage.scaleMode = StageScaleMode.NO_SCALE;
// 用左上角作为坐标原点
stage.align = StageAlign.TOP_LEFT;
// 创建调整大小的监听
stage.addEventListener(Event.RESIZE, onResize);
// 创建和添加顶部
_header = HeaderUI.getInstance (this);
addChild (_header);
// 创建和添加主体部分
_body = BodyUI.getInstance (this);
addChild (_body);
_body.y = _header.height;
// 创建和添加底部
_footer = FooterUI.getInstance (this);
addChild (_footer);
// 添加完成后,调整初始化的大小
onResize (null);
}
public function onResize (event:Event):void
{
// 获取新的舞台大小
var sw:Number = stage.stageWidth;
var sh:Number = stage.stageHeight;
// 修改各部分的大小
_header.setSize (sw, 0);
_body.setSize (sw, sh-hfh);
_footer.setSize (sw, 0);
// 改变各部分的位置(只有_footer的y坐标需要修改)
_footer.y = sh-fh;
}
}
}

版本4

在最后的这个版本中,我将加入一些扩展的功能。这些扩展的功能会比较复杂一些,并且和我们的主题关系不大,因此下面只是简单的描述一些要点而不写出详细的代码:

1,顶部。添加一组单选按钮,以便用户可以选择是显示原始图象大小还是自动缩放图象大小。这些按钮被创建成自定义的单选按钮,在你点击某个按钮的时候,一个自定义的onChangeState事件将被分派并传递一个包含要转换的到名称的事件对象。

2,中间部分。在这部分,我添加了一个loader对象用来加载图片。BodyUI类同时也实现了一些事件监听来监听顶部和底部分派的事件。

3,底部。在这部分,我实现了一个小的loader来依次显示图片的缩略图。每个缩略图是一个新的ThumbnailUI类的对象,此类实现了鼠标点击事件的监听。当某个缩略图被点击以后,一个自定义的事件将被分派并传递需要加载并显示的图象的地址。

五、更多
我希望你能觉得这个教程对你是有帮助的。图片库应用是很有意思的东西,你可以把它做得更好,这里有一些点子:

1,定义你自己的显示界面;
2,将底部显示的图片用一个XML格式的文件定义;
3,XML文件中可以包含图片名称,大小等内容,也可以显示出来;
4,在主体部分添加滚动条,当图片大小超过了可显示范围后,可以通过拖动滚动条显示各个部分;
5,在缩略图部分也添加一个滚动条,当图片很多的时候,就可以拖动查看更多的图片了;
6,创建一个图片库选择器,用户可以在不同的图片库中选择;
7,使用同样的方法做一些其他的应用,比如RSS新闻阅读器;
8,把你做的东西分享给大家。

最后,我很希望能和你交流这些技术。如果你以有任何建议或意见,可以直接和我联系。最好的联系方式是我的blog:jamesor.com。编程快乐!

附PDF格式下载:liquidGUI.pdf

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值