GWT UiBinder部分官方介绍的翻译
2011-08-16 15:11
387 查看
页面来源:http://code.google.com/intl/zh-CN/webtoolkit/doc/latest/DevGuideUiBinder.html
随便硬译的,没有检查,没有修改。。。刚刚搜索了一下,发现网上已经有翻译好的了。。。Orz。。。->http://gwt-note.psmonkey.org/official/buildUI/With-UiBinder
使用UiBinder创建布局
这篇文档解释了如何在GWT2.0中通过使用UiBinder来创建xml格式的Widget和DOM结构。它并不会覆盖区域特征。
概述
根本上说,一个GWT程序就是一个网页。当你对一个网页进行布局的时候,编写HTML和CSS代码是完成这项工作的最自然的方法。UiBinder让你可以构建嵌入GWT widget的HTML网页。
Uibinder除了是一种更加自然、简洁的方式去创建你的UI之外,它还可以让你的程序更加高效。因为相比较于通过调用API来创建DOM结构,浏览器更加擅长用填充内嵌的html熟悉字符串的方法。Uibinder很自然的利用了这个优势,结果是这将是构建应用程序的最佳方式。
Uibinder…
l 提高效率和持久性——通过复制和粘贴模板来创建UI
l 对于习惯使用XML,HTML和CSS,而不是java代码的ui设计者来说将更加容易
l 在开发中提供一种逐渐的从HTML模拟到真实的可交互UI的转变
l 将程序的逻辑实现和UI分离
l 在运行时检查java代码和XML之间的交叉引用
l 提供对国际化的直接支持
l 通过使其更加方便地使用轻量级的HTML组件来使浏览器资源的使用更加高效
但是正如你了解到的uibinder,你也得了解uibinder不能做什么。它不是一个渲染器。也没有循环、条件、if语句。Uibinder让你可以布局你的组件。但是将数据转换成HTML代码仍然取决于组件自身。
该页面的剩余部分将通过一系列的典型实例来展示如何使用uibinder。你将会看到怎样布局UI,如何设置式样,如何添加事件处理器等等。国际化部分将展示如何国际化程序。
Hello world
这里是一个非常简单的使用uibinder模板的例子,它不包含组件,只有html:
现在,假设你需要程序化地读和写上面nameSpan里面的文本,你将要编写java代码去实现,所以uibinder模板有一个关联的拥有者类,这个类允许对在模板中声明的UI结构的访问。一个拥有者类可能是这个样子:
接着,你可以实例化并使用这个拥有者类。稍后我们会看到如何使用组件,但是这个例子使用直接的DOM操作:
UIbinder事例是factories,它生成一个UI结构,并将它关联到拥有者类上。UiBinder<U,O>接口声明了两个参数类型:
l U是在ui.xml文件中声明的根元素类型,由createAndBindUi()返回
l O是拥有者类
(在这个例子中,U=DivElement,O=Helloworld)
任何在ui.xml中声明的对象,包括所有DOM元素,都可以被拥有者类通过field name访问。这个例子中,一个<span>元素的ui:field属性,设置为nameSpan。xml中对应的组件在java代码里都用@UiField标识。当uiBinder.createAndBindUi(this)运行时,相应字段将被填充一个SpanElement的实例。
我们创建的这个java类恰巧继承了UiObject类,但是也可以仅仅是继承Widget类。这里并没有关于这类的限制。然而需要注意的是,用@UiField标记的字段默认是可见的。如果它们是被binder填充的,它们不能使private的。
Hello widget world
这里是一个使用widgets的uibinder模板:
注意到我们现在既使用了widgets也创建了一个widget。Helloworldwidget类可以呗添加到任何panel类
为了使用一个ui.xml模板文件里面的widgets,你需要将它们的包关联到一个XML命名空间的前缀。这就是为什么<ui:uibinder>有这一项:xmlns:g='urn:import:com.google.gwt.user.client.ui'。这说明该包中的每一个类都可以被当做一个element来使用,只要使用类似带g前缀的和标签名的方式,比如<g:ListBox>。
看到g:ListBox为什么有个visibleItemCount=’1’属性了吗?那将成为对ListBox#setVisibleItemCount(int)方法的一个调用。Widget中的每个遵循javabean-style用来设置属性的方法都可以通过这种方式调用。
特别要注意的是HTMLPanel类实例的使用。HTMLPanel擅长于混合HTML和widget,uibinder也能够很好的支持HTMLPanel。总之,只要你想在widget架构里面使用HTML成分,那么你就需要一个HTMLPanel或者HTMLWidget的实例。
使用面板
任何面板(准确的说是任何实现了HasWidgets接口的面板)都能在模板文件里使用,也可以包含其他面板。
有些GWT widgets要求特殊的部分,这些你将在它们的javadoc中找到说明。这里是一个DockLayoutPanel:
DockLayoutPanel的成员被组织在像<g:north>和<g:body>这样的组织元素里。不像模板里出现的那样,他们并不代表运行时对象。你不能给他们ui:field属性,因为在你的java类里将不会产生任何东西。这就是为什么它们的名字不是大写的。你将会发现还有其他遵循相同约定的特别的非运行时元素。
另外一个需要注意的地方是我们不能将HTML直接放入多数面板里,只有那些知道如何处理HTML,比如HTMLPanel,和实现了HasHTML接口的组件才能直接接受html代码。未来的GWT版本将取消这个限制,但同时这取决于你是否将你的HTML放到能理解HTML的组件里。
HTML字符
Uibinder模板是xml文件,而xml并不理解像 这样的字符。当你需要这样的字符的时候,你必须自己定义。为了方便,我们提供了一组定义,你可以通过设置你的DOCTYPE来导入:
需要注意的是,GWT编译器实际上将不会访问这个URL去获取文件,因为这个文件的拷贝已经加入到了编译器。然而,你的IDE可能会要获取它。
将事件处理器进行简单的绑定
Uibinder的一个任务是减少用java代码编写用户接口的繁琐性,java里的一些东西要求比事件处理器更加让人心烦意乱的引用。想想看你已经有多少次这样编写你的代码?
在一个uibinder拥有者类里面,你可以使用@UiHandler标记去使用所有匿名类。
然而,这里有一个限制:你只能使用@UiHandler处理由widget对象抛出的事件,而不是DOM元素。比如:<g:Button>可以,但是<button>不行。
Hello stylish world
通过<ui:style>元素,你可以在你需要的时候随时定义UI的样式表。
注意:<ui:style>元素必须是root元素的直接子元素。其他资源元素也是这样(<ui:image>and <ui:data>)
一个CssResource接口已经为你生成好,与其同时还有一个ClientBundle。这意味着如果你错误拼写了类名的时候,编译器将会对你发出警告。同时,你的CSS类名将会被弄乱,这样可以防止跟其他css块中的名字发生冲突,意味着不再需要全局css命名空间!
实际上,你可以在一个简单模板里面利用这个特点:
最后,你不在需要把css写在ui.xml里。多数真正的项目将会把它们的css代码放在单独的文件里。在下面的例子中,src将关联css的位置:
除了html,你还可以设置widget的式样。你可以通过设置styleName属性来重写css,或者使用特别的addStyleNames来增加式样而不影响原有的式样。
注意:addStyleNames是复数。
编程访问内嵌式样
你的代码可能要访问模板中使用的某些式样。比如,假设你的widget在使用的时候需要改变颜色:
<ui:style>元素有一个新的属性,type=’com.my.app.MyFoo.MyStyle’。这意味着它需要实现那个接口,并且提供它调用的两个css类,enabled和disabled。
现在,看看MyFoo.java中的 @UiField style。这使得代码可以访问为<ui:style>块而生成的CssResource。setEnable 方法使用这个字段来关闭和打开式样。
你可以不受限制地在一个试样块中定义足够多的类,但是你的代码只能访问那些在接口中要求的类。
使用外部资源
有时候你的模板需要访问外部的一些式样或者对象。可以使用<ui:with>元素。
‘with’这个元素声明了一个持有资源对象的字段,这个资源对象的方法可以通过调用来填充属性值。在这个例子中,通过调用GWT.create(Resources.class)来初始化。
注意:并不一定要求一个ui:with资源一定要实现ClientBundle接口,这里只是一个例子。
共享资源实例
你可以通过<ui:with>元素,让你的资源可以被模板访问,但是付出的代价是将他们初始化。如果你像让给你的代码负责查找或者创建资源,有两种方式可以控制。1,用@UiFactory标记一个工厂方法;2,自己填充一个字段,并标记为@UiField(provided=true)。
下面的代码说明的是前面的例子中如何通过使用@UiFactory来提供资源实例:
模板中的任何字段,只要是资源类型的就可以通过调用getResources方法初始化。如果你的工厂方法需要参数,这些将会被要求为属性。
@UiField(provided=true)可以让事情更简洁和好用。
使用一个构造方法需要参数的widget
模板中声明的每个widget都是通过调用GWT.create()来创建的。多数情况下这意味着它们是默认初始化的,也就是调用没有参数的构造方法。然而这里也有方法不这样做。除了前面提到的@UiFactory和@UiField(provided=true)机制,还可以使用@UiConstructor标记widget。
假设你有一个已经存在的widget需要构造方法参数:
你在下面的模板中使用它:
这样将会出现一个错误:
所以你可以使用一个@UiFactory方法…
标记一个构造方法:
或者是用@UiField(provided=true)标记一个字段
在相同widget上使用不同的xml模板
假设你是一个MVP级的开发人员。你有好的ui接口和实现它的widget。那你怎样在相同视图上使用几个不同的xml模板呢?
警告:这个例子仅仅是用相同代码来创建一个的一个演示,并不一定是用来创建应用的一个好模式。
LazyPanel和LazyDomElement
将会出现在未来的2.4版本中
如果如试图把你的应用的性能提升到极致的话,有时候在你的一些标签控件却需要花很长时间去呈现出来,
有时候甚至在一小段时间内对用户来说是不可见的。那么你可能想使用LazyPanel来改善这种情况,但是渐渐你会发现你自己都很懒,
因为LazyPanel是抽象的,你根本就不想跟扩展实现它。
<gwt:TabLayoutPanel barUnit='EM' barHeight='1.5'>
<gwt:tab>
<gwt:header>Summary</gwt:header>
<gwt:LazyPanel>
<my:SummaryPanel/>
</gwt:LazyPanel>
</gwt:tab>
<gwt:tab>
<gwt:header>Profile</gwt:header>
<gwt:LazyPanel>
<my:ProfilePanel/>
</gwt:LazyPanel>
</gwt:tab>
<gwt:tab>
<gwt:header>Reports</gwt:header>
<gwt:LazyPanel>
<my:ReportsPanel/>
</gwt:LazyPanel>
</gwt:tab>
</gwt:TabLayoutPanel>
上面那段代码的确有用,但是你同时也能做更多事情。
在你的应用里面别的地方总是有一大堆dom元素字段,在你的UI界面完成之后,用getElementById()方法就可以调用它们中的每一个。
通过使用LazyDomElement你可以延缓这些方法的调用,直到真的需要的时候采取调用这些方法来载入这些控件。
public class HelloWorld extends UIObject { // Could extend Widget instead
interface MyUiBinder extends UiBinder<DivElement, HelloWorld> {}
private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class);
@UiField LazyDomElement<SpanElement> nameSpan;
public HelloWorld() {
// createAndBindUi initializes this.nameSpan
setElement(uiBinder.createAndBindUi(this));
}
public void setName(String name) { nameSpan.get().setInnerText(name); }
}
随便硬译的,没有检查,没有修改。。。刚刚搜索了一下,发现网上已经有翻译好的了。。。Orz。。。->http://gwt-note.psmonkey.org/official/buildUI/With-UiBinder
使用UiBinder创建布局
这篇文档解释了如何在GWT2.0中通过使用UiBinder来创建xml格式的Widget和DOM结构。它并不会覆盖区域特征。
概述
根本上说,一个GWT程序就是一个网页。当你对一个网页进行布局的时候,编写HTML和CSS代码是完成这项工作的最自然的方法。UiBinder让你可以构建嵌入GWT widget的HTML网页。
Uibinder除了是一种更加自然、简洁的方式去创建你的UI之外,它还可以让你的程序更加高效。因为相比较于通过调用API来创建DOM结构,浏览器更加擅长用填充内嵌的html熟悉字符串的方法。Uibinder很自然的利用了这个优势,结果是这将是构建应用程序的最佳方式。
Uibinder…
l 提高效率和持久性——通过复制和粘贴模板来创建UI
l 对于习惯使用XML,HTML和CSS,而不是java代码的ui设计者来说将更加容易
l 在开发中提供一种逐渐的从HTML模拟到真实的可交互UI的转变
l 将程序的逻辑实现和UI分离
l 在运行时检查java代码和XML之间的交叉引用
l 提供对国际化的直接支持
l 通过使其更加方便地使用轻量级的HTML组件来使浏览器资源的使用更加高效
但是正如你了解到的uibinder,你也得了解uibinder不能做什么。它不是一个渲染器。也没有循环、条件、if语句。Uibinder让你可以布局你的组件。但是将数据转换成HTML代码仍然取决于组件自身。
该页面的剩余部分将通过一系列的典型实例来展示如何使用uibinder。你将会看到怎样布局UI,如何设置式样,如何添加事件处理器等等。国际化部分将展示如何国际化程序。
Hello world
这里是一个非常简单的使用uibinder模板的例子,它不包含组件,只有html:
<!-- HelloWorld.ui.xml --> <ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'> <div> Hello, <span ui:field='nameSpan'/>. </div> </ui:UiBinder>
现在,假设你需要程序化地读和写上面nameSpan里面的文本,你将要编写java代码去实现,所以uibinder模板有一个关联的拥有者类,这个类允许对在模板中声明的UI结构的访问。一个拥有者类可能是这个样子:
public class HelloWorld extends UIObject { // Could extend Widget instead interface MyUiBinder extends UiBinder<DivElement, HelloWorld> {} private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class); @UiField SpanElement nameSpan; public HelloWorld() { // createAndBindUi initializes this.nameSpan setElement(uiBinder.createAndBindUi(this)); } public void setName(String name) { nameSpan.setInnerText(name); } }
接着,你可以实例化并使用这个拥有者类。稍后我们会看到如何使用组件,但是这个例子使用直接的DOM操作:
HelloWorld helloWorld = new HelloWorld(); Document.get().getBody().appendChild(helloWorld.getElement()); helloWorld.setName("World");
UIbinder事例是factories,它生成一个UI结构,并将它关联到拥有者类上。UiBinder<U,O>接口声明了两个参数类型:
l U是在ui.xml文件中声明的根元素类型,由createAndBindUi()返回
l O是拥有者类
(在这个例子中,U=DivElement,O=Helloworld)
任何在ui.xml中声明的对象,包括所有DOM元素,都可以被拥有者类通过field name访问。这个例子中,一个<span>元素的ui:field属性,设置为nameSpan。xml中对应的组件在java代码里都用@UiField标识。当uiBinder.createAndBindUi(this)运行时,相应字段将被填充一个SpanElement的实例。
我们创建的这个java类恰巧继承了UiObject类,但是也可以仅仅是继承Widget类。这里并没有关于这类的限制。然而需要注意的是,用@UiField标记的字段默认是可见的。如果它们是被binder填充的,它们不能使private的。
Hello widget world
这里是一个使用widgets的uibinder模板:
<!-- HelloWidgetWorld.ui.xml --> <ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' xmlns:g='urn:import:com.google.gwt.user.client.ui'> <g:HTMLPanel> Hello, <g:ListBox ui:field='listBox' visibleItemCount='1'/>. </g:HTMLPanel> </ui:UiBinder>
public class HelloWidgetWorld extends Composite { interface MyUiBinder extends UiBinder<Widget, HelloWidgetWorld> {} private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class); @UiField ListBox listBox; public HelloWidgetWorld(String... names) { // sets listBox initWidget(uiBinder.createAndBindUi(this)); for (String name : names) { listBox.addItem(name); } } } // Use: HelloWidgetWorld helloWorld = new HelloWidgetWorld("able", "baker", "charlie");
注意到我们现在既使用了widgets也创建了一个widget。Helloworldwidget类可以呗添加到任何panel类
为了使用一个ui.xml模板文件里面的widgets,你需要将它们的包关联到一个XML命名空间的前缀。这就是为什么<ui:uibinder>有这一项:xmlns:g='urn:import:com.google.gwt.user.client.ui'。这说明该包中的每一个类都可以被当做一个element来使用,只要使用类似带g前缀的和标签名的方式,比如<g:ListBox>。
看到g:ListBox为什么有个visibleItemCount=’1’属性了吗?那将成为对ListBox#setVisibleItemCount(int)方法的一个调用。Widget中的每个遵循javabean-style用来设置属性的方法都可以通过这种方式调用。
特别要注意的是HTMLPanel类实例的使用。HTMLPanel擅长于混合HTML和widget,uibinder也能够很好的支持HTMLPanel。总之,只要你想在widget架构里面使用HTML成分,那么你就需要一个HTMLPanel或者HTMLWidget的实例。
使用面板
任何面板(准确的说是任何实现了HasWidgets接口的面板)都能在模板文件里使用,也可以包含其他面板。
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' xmlns:g='urn:import:com.google.gwt.user.client.ui'> <g:HorizontalPanel> <g:Label>Keep your ducks</g:Label> <g:Label>in a row</g:Label> </g:HorizontalPanel> </ui:UiBinder>
有些GWT widgets要求特殊的部分,这些你将在它们的javadoc中找到说明。这里是一个DockLayoutPanel:
<g:DockLayoutPanel unit='EM'> <g:north size='5'> <g:Label>Top</g:Label> </g:north> <g:center> <g:Label>Body</g:Label> </g:center> <g:west size='10'> <g:HTML> <ul> <li>Sidebar</li> <li>Sidebar</li> <li>Sidebar</li> </ul> </g:HTML> </g:west> </g:DockLayoutPanel>
DockLayoutPanel的成员被组织在像<g:north>和<g:body>这样的组织元素里。不像模板里出现的那样,他们并不代表运行时对象。你不能给他们ui:field属性,因为在你的java类里将不会产生任何东西。这就是为什么它们的名字不是大写的。你将会发现还有其他遵循相同约定的特别的非运行时元素。
另外一个需要注意的地方是我们不能将HTML直接放入多数面板里,只有那些知道如何处理HTML,比如HTMLPanel,和实现了HasHTML接口的组件才能直接接受html代码。未来的GWT版本将取消这个限制,但同时这取决于你是否将你的HTML放到能理解HTML的组件里。
HTML字符
Uibinder模板是xml文件,而xml并不理解像 这样的字符。当你需要这样的字符的时候,你必须自己定义。为了方便,我们提供了一组定义,你可以通过设置你的DOCTYPE来导入:
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
需要注意的是,GWT编译器实际上将不会访问这个URL去获取文件,因为这个文件的拷贝已经加入到了编译器。然而,你的IDE可能会要获取它。
将事件处理器进行简单的绑定
Uibinder的一个任务是减少用java代码编写用户接口的繁琐性,java里的一些东西要求比事件处理器更加让人心烦意乱的引用。想想看你已经有多少次这样编写你的代码?
public class MyFoo extends Composite { Button button = new Button(); public MyFoo() { button.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { handleClick(); } }); initWidget(button); } void handleClick() { Window.alert("Hello, AJAX"); } }
在一个uibinder拥有者类里面,你可以使用@UiHandler标记去使用所有匿名类。
public class MyFoo extends Composite { @UiField Button button; public MyFoo() { initWidget(button); } @UiHandler("button") void handleClick(ClickEvent e) { Window.alert("Hello, AJAX"); } }
然而,这里有一个限制:你只能使用@UiHandler处理由widget对象抛出的事件,而不是DOM元素。比如:<g:Button>可以,但是<button>不行。
Hello stylish world
通过<ui:style>元素,你可以在你需要的时候随时定义UI的样式表。
注意:<ui:style>元素必须是root元素的直接子元素。其他资源元素也是这样(<ui:image>and <ui:data>)
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'> <ui:style> .pretty { background-color: Skyblue; } </ui:style> <div class='{style.pretty}'> Hello, <span ui:field='nameSpan'/>. </div> </ui:UiBinder>
一个CssResource接口已经为你生成好,与其同时还有一个ClientBundle。这意味着如果你错误拼写了类名的时候,编译器将会对你发出警告。同时,你的CSS类名将会被弄乱,这样可以防止跟其他css块中的名字发生冲突,意味着不再需要全局css命名空间!
实际上,你可以在一个简单模板里面利用这个特点:
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'> <ui:style> .pretty { background-color: Skyblue; } </ui:style> <ui:style field='otherStyle'> .pretty { background-color: Orange; } </ui:style> <div class='{style.pretty}'> Hello, <span class='{otherStyle.pretty}' ui:field='nameSpan'/>. </div> </ui:UiBinder>
最后,你不在需要把css写在ui.xml里。多数真正的项目将会把它们的css代码放在单独的文件里。在下面的例子中,src将关联css的位置:
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'> <ui:style src="MyUi.css" /> <ui:style field='otherStyle' src="MyUiOtherStyle.css"> <div class='{style.pretty}'> Hello, <span class='{otherStyle.pretty}' ui:field='nameSpan'/>. </div> </ui:UiBinder>
除了html,你还可以设置widget的式样。你可以通过设置styleName属性来重写css,或者使用特别的addStyleNames来增加式样而不影响原有的式样。
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' xmlns:g='urn:import:com.google.gwt.user.client.ui'> <ui:style> .hot { color: magenta; } .pretty { background-color: Skyblue; } </ui:style> <g:PushButton styleName='{style.pretty}'>This button doesn't look like one</g:PushButton> <g:PushButton addStyleNames='{style.pretty} {style.hot}'>Push my hot button!</g:PushButton> </ui:UiBinder>
注意:addStyleNames是复数。
编程访问内嵌式样
你的代码可能要访问模板中使用的某些式样。比如,假设你的widget在使用的时候需要改变颜色:
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'> <ui:style type='com.my.app.MyFoo.MyStyle'> .redBox { background-color:pink; border: 1px solid red; } .enabled { color:black; } .disabled { color:gray; } </ui:style> <div class='{style.redBox} {style.enabled}'>I'm a red box widget.</div> </ui:UiBinder>
public class MyFoo extends Widget { interface MyStyle extends CssResource { String enabled(); String disabled(); } @UiField MyStyle style; /* ... */ void setEnabled(boolean enabled) { getElement().addClassName(enabled ? style.enabled() : style.disabled()); getElement().removeClassName(enabled ? style.disabled() : style.enabled()); } }
<ui:style>元素有一个新的属性,type=’com.my.app.MyFoo.MyStyle’。这意味着它需要实现那个接口,并且提供它调用的两个css类,enabled和disabled。
现在,看看MyFoo.java中的 @UiField style。这使得代码可以访问为<ui:style>块而生成的CssResource。setEnable 方法使用这个字段来关闭和打开式样。
你可以不受限制地在一个试样块中定义足够多的类,但是你的代码只能访问那些在接口中要求的类。
使用外部资源
有时候你的模板需要访问外部的一些式样或者对象。可以使用<ui:with>元素。
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' xmlns:g='urn:import:com.google.gwt.user.client.ui'> <ui:with field='res' type='com.my.app.widgets.logoname.Resources'/> <g:HTMLPanel> <g:Image resource='{res.logo}'/> <div class='{res.style.mainBlock}'> <div class='{res.style.userPictureSprite}'/> <div> Well hello there <span class='{res.style.nameSpan}' ui:field='nameSpan'/> </div> </div> </g:HTMLPanel> </ui:UiBinder>
/** * Resources used by the entire application. */ public interface Resources extends ClientBundle { @Source("Style.css") Style style(); @Source("Logo.jpg") ImageResource logo(); public interface Style extends CssResource { String mainBlock(); String nameSpan(); Sprite userPictureSprite(); } }
‘with’这个元素声明了一个持有资源对象的字段,这个资源对象的方法可以通过调用来填充属性值。在这个例子中,通过调用GWT.create(Resources.class)来初始化。
注意:并不一定要求一个ui:with资源一定要实现ClientBundle接口,这里只是一个例子。
共享资源实例
你可以通过<ui:with>元素,让你的资源可以被模板访问,但是付出的代价是将他们初始化。如果你像让给你的代码负责查找或者创建资源,有两种方式可以控制。1,用@UiFactory标记一个工厂方法;2,自己填充一个字段,并标记为@UiField(provided=true)。
下面的代码说明的是前面的例子中如何通过使用@UiFactory来提供资源实例:
public class LogoNamePanel extends Composite { interface MyUiBinder extend UiBinder<Widget, LogoNamePanel> {} private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class); @UiField SpanElement nameSpan; final Resources resources; public LogoNamePanel(Resources resources) { this.resources = resources; initWidget(uiBinder.createAndBindUi(this)); } public void setUserName(String userName) { nameSpan.setInnerText(userName); } @UiFactory /* this method could be static if you like */ public Resources getResources() { return resources; } }
模板中的任何字段,只要是资源类型的就可以通过调用getResources方法初始化。如果你的工厂方法需要参数,这些将会被要求为属性。
@UiField(provided=true)可以让事情更简洁和好用。
public class LogoNamePanel extends Composite { interface MyUiBinder extends UiBinder<Widget, LogoNamePanel> {} private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class); @UiField SpanElement nameSpan; @UiField(provided = true) final Resources resources; public LogoNamePanel(Resources resources) { this.resources = resources; initWidget(uiBinder.createAndBindUi(this)); } public void setUserName(String userName) { nameSpan.setInnerText(userName); } }
使用一个构造方法需要参数的widget
模板中声明的每个widget都是通过调用GWT.create()来创建的。多数情况下这意味着它们是默认初始化的,也就是调用没有参数的构造方法。然而这里也有方法不这样做。除了前面提到的@UiFactory和@UiField(provided=true)机制,还可以使用@UiConstructor标记widget。
假设你有一个已经存在的widget需要构造方法参数:
public CricketScores(String... teamNames) {...}
你在下面的模板中使用它:
<!-- UserDashboard.ui.xml --> <ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' xmlns:g='urn:import:com.google.gwt.user.client.ui' xmlns:my='urn:import:com.my.app.widgets' > <g:HTMLPanel> <my:WeatherReport ui:field='weather'/> <my:Stocks ui:field='stocks'/> <my:CricketScores ui:field='scores' /> </g:HTMLPanel> </ui:UiBinder>
public class UserDashboard extends Composite { interface MyUiBinder extends UiBinder<Widget, UserDashboard> {} private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class); public UserDashboard() { initWidget(uiBinder.createAndBindUi(this)); } }
这样将会出现一个错误:
[ERROR] com.my.app.widgets.CricketScores has no default (zero args) constructor. To fix this, you can define a @UiFactory method on the UiBinder's owner, or annotate a constructor of CricketScores with @UiConstructor.
所以你可以使用一个@UiFactory方法…
public class UserDashboard extends Composite { interface MyUiBinder extends UiBinder<Widget, UserDashboard>; private static final MyUiBinder uiBinder = GWT.create(MyUiBinder.class); private final String[] teamNames; public UserDashboard(String... teamNames) { this.teamNames = teamNames; initWidget(uiBinder.createAndBindUi(this)); } /** Used by MyUiBinder to instantiate CricketScores */ @UiFactory CricketScores makeCricketScores() { // method name is insignificant return new CricketScores(teamNames); } }
标记一个构造方法:
public @UiConstructor CricketScores(String teamNames) { this(teamNames.split("[, ]+")); }
<!-- UserDashboard.ui.xml --> <g:HTMLPanel xmlns:ui='urn:ui:com.google.gwt.uibinder' xmlns:g='urn:import:com.google.gwt.user.client.ui' xmlns:my='urn:import:com.my.app.widgets' > <my:WeatherReport ui:field='weather'/> <my:Stocks ui:field='stocks'/> <my:CricketScores ui:field='scores' teamNames='AUS, SAF, WA, QLD, VIC'/> </g:HTMLPanel>
或者是用@UiField(provided=true)标记一个字段
public class UserDashboard extends Composite { interface MyUiBinder extends UiBinder<Widget, UserDashboard>; private static final MyUiBinder uiBinder = GWT.create(MyUiBinder.class); @UiField(provided=true) final CricketScores cricketScores; // cannot be private public UserDashboard(CricketScores cricketScores) { // DI fans take note! this.cricketScores = cricketScores; initWidget(uiBinder.createAndBindUi(this)); } }
在相同widget上使用不同的xml模板
假设你是一个MVP级的开发人员。你有好的ui接口和实现它的widget。那你怎样在相同视图上使用几个不同的xml模板呢?
警告:这个例子仅仅是用相同代码来创建一个的一个演示,并不一定是用来创建应用的一个好模式。
public class FooPickerController { public interface Display { HasText getTitleField(); SourcesChangeEvents getPickerSelect(); } public void setDisplay(FooPickerDisplay display) { ... } } public class FooPickerDisplay extends Composite implements FooPickerController.Display { @UiTemplate("RedFooPicker.ui.xml") interface RedBinder extends UiBinder<Widget, FooPickerDisplay> {} private static RedBinder redBinder = GWT.create(RedBinder.class); @UiTemplate("BlueFooPicker.ui.xml") interface BlueBinder extends UiBinder<Widget, FooPickerDisplay> {} private static BlueBinder blueBinder = GWT.create(BlueBinder.class); @UiField HasText titleField; @UiField SourcesChangeEvents pickerSelect; public HasText getTitleField() { return titleField; } public SourcesChangeEvents getPickerSelect() { return pickerSelect; } protected FooPickerDisplay(UiBinder<Widget, FooPickerDisplay> binder) { initWidget(uiBinder.createAndBindUi(this)); } public static FooPickerDisplay createRedPicker() { return new FooPickerDisplay(redBinder); } public static FooPickerDisplay createBluePicker() { return new FooPickerDisplay(blueBinder); } }
LazyPanel和LazyDomElement
将会出现在未来的2.4版本中
如果如试图把你的应用的性能提升到极致的话,有时候在你的一些标签控件却需要花很长时间去呈现出来,
有时候甚至在一小段时间内对用户来说是不可见的。那么你可能想使用LazyPanel来改善这种情况,但是渐渐你会发现你自己都很懒,
因为LazyPanel是抽象的,你根本就不想跟扩展实现它。
<gwt:TabLayoutPanel barUnit='EM' barHeight='1.5'>
<gwt:tab>
<gwt:header>Summary</gwt:header>
<gwt:LazyPanel>
<my:SummaryPanel/>
</gwt:LazyPanel>
</gwt:tab>
<gwt:tab>
<gwt:header>Profile</gwt:header>
<gwt:LazyPanel>
<my:ProfilePanel/>
</gwt:LazyPanel>
</gwt:tab>
<gwt:tab>
<gwt:header>Reports</gwt:header>
<gwt:LazyPanel>
<my:ReportsPanel/>
</gwt:LazyPanel>
</gwt:tab>
</gwt:TabLayoutPanel>
上面那段代码的确有用,但是你同时也能做更多事情。
在你的应用里面别的地方总是有一大堆dom元素字段,在你的UI界面完成之后,用getElementById()方法就可以调用它们中的每一个。
通过使用LazyDomElement你可以延缓这些方法的调用,直到真的需要的时候采取调用这些方法来载入这些控件。
public class HelloWorld extends UIObject { // Could extend Widget instead
interface MyUiBinder extends UiBinder<DivElement, HelloWorld> {}
private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class);
@UiField LazyDomElement<SpanElement> nameSpan;
public HelloWorld() {
// createAndBindUi initializes this.nameSpan
setElement(uiBinder.createAndBindUi(this));
}
public void setName(String name) { nameSpan.get().setInnerText(name); }
}
相关文章推荐
- GWT UiBinder部分官方介绍的翻译
- 翻译Protocol buffers官方部分介绍 java
- Apache Cassandra 1.1 项目介绍(逐篇翻译官方文档加一部分评论)
- Django 2.0.1 官方文档翻译:编写你的第一个 Django app,第六部分(Page 11)
- 【AKKA 官方文档翻译】示例介绍
- django 1.8 官方文档翻译: 1-2-4 编写你的第一个Django应用,第4部分
- spring-boot官方文档翻译——第三部分
- Unity官方教程 联机部分翻译
- Django 2.0.1 官方文档翻译: 编写你的第一个 Django app,第四部分(Page 9)
- GreenDao 3.2.0官网介绍的部分翻译(一)
- 《WCF技术内幕》翻译20:第2部分_第5章_消息:Message类型介绍
- 【AKKA 官方文档翻译】第二部分:创建第一个actor
- Spring官方文档翻译——15.1 介绍Spring Web MVC框架
- django 1.8 官方文档翻译: 1-2-5 编写你的第一个Django应用,第5部分
- 操作系统三个简单的部分(Operating Systems in Three Easy Pieces闲来无聊,翻译的)1,2(操作系统的介绍部分)
- iOS 开发 深入浅出Runtime运行时之官方指南翻译--runtime介绍
- erlang的官方文档部分翻译
- 【AKKA 官方文档翻译】第三部分:与设备Actor一起工作
- Postman使用官方文档翻译--7设置介绍
- Spring官方文档翻译——15.1 介绍Spring Web MVC框架