?使用 GWT 小部件构建 UI。

在本章中,我们将使用 Material Design 规范为 **TodoList** 应用程序构建一个现代化的 UI。我们将使用 Vaadin gwt-polymer-elements 库,它是 Polymer Paper Elements 集合的包装器。

主屏幕

  1. 创建应用程序的 **主屏幕**。

    我们将创建一个由 Java 文件(Main.java)及其视觉描述符(Main.ui.xml)组成的 UiBinder 屏幕。

    您可以通过复制以下代码段或使用 Eclipse GWT 插件生成这些文件。

    • Main.java
        package org.gwtproject.tutorial;
    
        import com.google.gwt.core.client.GWT;
        import com.google.gwt.uibinder.client.UiBinder;
        import com.google.gwt.user.client.ui.Composite;
        import com.google.gwt.user.client.ui.HTMLPanel;
    
        public class Main extends Composite {
          interface MainUiBinder extends UiBinder<HTMLPanel, Main> {
          }
    
          private static MainUiBinder ourUiBinder = GWT.create(MainUiBinder.class);
    
          public Main() {
            initWidget(ourUiBinder.createAndBindUi(this));
          }
        }
    
    • Main.ui.xml
        <ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
                 xmlns:g='urn:import:com.google.gwt.user.client.ui'>
    
          <g:HTMLPanel>
          </g:HTMLPanel>
    
        </ui:UiBinder>
    
  2. 添加 **菜单项**。

    现在,我们可以通过添加菜单项来更新 Main.ui.xml 文件。

    <ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
             xmlns:g='urn:import:com.google.gwt.user.client.ui'
             xmlns:p='urn:import:com.vaadin.polymer.paper.widget'
             xmlns:i='urn:import:com.vaadin.polymer.iron.widget'>
    
      <g:HTMLPanel>
        <p:PaperIconItem ui:field="menuClearAll">
            <i:IronIcon icon="delete" attributes="item-icon"/>
            <div>Clear All</div>
        </p:PaperIconItem>
        <p:PaperIconItem ui:field="menuClearDone">
            <i:IronIcon icon="clear" attributes="item-icon"/>
            <div>Clear Done</div>
        </p:PaperIconItem>
        <p:PaperIconItem ui:field="menuSettings">
            <i:IronIcon icon="settings" attributes="item-icon"/>
            <div>Settings</div>
        </p:PaperIconItem>
        <p:PaperIconItem ui:field="menuAbout">
            <i:IronIcon icon="help" attributes="item-icon"/>
            <div>About</div>
        </p:PaperIconItem>
      </g:HTMLPanel>
    </ui:UiBinder>
    

    **注意**:在此步骤中,我们添加了 Paper 和 Iron 包所需的导入。

    **提示**:如果您对小部件的详细信息感兴趣,请访问 IronPaper 小部件的 Javadoc

  3. 更新 **入口点** 以使用我们的新屏幕。

    package org.gwtproject.tutorial;
    
    import com.google.gwt.core.client.EntryPoint;
    import com.google.gwt.user.client.ui.RootPanel;
    
    public class TodoList implements EntryPoint {
    
      public void onModuleLoad() {
        RootPanel.get().add(new Main());
      }
    }
    
  4. 运行应用程序。

    在浏览器中重新加载页面,您应该看到四个菜单项。您可能会注意到缺少图标。我们将在下一步中修复它。

