自定义导航栏(10.1.68)

Nebula 容器可支持自定义导航栏,您可以制定导航栏的样式,例如标题的位置、返回按钮的样式等。本文将向您介绍如何在 10.1.68 基线中自定义导航栏。

前提条件

在完整阅读此指南前,需提前知晓以下四点:

  • 由于小程序和 H5 共用导航栏的实现,在进行自定义导航栏的开发时应将 H5 和小程序使用导航栏的情况都考虑在内,除非确定使用场景不包含小程序或 H5。

  • 自定义导航栏 必须符合容器调用的标准流程,请仔细阅读本文档并按照要求进行开发。

  • 小程序导航栏默认使用内置导航栏,如需开启自定义导航栏,详情请参考 容器配置

  • 由于导航栏的颜色可以动态设置,为达到最佳体验效果,您应当准备 两套主题配置 并根据不同场景进行切换。

接入步骤

  1. 继承 AbsTitleView 抽象类并实现自定义导航栏。

  2. 实现 H5ViewProvider,在 createTitleView 方法中创建并返回自定义导航栏实例。

     public class H5ViewProviderImpl implements H5ViewProvider {
         @Override
         public H5TitleView createTitleView(Context context) {
             return new NewH5TitleViewImpl(context);
         }
    
         @Override
         public H5NavMenuView createNavMenu() {
             return null;
         }
    
         @Override
         public H5PullHeaderView createPullHeaderView(Context context, ViewGroup viewGroup) {
             return null;
         }
    
         @Override
         public H5WebContentView createWebContentView(Context context) {
             return null;
         }
     }
  3. 在合适的地方,比如应用启动时,设置 H5ViewProvider 至容器。

     MPNebula.setCustomViewProvider(new H5ViewProviderImpl());
  4. 如果工程是基于 Portal&Bundle 架构,需额外设置。

     H5Utils.setProvider(H5ReplaceResourceProvider.class.getName(), new H5ReplaceResourceProvider() {
         @Override
         public String getReplaceResourcesBundleName() {
             return BuildConfig.BUNDLE_NAME;
         }
     });

更多扩展

背景色

resetTitle 一般在前端页面调用 setTitleColor 的 JSAPI 时被触发。这种情况下,建议您将导航栏的背景以及其他后续提及组件的色值等显示元素重置为默认元素。

    /**
     * 返回导航栏背景颜色值
     * @return
     */
    public abstract int getBackgroundColor();

    /**
     * 设置导航栏透明度
     * @param alpha
     */
    public abstract void setBackgroundAlphaValue(int alpha);

    /**
     * 设置导航栏背景色,不含 alpha 值
     * @param color
     */
    public abstract void setBackgroundColor(int color);

    /**
     * 重置导航栏
     */
    public abstract void resetTitle();

标题

副标题当前仅在 H5 场景中支持,如应用不需要副标题,可以不提供副标题实现。

为了使 H5 页面能够监听 点击标题栏事件,导航栏应该在合适的地方调用 invokeTitleClickEvent 方法;监听 点击副标题栏事件,则调用 invokeSubTitleClickEvent 方法。

    /**
     * 返回主标题文本
     * @return
     */
    public abstract String getTitle();

    /**
     * 设置主标题文本
     * @param title
     */
    public abstract void setTitle(String title);

    /**
     * 设置副标题文本
     * @param subTitle
     */
    public abstract void setSubTitle(String subTitle);

    /**
     * 返回主标题视图
     * @return
     */
    public abstract TextView getMainTitleView();

    /**
     * 返回副标题视图
     * @return
     */
    public abstract TextView getSubTitleView();

左侧控制区

    /**
     * 设置关闭按钮可见性
     * @param visible
     */
    public abstract void showCloseButton(boolean visible);

    /**
     * 设置返回按钮可见性
     * @param visible
     */
    public abstract void showBackButton(boolean visible);

    /**
     * 设置去首页按钮可见性
     * @param visible
     */
    public abstract void showBackHome(boolean visible);

    /**
     * 设置标题栏加载提示符可见性
     * @param visible
     */
    public abstract void showTitleLoading(boolean visible);

