Views
出自OpenFace
第十八章 视图
第四部分 进级概念
目录 |
基本特性
视图是OpenFace应用中的基本可视元素。任何在canvas上显示出来的东西都是一个<view>或视图类的扩展。
视图是矩形容器
在视觉上,一个<view>是矩形容器,它包含高,宽和位置(由左上角的x,y值来指定)属性。视图的背景颜色默认为透明,但也可以设置颜色。透明视图可以包含任意形状的图像。因此,虽然视图是长方形的,但OpenLaszlo应用程序在看起来可以有任何的外观。
逻辑上,视图是用作容器的对象。视图可以包含其他视图,即子视图;也可以和资源相联系,如图像。
Example 18.1. 简单视图
<canvas height="50" width="500"> <view width="50" height="50" bgcolor="red"/> </canvas>
Example 18.2. 不可见视图
<canvas height="50"> <view height="20" width="20" visible="false"/> </canvas>
Example 18.3. 视图初试化
<canvas height="160">
<view height="20" width="20" oninit="Debug.write('howdy')"/>
</canvas>
可见视图
如果将一个颜色或一张图片分派给视图并且他的宽和高都大于零,那他是可见的。例如,下面的代码显示的只有定义的四个视图中的两个图像。第二个和第三个视图存在但他们完全透明。第二个没有给他分派颜色,第三个的宽为零。然而,他们仍然影响其他两个视图的排列。
Example 18.4. 例
<canvas height="60" width="500"> <view width="50" height="50" bgcolor="red"/> <view width="50" height="50"/> <view width="0" height="50" bgcolor="blue"/> <view resource="../images/logo.jpg"/> <simplelayout axis="x" spacing="5"/> </canvas>
第一个视图是一个红色的正方形。
第二个视图不能直观地看到,因为他没有颜色但他仍然存在并移动了其他视图。
第三个视图不能直观地看到,因为他的宽为零,但他仍然存在。
第四个视图显示的是格式为jpg 的图像。
Z 轴
除了x,y轴,OpenLaszlo视图结构体系中还存在z轴。如果两个兄弟视图有重叠,后者(指它的LZX代码处于后面)将会出现在前者的上面。
这种顺序可以使用bringToFront()和sendToBack()方法来改变,允许一个视图在z轴上相对另一个视图移动:
Example 18.5.
<canvas height="100">
<view bgcolor="red" id="red" width="50" height="50" />
<view bgcolor="blue" id="blue" width="50" height="50" x="20" y="20"/>
<view bgcolor="green" id="green" width="50" height="50" x="40" y="40"/>
<handler name="onkeydown" args="key" reference="LzKeys">
var keycode = key.intValue();
switch(keycode){
case 96:
red.sendInFrontOf(blue);
break;
case 97:
blue.sendInFrontOf(green);
break;
case 98:
green.sendBehind(red);
break;
}
</handler>
</canvas>
视图嵌套
视图间也可以相互包含,从而可以创造出复杂的可视化元素。每个父视图可以拥有多个子视图,每个子视图的位置都是相对于父视图的左上角的,如这显示的:
Example 18.6. 嵌套视图
<canvas height="200" width="500">
<view bgcolor="red" x="50" y="50" width="100" height="100">
<view bgcolor="blue" width="50" height="50"/>
<view bgcolor="yellow" x="50" y="50" width="60" height="105">
<view width="50" height="50" bgcolor="green"/>
</view>
</view>
</canvas>
每个子视图有且只能拥有一个父视图。父视图和子视图之间的关系在下文和后面的章节复述。
根据子视图来设置视图大小
如果没有对视图设置宽度和高度,它就会采用子视图的外包矩形的宽度和高度。而上面的例子所示,视图也可以和子视图外包矩形尺寸不一致。黄颜色的视图,即使处在父视图以外了,也没有被裁剪。如果需要裁剪的话,可以设置属性 clip=“true” :
Example 18.7. 使用clip属性
<canvas height="150" width="500">
<view bgcolor="red" x="50" y="50" width="100" height="100" clip="true">
<view bgcolor="blue" width="50" height="50"/>
<view bgcolor="yellow" x="50" y="50" width="60" height="105">
<view width="50" height="50" bgcolor="green"/>
</view>
</view>
</canvas>
如上所述,视图不需要显示一个图片或颜色去影响其他视图。这种类型的视图被称为“空白视图”。实际上,这种在一组视图中使用空白视图的技术被广泛地使用在应用的例子中。下面的代码显示时发生什么
Example 18.8. 空白视图
<canvas height="200" width="500">
<view x="50" y="50" width="100" height="100">
<view bgcolor="blue" width="50" height="50"/>
<view bgcolor="yellow" x="50" y="50" width="60" height="105">
<view width="50" height="50" bgcolor="green"/>
</view>
</view>
</canvas>
视图,约束和布局
事实上,视图可以被分配不同的尺寸。在OpenLaszlo中子视图比其他元素有优势,例如:约束(第24章)和布局(第16章)。
为了说明这一点,下面的例子有两个同样尺寸的视图和子视图。这段代码的不同是在顶视图中有一个<simplelayout>。<simplelayout>忽略了父节点的宽度。
如果不明白这样使用上面描述的布局不要担心;布局在第16章布局和设计中会详细的介绍。要把握的关键点是视图与他的子视图边界相比可以有不同的尺寸。这是OpenLaszlo视图系统中数不胜数的基本特性之一。
Example 18.9. 子视图布局
<canvas height="100" width="500"> <view bgcolor="red" width="200" height="30"> <view bgcolor="blue" width="30" height="30"/> <view bgcolor="yellow" width="30" height="30"/> <view bgcolor="blue" width="30" height="30"/> <simplelayout axis="x" spacing="0"/> </view> </canvas>
视图坐标系
以canvas开始,每个视图有他自己内在的2D坐标系,正像你期望的,水平轴是x和垂直轴是y。视图的位置是相对于上一层坐标系计算的。
作为视图的层次可以是很复杂的,重要的是谨记,对于任何视图:
视图从那开始计算是与该视图上一层的坐标系有关的。
一个简单的例子来说,例如,canvas的下一层,明确他的起始坐标轴是简单的。另一个例子有些微妙——例如当一个视图的x或y的值是负数时,或父视图大小改变时。这些例子将在下面探讨。
相对位置
对于程序运行时视图的位置,可以使用视图的getAbsoluteX()和getAbsoluteY()方法来获得视图相对其上一层的x和y坐标。例如,考虑下面的例子:
Example 18.10. 相对位置
<canvas height="350">
<view name="parentView" x="10" bgcolor="blue" height="40" width="40"
oninit="Debug.write('parentView x is', x)" >
<view name="childView" x="35" bgcolor="yellow" height="20" width="20"
oninit="Debug.write('childview x is', x)"/>
</view>
</canvas>
childView的x值是35,但是他的x值相对于canvas是45(因为他的上一层parentView,相对于canvas已经有10个像素的偏移)。当childView位于canvas下时,该视图的x值是45,因为相对于他的上一层(canvas)有相同的偏移量。
设置视图大小
不指定视图的宽和高时将是0px宽和0px高:
<view/>
视图的大小尺寸可以被明确的设置:
<view width="20"/> <view width="20" height="35"/>
第一个视图是不可见的,因为他的高是零
如果一个视图的尺寸没有明确地给出,但它包含了子视图(或有附有一个资源),那么该视图将自动地给定大小到符合它的内容或资源。在这个例子中,黄色的视图会是40px宽和25px高:
<view bgcolor="yellow"> <view bgcolor="red" width="10" height="10" x="30" y="15"/> </view>
如果视图附有一种资源(并且没有设置它的尺寸),那么视图的大小是它附有资源的大小。在这个例子中,如果someimg.jpg的宽是70px,高是30px,那么视图的宽也是70px,高也是30px。
<view resource="someimg.jpg"/>
在例子中,视图中的资源在运行时被加载时(i.e.当按键时加载图片),该视图直到被加载之前宽是0px,高是0px。 如果在应用中其他的元素依赖这个视图的大小是,可能引起意想不到的问题。
<canvas>
<simplelayout axis="y" spacing="2"/>
<view id="myImageView"/>
<view width="100" height="20" bgcolor="yellow"/>
<view width="100" height="20" bgcolor="red"/>
<view x="10" y="110" oninit="LzFocus.setFocus(this)">Set Image Now!
<handler name="onkeydown" reference="LzKeys">
myImageView.setSource("someimage.jpg");
</handler>
</view >
</canvas>
在初始化时,黄色的视图的位置是(0, 0),因为myImageView的尺度宽是0px,高是0px。当图片被加载(按键后)myImageView的大小被调整成图像的大小。myImageView和其他兄弟视图由于<simplelayout>的作用,都将向下移动。
如需了解更多关于视图的分配资源的问题,见第17章,媒体资源。
视图的定位
有多种方式可以设置一个视图的位置。可以在视图的标签中明确地给出的x和y的值;可以通过其他属性强制地给出x和y的值,包括包含在一个数据集里。可以使用布局让系统确定视图的位置,或者在运行期间通过脚本改变位置。
声明
使用绝对的x和y的值
使用约束
使用路径约束
使用布局
编程
使用setAttribute()方法
脚本实例
使用绝对坐标声明视图的位置
可以使用绝对的x和y坐标决定视图的位置,然而视图的位置相对于它的上一层位置确定:
Example 18.11. 绝对坐标
<canvas> <view bgcolor="yellow" width="300" height="300" x="15" y="20"> <view bgcolor="red" width="20" height="20" x="25" y="75"/> <view bgcolor="blue" width="20" height="20" x="75" y="200"/> <view bgcolor="green" width="20" height="20" x="50" y="50"/> </view> </canvas>
使用约束声明视图的位置
您也可以使用约束来确定视图的位置。在下面的例子中,红色视图的位置是绝对的,蓝色视图的x和y是被红色视图的坐标函数约束的。
Example 18.12。 使用约束
<canvas>
<view bgcolor="yellow" width="300" height="300">
<attribute name="someXValue" type="number" value="50"/>
<view bgcolor="red" name="red" width="20" height="20" x="$once{20 + 5}" y="$once{70 + 5}"/>
<view bgcolor="blue" width="20" height="20" x="${parent.red.y}" y="${parent.red.x}"/>
<view bgcolor="green" width="20" height="20" x="${parent.someXValue}" y="${this.x}"/>
</view>
</canvas>
在上面的例子中
红色视图的x和y坐标是被数学表达式约束的(分别是20+5和70+5)。
蓝色视图的x和y坐标是分别是被红色视图的y和x坐标约束的。
绿色视图的x和y坐标是被一些任意的属性值约束的。
要更多地了解约束的语法,见第19章,约束。
负坐标值
x和y的值也可以被设置为负数。在下面的例子中,运行后正方形的视图向左或向右。上一层的正方形(teal颜色的)包含蓝色和黑色的正方形,但不包括x和y值是负的红色和银色正方形。
Example 18.14. 负坐标值
<canvas height="250" bgcolor="gray">
<view bgcolor="red" width="20" height="20" >
<animator attribute="y" from="-50" to="200" duration="500"/>
</view>
<view bgcolor="silver" width="20" height="20" >
<animator attribute="x" from="-50" to="200" duration="500"/>
</view>
<view bgcolor="blue" width="20" height="20">
<animator attribute="y" from="50" to="200" duration="500"/>
</view>
<view bgcolor="black" width="20" height="20" >
<animator attribute="x" from="50" to="200" duration="500"/>
</view>
</canvas>
视图的层次
在视图层次中每个视图有一个位置,这是一个对象的树形结构,每个视图有一个父视图,任意个子视图或兄弟视图。一个简单的例子就像父母和孩子之间的关系是显而易见的。
Example 18.15. 多层view
<canvas height="100">
<view height="100" width="100" name="grandparent" bgcolor="red">
<view height="50" width="50" name="parent" bgcolor="green">
<view height="30" width="30" name="child" bgcolor="blue"/>
</view>
</view>
</canvas>
然而,事情通常是更复杂的,尤其是当视图在类中被创建时。视图能在运行是被创建或销毁,此外唯一的代码行可能导致创建多个视图。在多数情况下,实际上是代码中视图的两个层次,对象的节点层次通过代码被创建。
在不同层次的视图关系中LZX使用间接父视图和直接父视图是有区别的。这些术语更深入的解释将在之后的章节介绍,但这里有个短暂的浏览。
父视图和子视图
Example 18.16.父视图和子视图
<canvas height="100">
<class name="mywindow" bgcolor="blue">
<attribute name="defaultplacement" value="mycontent" type="string"/>
<view name="mycontent" x="10" y="10" bgcolor="white"
width="${parent.width-20}" height="${parent.height-20}">
</view>
</class>
<mywindow id="w" width="100" height="100" bgcolor="blue">
<text>hello</text>
</mywindow>
</canvas>
这个视图包含文本hello,该文本有一个父视图 w和一个直接父视图w.mycontent。注意"mycontent"能被嵌套在其他的视图中。我们通过“节点层次”调用排序的对象。“视图层次”更直观,但“节点层次”更准确。(注意在上述的例子中"dragger"是一个节点而不是一个视图)。
如果你是一个有经验的javascript程序员,你会在之前看见过这种模式。当你在JavaScript中看到"immediateparent",会想到“容器”。
类定义:
Example 18.17. 简单布局
<canvas height="60"> <class name="myclass"> <simplelayout/> <view name="content"/> <text>label</text> </class> <myclass><text placement="content">content1</text></myclass> <myclass><text placement="content">content2</text></myclass> <simplelayout axis="y"/> </canvas>
这是源代码片段:
<myclass><text placement="content">content1</text></myclass> <myclass><text placement="content">content2</text></myclass>
逻辑分析图:
myclass (text "content1") myclass (text "content2")
视觉图:
myclass (view (text "content1")) (text "label") myclass (view (text "content2")) (text "label")
因此父视图在逻辑分析图中引用父节点。直接父节点(在JavaScript)和布置(在XML)在视觉图中引用父节点。布置是类似的,但直接父节点不同。你可以把他们当作相同的定义不同的类型,但必须清楚的是:布置是一个意味着“当视图中创建个子视图,在子视图(或任意子视图)中找这个名字的视图”的字符串。直接父视图随后引用这个视图。
这些概念在第24章,继承类中有更多的例子做进一步的解释。
视图和节点
在LZX中,基本的对象被叫做节点。节点是抽象的实体,正因如此它们没有视觉的代表性。视图是最常见的一种节点,而在大多数情况下,当你需要一个容器对象,你应该是用视图。事实上,虽然你为大部分的抽象基础结构使用<node>(数据集操作、内容管理、检测等)。节点只通过脚本被创建;没有标签创建它们。
如何建立视图
有时重要的是要明白视图被创建的顺序。在附录A中有更深层的解释,理解实例,这里只是简要的介绍:
视图形成的三个阶段:
创建:视图被创建,用常量设置属性初始值。
实例化:用动态的值设置属性(包括约束和子视图的实例化)。
设定初值:init() 方法被执行,oninit 事件发送
特色鲜明的OpenLaszlo坐标系
如果你有图形编程的经验,你可能会对下面的段落感兴趣。否则,你可以跳过这个话题。
视图的基本特性有:
拉伸--无论在模式上还是在尺寸上
{height,width}—剪切或模式按照拉伸设定
OpenFace系统相当于Flash Player's,但是在语句构成上更接近HTML/CSS标准(拉伸的默认值是both而不是none)。
其他系统的界定,只有一个转换,或仅是一个转换和模式,或者允许任意3x2或3x3转型。OpenLaszlo 与众不同的是没有确定的转换('x'和'y'的位置在父视图内定以的转换由于旋转\模式,因此不能这样使用)