图标和效果

  1. 导入 **图标集合**。

    Polymer 附带几个图标集合。在可以使用集合之前,必须先导入它。在此示例中,我们将使用 Iron 集。在下面的代码中,我们使用 Polymer.importHref 实用程序方法,并在集合加载完毕后运行应用程序。

    package org.gwtproject.tutorial;
    
    import com.google.gwt.core.client.EntryPoint;
    import com.google.gwt.user.client.ui.RootPanel;
    import com.vaadin.polymer.Polymer;
    import com.vaadin.polymer.elemental.Function;
    
    public class TodoList implements EntryPoint {
    
      public void onModuleLoad() {
        // We have to load icon sets before run application
        Polymer.importHref("iron-icons/iron-icons.html", new Function() {
            public Object call(Object arg) {
                // The app is executed when all imports succeed.
                startApplication();
                return null;
            }
        });
      }
    
      private void startApplication() {
        RootPanel.get().add(new Main());
      }
    }
    
  2. 重新加载应用程序

    您现在应该在浏览器中看到所有图标。

  3. 添加 **涟漪** 效果

    与 UI 元素交互时的反馈通常被认为是积极的。如果您愿意,可以详细了解 Material Design 关于 响应式交互 的理念。

    • <p:PaperRipple/> 添加到 Main.ui.xml 文件中的每个项目中。
    • 我们需要在项目中添加一些 CSS 样式属性,以便涟漪效果限制在项目区域内。
        <ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
             xmlns:g='urn:import:com.google.gwt.user.client.ui'
             xmlns:p='urn:import:com.vaadin.polymer.paper.widget'
             xmlns:i='urn:import:com.vaadin.polymer.iron.widget'>
    
            <ui:style>
              paper-icon-item {
                position: relative;
                overflow: hidden;
              }
            </ui:style>
    
            <g:HTMLPanel>
              <p:PaperIconItem ui:field="menuClearAll">
                <i:IronIcon icon="delete" attributes="item-icon"/>
                <div>Clear All</div>
                <p:PaperRipple/>
              </p:PaperIconItem>
              <p:PaperIconItem ui:field="menuClearDone">
                <i:IronIcon icon="clear" attributes="item-icon"/>
                <div>Clear Done</div>
                <p:PaperRipple/>
              </p:PaperIconItem>
              <p:PaperIconItem ui:field="menuSettings">
                <i:IronIcon icon="settings" attributes="item-icon"/>
                <div>Settings</div>
                <p:PaperRipple/>
              </p:PaperIconItem>
              <p:PaperIconItem ui:field="menuAbout">
                <i:IronIcon icon="help" attributes="item-icon"/>
                <div>About</div>
                <p:PaperRipple/>
              </p:PaperIconItem>
            </g:HTMLPanel>
        </ui:UiBinder>
    
  4. 重新加载应用程序以查看涟漪效果。

    比较添加 PaperRipple 效果前后点击的反应。