关闭按钮

如上图红框区域中所显示,关闭按钮仅出现在 H5 场景中,当在线页面的历史(即浏览器历史页面数)大于 1 时,容器会调用 showCloseButton 方法来控制其可见性。此按钮被点击时必须调用 invokePageCloseEvent 方法以符合容器行为规范。

返回按钮

上图红框区域中的返回按钮是 必须 要在自定义导航栏上实现的控件,容器调用 showBackButton 方法控制其可见性。响应返回按钮点击时,开发者必须调用 invokePageBackEvent 方法以符合容器行为规范。

去首页按钮

去首页按钮仅在小程序场景下使用,当跳转小程序的非首页页面时,容器会调用 showBackHome 方法控制其可见性。响应按钮点击事件时,开发者必须调用 invokeHomeClickEvent 方法以符合容器行为规范。

加载提示符

当 H5 页面或者小程序调用导航栏加载动画 API 时,容器会调用 showTitleLoading 方法控制其可见性。

右侧控制区

右侧控制区,也可称为 OptionMenu 控制区,主要用于提供更多操作给用户。

  • H5 容器:

  • 小程序:

由上图可见,开发者需要为 OptionMenu 控制区预留两个视图区域,容器操作时会按照索引来操作这两块区域,从右至左,从 0 开始

    public abstract void showOptionMenu(boolean visible);

    public abstract View getOptionMenuContainer(int index);

    public abstract void setOptionMenu(boolean reset, boolean override, boolean isTinyApp, List<MenuData> menus);

容器通过调用 showOptionMenu 方法来控制 OptionMenu 区域可见性,在某些情况也需要获取该区域的视图进行操作,开发者需要正确实现 getOptionMenuContainer 方法。

实现 setOptionMenu 方法,请参考 设置右上角按钮 API 入参进行合理的实现。icontype 为内置按钮样式,仅在 H5 场景中可用,如果接入场景中不会用到则可忽略,否则需要为不同类型配置相应的按钮。redDoticontype 类似,可以选择性接入。

为了使 H5 页面或小程序监听右上角按钮点击事件,开发者需要调用 invokeOptionClickEvent 方法。

重要

在小程序场景下:

  • setOptionMenu 方法的 isTinyApp 参数值必定为 true,以此区分 H5 和小程序场景。

  • 必须从 最右侧倒数第二个 按钮开始设置按钮。

小程序右上角控制区

当处于小程序场景时,最右侧区域需要特殊实现,步骤如下:

  1. 继承 AbsTinyOptionMenuView 抽象类实现自定义控制区。

  2. 在合适的地方,比如应用启动时,设置 TinyOptionMenuViewProvider 至容器。

    H5Utils.setProvider(TinyOptionMenuViewProvider.class.getName(), new TinyOptionMenuViewProvider() {
     @Override
     public AbsTinyOptionMenuView createView(Context context) {
         return new TinyOptionMenuView(context);
     }
    });

按照容器规范要求,开发者必须实现和配置 更多关闭 按钮视图。

    public abstract void setOptionMenuOnClickListener(View.OnClickListener listener);

    public abstract void setCloseButtonOnClickListener(View.OnClickListener listener);

    public abstract void setCloseButtonOnLongClickListener(View.OnLongClickListener listener);

    public abstract void onStateChanged(TinyAppActionState currentState);

    public abstract View getView();

容器会调用上方代码中的前三个方法来设置合理的响应回调,开发者必须让指定的视图设置该响应回调。

onStateChanged 方法在定位、蓝牙场景中会被调用,举例来说,当小程序正在使用定位服务的时,容器会调用此方法,开发者可作出响应,下面是样式效果。

简单示例代码

