自定義導(dǎo)航欄(10.1.68)
Nebula 容器可支持自定義導(dǎo)航欄,您可以制定導(dǎo)航欄的樣式,例如標題的位置、返回按鈕的樣式等。本文將向您介紹如何在 10.1.68 基線中自定義導(dǎo)航欄。
前提條件
在完整閱讀此指南前,需提前知曉以下四點:
由于小程序和 H5 共用導(dǎo)航欄的實現(xiàn),在進行自定義導(dǎo)航欄的開發(fā)時應(yīng)將 H5 和小程序使用導(dǎo)航欄的情況都考慮在內(nèi),除非確定使用場景不包含小程序或 H5。
自定義導(dǎo)航欄 必須符合容器調(diào)用的標準流程,請仔細閱讀本文檔并按照要求進行開發(fā)。
小程序?qū)Ш綑谀J使用內(nèi)置導(dǎo)航欄,如需開啟自定義導(dǎo)航欄,詳情請參考 容器配置。
由于導(dǎo)航欄的顏色可以動態(tài)設(shè)置,為達到最佳體驗效果,您應(yīng)當準備 兩套主題配置 并根據(jù)不同場景進行切換。
接入步驟
繼承 AbsTitleView 抽象類并實現(xiàn)自定義導(dǎo)航欄。
實現(xiàn)
H5ViewProvider
,在createTitleView
方法中創(chuàng)建并返回自定義導(dǎo)航欄實例。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; } }
在合適的地方,比如應(yīng)用啟動時,設(shè)置
H5ViewProvider
至容器。MPNebula.setCustomViewProvider(new H5ViewProviderImpl());
如果工程是基于 Portal&Bundle 架構(gòu),需額外設(shè)置。
H5Utils.setProvider(H5ReplaceResourceProvider.class.getName(), new H5ReplaceResourceProvider() { @Override public String getReplaceResourcesBundleName() { return BuildConfig.BUNDLE_NAME; } });
更多擴展
背景色
resetTitle 一般在前端頁面調(diào)用 setTitleColor 的 JSAPI 時被觸發(fā)。這種情況下,建議您將導(dǎo)航欄的背景以及其他后續(xù)提及組件的色值等顯示元素重置為默認元素。
/**
* 返回導(dǎo)航欄背景顏色值
* @return
*/
public abstract int getBackgroundColor();
/**
* 設(shè)置導(dǎo)航欄透明度
* @param alpha
*/
public abstract void setBackgroundAlphaValue(int alpha);
/**
* 設(shè)置導(dǎo)航欄背景色,不含 alpha 值
* @param color
*/
public abstract void setBackgroundColor(int color);
/**
* 重置導(dǎo)航欄
*/
public abstract void resetTitle();
標題
副標題當前僅在 H5 場景中支持,如應(yīng)用不需要副標題,可以不提供副標題實現(xiàn)。
為了使 H5 頁面能夠監(jiān)聽 點擊標題欄事件,導(dǎo)航欄應(yīng)該在合適的地方調(diào)用 invokeTitleClickEvent
方法;監(jiān)聽 點擊副標題欄事件,則調(diào)用 invokeSubTitleClickEvent
方法。
/**
* 返回主標題文本
* @return
*/
public abstract String getTitle();
/**
* 設(shè)置主標題文本
* @param title
*/
public abstract void setTitle(String title);
/**
* 設(shè)置副標題文本
* @param subTitle
*/
public abstract void setSubTitle(String subTitle);
/**
* 返回主標題視圖
* @return
*/
public abstract TextView getMainTitleView();
/**
* 返回副標題視圖
* @return
*/
public abstract TextView getSubTitleView();
左側(cè)控制區(qū)
/**
* 設(shè)置關(guān)閉按鈕可見性
* @param visible
*/
public abstract void showCloseButton(boolean visible);
/**
* 設(shè)置返回按鈕可見性
* @param visible
*/
public abstract void showBackButton(boolean visible);
/**
* 設(shè)置去首頁按鈕可見性
* @param visible
*/
public abstract void showBackHome(boolean visible);
/**
* 設(shè)置標題欄加載提示符可見性
* @param visible
*/
public abstract void showTitleLoading(boolean visible);
關(guān)閉按鈕
如上圖紅框區(qū)域中所顯示,關(guān)閉按鈕僅出現(xiàn)在 H5 場景中,當在線頁面的歷史(即瀏覽器歷史頁面數(shù))大于 1 時,容器會調(diào)用 showCloseButton
方法來控制其可見性。此按鈕被點擊時必須調(diào)用 invokePageCloseEvent
方法以符合容器行為規(guī)范。
返回按鈕
上圖紅框區(qū)域中的返回按鈕是 必須 要在自定義導(dǎo)航欄上實現(xiàn)的控件,容器調(diào)用 showBackButton
方法控制其可見性。響應(yīng)返回按鈕點擊時,開發(fā)者必須調(diào)用 invokePageBackEvent
方法以符合容器行為規(guī)范。
去首頁按鈕
去首頁按鈕僅在小程序場景下使用,當跳轉(zhuǎn)小程序的非首頁頁面時,容器會調(diào)用 showBackHome
方法控制其可見性。響應(yīng)按鈕點擊事件時,開發(fā)者必須調(diào)用 invokeHomeClickEvent
方法以符合容器行為規(guī)范。
加載提示符
當 H5 頁面或者小程序調(diào)用導(dǎo)航欄加載動畫 API 時,容器會調(diào)用 showTitleLoading
方法控制其可見性。
右側(cè)控制區(qū)
右側(cè)控制區(qū),也可稱為 OptionMenu
控制區(qū),主要用于提供更多操作給用戶。
H5 容器:
小程序:
由上圖可見,開發(fā)者需要為 OptionMenu
控制區(qū)預(yù)留兩個視圖區(qū)域,容器操作時會按照索引來操作這兩塊區(qū)域,從右至左,從 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);
容器通過調(diào)用 showOptionMenu
方法來控制 OptionMenu
區(qū)域可見性,在某些情況也需要獲取該區(qū)域的視圖進行操作,開發(fā)者需要正確實現(xiàn) getOptionMenuContainer
方法。
實現(xiàn) setOptionMenu
方法,請參考 設(shè)置右上角按鈕 API 入?yún)⑦M行合理的實現(xiàn)。icontype
為內(nèi)置按鈕樣式,僅在 H5 場景中可用,如果接入場景中不會用到則可忽略,否則需要為不同類型配置相應(yīng)的按鈕。redDot
與 icontype
類似,可以選擇性接入。
為了使 H5 頁面或小程序監(jiān)聽右上角按鈕點擊事件,開發(fā)者需要調(diào)用 invokeOptionClickEvent
方法。
在小程序場景下:
setOptionMenu
方法的isTinyApp
參數(shù)值必定為true
,以此區(qū)分 H5 和小程序場景。必須從 最右側(cè)倒數(shù)第二個 按鈕開始設(shè)置按鈕。
小程序右上角控制區(qū)
當處于小程序場景時,最右側(cè)區(qū)域需要特殊實現(xiàn),步驟如下:
繼承
AbsTinyOptionMenuView
抽象類實現(xiàn)自定義控制區(qū)。在合適的地方,比如應(yīng)用啟動時,設(shè)置
TinyOptionMenuViewProvider
至容器。H5Utils.setProvider(TinyOptionMenuViewProvider.class.getName(), new TinyOptionMenuViewProvider() { @Override public AbsTinyOptionMenuView createView(Context context) { return new TinyOptionMenuView(context); } });
按照容器規(guī)范要求,開發(fā)者必須實現(xiàn)和配置 更多 和 關(guān)閉 按鈕視圖。
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();
容器會調(diào)用上方代碼中的前三個方法來設(shè)置合理的響應(yīng)回調(diào),開發(fā)者必須讓指定的視圖設(shè)置該響應(yīng)回調(diào)。
onStateChanged
方法在定位、藍牙場景中會被調(diào)用,舉例來說,當小程序正在使用定位服務(wù)的時,容器會調(diào)用此方法,開發(fā)者可作出響應(yīng),下面是樣式效果。
簡單示例代碼:
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 應(yīng)用可能會設(shè)置不同的導(dǎo)航欄背景色,考慮到用戶體驗,在導(dǎo)航欄背景色發(fā)生變化的時候,也需要對導(dǎo)航欄上的其他元素進行調(diào)整,比如右上角控制區(qū)。
在導(dǎo)航欄的擴展上,右上角控制區(qū)和導(dǎo)航欄分別為不同的組件,所以我們提供接口來方便開發(fā)者能夠讓右上角控制區(qū)能夠及時響應(yīng)導(dǎo)航欄的變化。
AbsTinyOptionMenuView
提供onTitleChanged
方法供 override 來響應(yīng)導(dǎo)航欄變化。當此方法被調(diào)用時,可通過傳入H5TitleView 對象來獲取導(dǎo)航欄的信息,如背景色。也可以使用AbsTinyOptionMenuView
提供的getTitleBar
方法直接獲取導(dǎo)航欄對象。另外,您可以將 H5TitleView 轉(zhuǎn)換成自己實現(xiàn)的導(dǎo)航欄對象,因為AbsTitleView
實現(xiàn)了H5TitleView
接口類,這樣能夠獲得更多的導(dǎo)航欄信息。protected void onTitleChange(H5TitleView title)
您需要主動調(diào)用
AbsTitleView
提供的notifyTitleBarChanged
方法觸發(fā)onTitleChange
被調(diào)用,比如在對導(dǎo)航欄對象設(shè)置背景色時。舉例說明: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(); } }
上述示例代碼調(diào)用
notifyTitleBarChange
方法時,AbsTinyOptionMenuView
的子類對象可能并沒有初始化完畢,因此建議覆寫setH5Page
方法,獲取導(dǎo)航欄信息并判定當前主題,示例如下: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); } } }