响应式布局

  1. 使用 PaperDrawPanel 布局应用程序。

    Paper 元素集合包括一个响应式抽屉面板。它是一个布局组件,可用于现代应用程序,以确保它们在台式机和移动设备上都能正常运行。有关详细信息,请查看 paper-drawer-panel 的 演示

    <ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
             xmlns:g='urn:import:com.google.gwt.user.client.ui'
             xmlns:p='urn:import:com.vaadin.polymer.paper.widget'
             xmlns:i='urn:import:com.vaadin.polymer.iron.widget'>
    
      <ui:style>
         paper-icon-item {
           position: relative;
           overflow: hidden;
         }
      </ui:style>
    
      <g:HTMLPanel>
        <p:PaperDrawerPanel ui:field="drawerPanel">
            <div drawer="">
                <p:PaperHeaderPanel mode="seamed">
                    <p:PaperToolbar/>
                    <p:PaperIconItem ui:field="menuClearAll">
                        <i:IronIcon icon="delete" attributes="item-icon"/>
                        <div>Clear All</div>
                        <p:PaperRipple/>
                    </p:PaperIconItem>
                    <p:PaperIconItem ui:field="menuClearDone">
                        <i:IronIcon icon="clear" attributes="item-icon"/>
                        <div>Clear Done</div>
                        <p:PaperRipple/>
                    </p:PaperIconItem>
                    <p:PaperIconItem ui:field="menuSettings">
                        <i:IronIcon icon="settings" attributes="item-icon"/>
                        <div>Settings</div>
                        <p:PaperRipple/>
                    </p:PaperIconItem>
                    <p:PaperIconItem ui:field="menuAbout">
                        <i:IronIcon icon="help" attributes="item-icon"/>
                        <div>About</div>
                        <p:PaperRipple/>
                    </p:PaperIconItem>
                </p:PaperHeaderPanel>
            </div>
            <div main="">
                <p:PaperHeaderPanel mode="seamed">
                    <p:PaperToolbar>
                        <p:PaperIconButton ui:field="menu" icon="more-vert"
                            attributes="paper-drawer-toggle"/>
                        <span>Todo List</span>
                    </p:PaperToolbar>
                </p:PaperHeaderPanel>
            </div>
        </p:PaperDrawerPanel>
      </g:HTMLPanel>
    </ui:UiBinder>
    
  2. 添加 *内容面板*

    • 添加一个用于存放待办事项的容器。
        <g:HTMLPanel>
           ...
            <div main="">
                <p:PaperHeaderPanel mode="seamed">
                    <p:PaperToolbar>
                        <p:PaperIconButton ui:field="menu" icon="more-vert"
                            attributes="paper-drawer-toggle"/>
                        <span>Todo List</span>
                    </p:PaperToolbar>
    
                    <g:HTMLPanel ui:field="content"
                       addStyleNames="vertical center-justified layout" />
    
                </p:PaperHeaderPanel>
            </div>
           ...
        </g:HTMLPanel>
    
  3. 重新加载应用程序

    应用程序现在应该具有现代外观并具有响应能力。如果调整浏览器窗口大小,使其宽度小于 640 像素,则抽屉面板应隐藏菜单。

?样式化应用程序

使用 CssResource 样式化

使用 Polymer 小部件时,您可以像往常一样使用 GWT GSS 解析器,并使用 {} 运算符将样式添加到小部件或元素。

  • 更改工具栏的颜色,设置标题文本和内容面板的样式

        <ui:style>
          .toolbar {
            background: #4285f4 !important;
           }
          .header {
            font-size: 200%;
            margin-left: 50px;
            background: #4285f4 !important;
           }
          .content {
            padding: 15px;
           }
           ...
        </ui:style>
        <g:HTMLPanel>
           ...
            <div main="">
                <p:PaperHeaderPanel mode="seamed">
                    <p:PaperToolbar addStyleNames="{style.toolbar}">
                        <p:PaperIconButton ui:field="menu" icon="more-vert"
                            attributes="paper-drawer-toggle"/>
                        <span class="{style.header}">Todo List</span>
                    </p:PaperToolbar>
                    <g:HTMLPanel ui:field="content"
                           addStyleNames="{style.content} vertical center-justified layout"/>
                </p:PaperHeaderPanel>
            </div>
           ...
        </g:HTMLPanel>
    

**注意**:verticalcenter-justifiedlayout 类由 Polymer 提供。

使用 Polymer 样式化

Web Components 使用 Shadow DOM 样式 规则,提供封装的组件样式。此外,Polymer 还提供 Shady DOM,这对于没有实现本地 Shadow DOM 的浏览器来说是必需的。因此,Polymer 会监视并解析每个 <style> 块,并在运行时重写规则。

GSS 处理器以及 GWT 加载 css 资源的方式使得无法使用 shadowpolymer 选择器,也无法在 <ui:style> 块中使用 Polymer 属性。因此,您必须在 UiBinder 文件中使用普通的 <style>

另一个需要注意的地方是,GWT 会延迟加载 CssResource,因此,在某些情况下,如果需要在元素位于 DOM 中之前使用样式规则,则必须使用 <style>

  • 添加并设置 **浮动操作按钮** 的样式

    Material Design 应用程序使用浮动按钮作为主要操作的典型按钮。在 Paper 元素集合中,此按钮称为 paper-fab

    <ui:style>
    ...
    </ui:style>
    <g:HTMLPanel>
      <style is='custom-style'>
        .add {
            position: absolute;
            bottom: 20px;
            right: 20px;
            --paper-fab-background: var(--paper-red-500);
        }
      </style>
      <div main="">
        ...
        <p:PaperFab ui:field="addButton" icon="add"
                    addStyleNames="add"/>
      </div>
    </g:HTMLPanel>
    