public class TinyOptionMenuView extends AbsTinyOptionMenuView {

    private View container;

    private ImageView ivMore;

    private View ivClose;

    private Context context;

    public TinyOptionMenuView(Context context) {
        this.context = context;
        ViewGroup parent = null;
        if (context instanceof Activity) {
            parent = (ViewGroup) ((Activity) context).findViewById(android.R.id.content);
        }
        container = LayoutInflater.from(context).inflate(R.layout.layout_tiny_right, parent, false);
        ivClose = container.findViewById(R.id.close);
        ivMore = (ImageView) container.findViewById(R.id.more);

    }

    @Override
    public View getView() {
        return container;
    }

    @Override
    public void setOptionMenuOnClickListener(View.OnClickListener onClickListener) {
        ivMore.setOnClickListener(onClickListener);
    }

    @Override
    public void setCloseButtonOnClickListener(View.OnClickListener onClickListener) {
        ivClose.setOnClickListener(onClickListener);
    }

    @Override
    public void setCloseButtonOnLongClickListener(View.OnLongClickListener onLongClickListener) {
        ivClose.setOnLongClickListener(onLongClickListener);
    }

    @Override
    public void onStateChanged(TinyAppActionState state) {
        if (state == null) {
            ivMore.setImageDrawable(context.getResources().getDrawable(R.drawable.icon_more));
        } else if (state.getAction().equals(TinyAppActionState.ACTION_LOCATION)) {
            ivMore.setImageDrawable(context.getResources().getDrawable(R.drawable.icon_miniprogram_location));
        }
    }
}

主题变更

不同的小程序或 H5 应用可能会设置不同的导航栏背景色,考虑到用户体验,在导航栏背景色发生变化的时候,也需要对导航栏上的其他元素进行调整,比如右上角控制区。

在导航栏的扩展上,右上角控制区和导航栏分别为不同的组件,所以我们提供接口来方便开发者能够让右上角控制区能够及时响应导航栏的变化。

  • AbsTinyOptionMenuView 提供 onTitleChanged 方法供 override 来响应导航栏变化。当此方法被调用时,可通过传入H5TitleView 对象来获取导航栏的信息,如背景色。也可以使用 AbsTinyOptionMenuView 提供的 getTitleBar 方法直接获取导航栏对象。另外,您可以将 H5TitleView 转换成自己实现的导航栏对象,因为 AbsTitleView 实现了 H5TitleView 接口类,这样能够获得更多的导航栏信息。

      protected void onTitleChange(H5TitleView title)
  • 您需要主动调用 AbsTitleView 提供的 notifyTitleBarChanged 方法触发 onTitleChange 被调用,比如在对导航栏对象设置背景色时。举例说明:

      package com.mpaas.demo.nebula;
    
      public class NewH5TitleViewImpl extends AbsTitleView {
    
          @Override
          public void setBackgroundAlphaValue(int i) {
              content.getContentBgView().setAlpha(i);
              notifyTitleBarChanged();
          }
    
          @Override
          public void setBackgroundColor(int i) {
              content.getContentBgView().setColor(i);
              notifyTitleBarChanged();
          }
    
          @Override
          public void resetTitle() {
              content.getContentBgView().setColor(context.getResources().getColor(R.color.h5_default_titlebar_color));
              notifyTitleBarChanged();
          }
      }

    上述示例代码调用 notifyTitleBarChange 方法时,AbsTinyOptionMenuView 的子类对象可能并没有初始化完毕,因此建议覆写 setH5Page 方法,获取导航栏信息并判定当前主题,示例如下:

      public class TinyOptionMenuView extends AbsTinyOptionMenuView {
    
          @Override
          public void setH5Page(H5Page h5Page) {
              super.setH5Page(h5Page);
              // title becomes available from here.
              if (getTitleBar().getBackgroundColor() == -1) {
                  bgView.setBackgroundColor(Color.RED);
              }
          }
      }