3.5.10.2. 使用其它字体库中的图标

为了增强主题扩展,可能需要创建图标并将其嵌入到字体中,以及使用一些外部图标库。

  1. web 模块中,为新图标创建实现 com.vaadin.server.FontIcon 接口的 enum 类:

    1. import com.vaadin.server.FontIcon;
    2. import com.vaadin.server.GenericFontIcon;
    3. public enum IcoMoon implements FontIcon {
    4. HEADPHONES(0XE900),
    5. SPINNER(0XE905);
    6. public static final String FONT_FAMILY = "IcoMoon";
    7. private int codepoint;
    8. IcoMoon(int codepoint) {
    9. this.codepoint = codepoint;
    10. }
    11. @Override
    12. public String getFontFamily() {
    13. return FONT_FAMILY;
    14. }
    15. @Override
    16. public int getCodepoint() {
    17. return codepoint;
    18. }
    19. @Override
    20. public String getHtml() {
    21. return GenericFontIcon.getHtml(FONT_FAMILY, codepoint);
    22. }
    23. @Override
    24. public String getMIMEType() {
    25. throw new UnsupportedOperationException(FontIcon.class.getSimpleName()
    26. + " should not be used where a MIME type is needed.");
    27. }
    28. public static IcoMoon fromCodepoint(final int codepoint) {
    29. for (IcoMoon f : values()) {
    30. if (f.getCodepoint() == codepoint) {
    31. return f;
    32. }
    33. }
    34. throw new IllegalArgumentException("Codepoint " + codepoint
    35. + " not found in IcoMoon");
    36. }
    37. }
  2. 向主题扩展添加新样式。建议在主题扩展的主文件夹中创建一个特定的子文件夹 fonts,例如 modules/web/themes/halo/com.company.demo/fonts。将样式和字体文件放在特有的子文件夹中,例如 fonts/icomoon

    字体文件由以下扩展名表示:

    • .eot,

    • .svg,

    • .ttf,

    • .woff.

      本例中使用了一个开源字体集 icomoon,由 4 个联合使用的文件组成:icomoon.eoticomoon.svgicomoon.ttficomoon.woff

  1. 创建一个包含 @font-face 样式和一个图标样式 CSS 类的文件。下面是 icomoon.scss 文件的示例,其中 IcoMoon css 类名对应于 FontIcon#getFontFamily 方法返回的值:

    1. @mixin icomoon-style {
    2. /* use !important to prevent issues with browser extensions that change fonts */
    3. font-family: 'icomoon' !important;
    4. speak: none;
    5. font-style: normal;
    6. font-weight: normal;
    7. font-variant: normal;
    8. text-transform: none;
    9. line-height: 1;
    10. /* Better Font Rendering =========== */
    11. -webkit-font-smoothing: antialiased;
    12. -moz-osx-font-smoothing: grayscale;
    13. }
    14. @font-face {
    15. font-family: 'icomoon';
    16. src:url('icomoon.eot?hwgbks');
    17. src:url('icomoon.eot?hwgbks#iefix') format('embedded-opentype'),
    18. url('icomoon.ttf?hwgbks') format('truetype'),
    19. url('icomoon.woff?hwgbks') format('woff'),
    20. url('icomoon.svg?hwgbks#icomoon') format('svg');
    21. font-weight: normal;
    22. font-style: normal;
    23. }
    24. .IcoMoon {
    25. @include icomoon-style;
    26. }
  2. halo-ext.scss 文件或其它主题扩展文件中添加对上述包含字体样式的文件的引用。

    1. @import "fonts/icomoon/icomoon";
  3. 然后创建新的图标集,这是一个实现 Icons.Icon 接口的枚举:

    1. import com.haulmont.cuba.gui.icons.Icons;
    2. public enum IcoMoonIcon implements Icons.Icon {
    3. HEADPHONES("ico-moon:HEADPHONES"),
    4. SPINNER("ico-moon:SPINNER");
    5. protected String source;
    6. IcoMoonIcon(String source) {
    7. this.source = source;
    8. }
    9. @Override
    10. public String source() {
    11. return source;
    12. }
    13. }
  4. 创建新的 IconProvider.

    为了管理自定义图标集,CUBA 框架提供了由 IconProviderIconResolver 组成的机制。

    IconProvider 是一个标记接口,只存在于 web 模块中,可以通过图标路径提供资源(com.vaadin.server.Resource)。

    IconResolver bean 获取实现 IconProvider 接口的所有 bean,并遍历它们以找到可以为图标提供资源的 bean。

    要使用这种机制,应该创建 IconProvider 的实现:

    1. import com.haulmont.cuba.web.gui.icons.IconProvider;
    2. import com.vaadin.server.Resource;
    3. import org.slf4j.Logger;
    4. import org.slf4j.LoggerFactory;
    5. import org.springframework.stereotype.Component;
    6. @Order(10)
    7. @Component
    8. public class IcoMoonIconProvider implements IconProvider {
    9. private final Logger log = LoggerFactory.getLogger(IcoMoonIconProvider.class);
    10. @Override
    11. public Resource getIconResource(String iconPath) {
    12. Resource resource = null;
    13. iconPath = iconPath.split(":")[1];
    14. try {
    15. resource = ((Resource) IcoMoon.class
    16. .getDeclaredField(iconPath)
    17. .get(null));
    18. } catch (IllegalAccessException | NoSuchFieldException e) {
    19. log.warn("There is no icon with name {} in the FontAwesome icon set", iconPath);
    20. }
    21. return resource;
    22. }
    23. @Override
    24. public boolean canProvide(String iconPath) {
    25. return iconPath.startsWith("ico-moon:");
    26. }
    27. }

    这里我们用 @Order annotation 注解显式地为这个 bean 指定顺序。

  5. 在应用程序属性文件中注册自定义图标集:

    1. cuba.iconsConfig = +com.company.demo.gui.icons.IcoMoonIcon

现在,在界面 XML 描述中可以直接引用图标的类和 枚举 元素 :

  1. <button caption="Headphones" icon="ico-moon:HEADPHONES"/>

或者在 Java 控制器中:

  1. spinnerBtn.setIconFromSet("ico-moon:SPINNER");

这样新图标会添加到按钮上:

add icons

覆盖图标集的图标

图标集机制可以覆盖其它图标集中的图标。为此,应该创建并注册一个具有相同图标(枚举值)但不同图标路径(source)的新图标集(枚举)。在下面的示例中,创建了一个新的图标枚举 MyIcon ,用于覆盖 CubaIcon 图标集中的标准图标。

  1. 默认图标集:

    1. public enum CubaIcon implements Icons.Icon {
    2. OK("font-icon:CHECK"),
    3. CANCEL("font-icon:BAN"),
    4. ...
    5. }
  2. 新图标集:

    1. public enum MyIcon implements Icons.Icon {
    2. OK("icons/my-custom-ok.png"),
    3. ...
    4. }
  3. web-app.properties 中注册的新图标集:

    1. cuba.iconsConfig = +com.company.demo.gui.icons.MyIcon

现在,新的 OK 图标将代替标准图标而被使用:

  1. Icons icons = AppBeans.get(Icons.NAME);
  2. button.setIcon(icons.getIcon(CubaIcon.OK))

如果需要忽略重新定义的图标,仍然可以通过使用标准图标的路径而不是选项名称来使用标准图标:

  1. <button caption="Created" icon="icons/create.png"/>

或者

  1. button.setIcon(CubaIcon.CREATE_ACTION.source());