**提示**:为了让 Polymer 处理您的样式块,请添加 is="custom-style" 属性。

**提示**:请查看 paper-fab 文档,了解可用的自定义样式属性和混合。

摘要

最后,您的 Main.ui.xml 文件应如下所示

<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
         xmlns:g='urn:import:com.google.gwt.user.client.ui'
         xmlns:p='urn:import:com.vaadin.polymer.paper.widget'
         xmlns:i='urn:import:com.vaadin.polymer.iron.widget'>

  <ui:style>
    paper-icon-item {
      position: relative;
      overflow: hidden;
    }
    .toolbar {
       background: #4285f4 !important;
    }
    .header {
       font-size: 200%;
       margin-left: 50px;
    }
    .content {
       padding: 15px;
    }
  </ui:style>

  <g:HTMLPanel>
    <style is='custom-style'>
      .add {
        position: absolute;
        bottom: 20px;
        right: 20px;
        --paper-fab-background: var(--paper-red-500);
      }
    </style>
    <p:PaperDrawerPanel ui:field="drawerPanel">
       <div drawer="">
          <p:PaperHeaderPanel mode="seamed">
             <p:PaperToolbar addStyleNames="{style.toolbar}"/>
             <p:PaperIconItem ui:field="menuClearAll">
               <i:IronIcon icon="delete" attributes="item-icon"/>
               <div>Clear All</div>
               <p:PaperRipple/>
             </p:PaperIconItem>
             <p:PaperIconItem ui:field="menuClearDone">
               <i:IronIcon icon="clear" attributes="item-icon"/>
               <div>Clear Done</div>
               <p:PaperRipple/>
             </p:PaperIconItem>
             <p:PaperIconItem ui:field="menuSettings">
               <i:IronIcon icon="settings" attributes="item-icon"/>
               <div>Settings</div>
               <p:PaperRipple/>
             </p:PaperIconItem>
             <p:PaperIconItem ui:field="menuAbout">
               <i:IronIcon icon="help" attributes="item-icon"/>
               <div>About</div>
               <p:PaperRipple/>
             </p:PaperIconItem>
          </p:PaperHeaderPanel>
       </div>
       <div main="">
          <p:PaperHeaderPanel mode="seamed">
            <p:PaperToolbar addStyleNames="{style.toolbar}">
              <p:PaperIconButton ui:field="menu" icon="more-vert"
                                 attributes="paper-drawer-toggle"/>
              <span class="{style.header}">Todo List</span>
            </p:PaperToolbar>
            <g:HTMLPanel ui:field="content"
                         addStyleNames="{style.content} vertical center-justified layout"/>
          </p:PaperHeaderPanel>
          <p:PaperFab ui:field="addButton" icon="add"
                      addStyleNames="add"/>
       </div>
    </p:PaperDrawerPanel>
  </g:HTMLPanel>
</ui:UiBinder>

如果一切正常,重新加载后,您的应用程序应如下所示

下一步

  1. 我们已经学习了如何使用 UiBinder 创建新的窗口小部件。
  2. 我们可以将第三方窗口小部件添加到我们的 UI 中。
  3. 我们了解了导入 Polymer 元素(如图标集合)的机制,以及如何使用提供视觉效果的特殊组件。
  4. 我们可以使用 Paper 面板创建响应式布局,并且了解了如何在与传统的 GWT 小部件配合使用时使用它们。
  5. 我们了解了如何在 UiBinder XML 文件中使用 GSS 或 Polymer 解析器设置元素的样式。

步骤 3a:将事件逻辑添加到应用程序

免责声明