在 10.1.60 基準下,如果有自訂 H5 容器標題列的需求,可參考下方範例程式碼:
H5TitleViewImpl.java
package com.mpaas.demo.nebula;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alipay.mobile.h5container.api.H5Page;
import com.alipay.mobile.h5container.api.H5Param;
import com.alipay.mobile.h5container.api.H5Plugin;
import com.alipay.mobile.nebula.util.H5Log;
import com.alipay.mobile.nebula.util.H5StatusBarUtils;
import com.alipay.mobile.nebula.util.H5Utils;
import com.alipay.mobile.nebula.view.H5TitleBarFrameLayout;
import com.alipay.mobile.nebula.view.H5TitleView;
import com.alipay.mobile.nebula.view.IH5TinyPopMenu;
import java.util.ArrayList;
import java.util.List;
/**
* Created by omg on 2018/7/23.
*/
public class H5TitleViewImpl implements H5TitleView, View.OnClickListener {
private static final String TAG = "H5TitleViewImpl";
private Context mContext;
private H5TitleBarFrameLayout contentView;
private String title;
// 此處定義標題列的基本控制項
private TextView mTitleView;
private TextView mSubTitleView;
private View mCloseButton;
private View mBackButton;
private View vDivider;
private View hDivider;
private View statusBarAdjustView;
/**
* ==== OptionMenu的各種View Start ====
*/
// OptionMenu的Container
public View h5NavOptions;
public View h5NavOptions1;
public List<View> h5NavOptionsList = new ArrayList<View>();
// ---- OptionMenu 三種形態 Start ---- //
// 1. OptionType.MENU(預設) -預設的 Option 按鈕
public TextView btMenu;
public TextView btMenu1;
public List<TextView> btMenuList = new ArrayList<TextView>();
// 2. OptionType.ICON - 通過 setOptionMenu 手動設定的 icon
public ImageButton btIcon;
public ImageButton btIcon1;
public List<ImageButton> btIconList = new ArrayList<ImageButton>();
// 3. OptionType.TEXT - 文字
public TextView btText;
public TextView btText1;
public List<TextView> btTextList = new ArrayList<TextView>();
// ---- OptionMenu 三種形態 Over ---- //
// Web 頁面的執行個體介面類,可用於控制 web 行為
private H5Page h5Page;
private int visibleOptionNum = 0;
private IH5TinyPopMenu h5TinyPopMenu;
/**
* H5 容器標題列構造方法
* 注意:標題列布局 xml 檔案必須以 H5TitleBarFrameLayout 作為根節點
* @param context
*/
public H5TitleViewImpl(Context context) {
mContext = context;
ViewGroup parent = null;
if (context instanceof Activity) {
parent = (ViewGroup) ((Activity) mContext).findViewById(android.R.id.content);
}
contentView = (H5TitleBarFrameLayout) LayoutInflater.from(context).inflate(R.layout.h5_navigation_bar, parent, false);
contentView.getContentBgView().setColor(context.getResources().getColor(R.color.h5_default_titlebar_color));
mTitleView = (TextView) contentView.findViewById(R.id.h5_tv_title);
mTitleView.setOnClickListener(this);
mSubTitleView = (TextView) contentView.findViewById(R.id.h5_tv_subtitle);
mSubTitleView.setOnClickListener(this);
mCloseButton = contentView.findViewById(R.id.h5_nav_close);
mCloseButton.setOnClickListener(this);
mBackButton = contentView.findViewById(R.id.h5_tv_nav_back);
mBackButton.setOnClickListener(this);
vDivider = contentView.findViewById(R.id.h5_v_divider);
hDivider = contentView.findViewById(R.id.h5_h_divider_intitle);
h5NavOptions = contentView.findViewById(R.id.h5_nav_options);
h5NavOptions1 = contentView.findViewById(R.id.h5_nav_options1);
statusBarAdjustView = contentView.findViewById(R.id.h5_status_bar_adjust_view);
btIcon = (ImageButton) contentView.findViewById(R.id.h5_bt_image);
btText = (TextView) contentView.findViewById(R.id.h5_bt_text);
btMenu = (TextView) contentView.findViewById(R.id.h5_bt_options);
btIcon1 = (ImageButton) contentView.findViewById(R.id.h5_bt_image1);
btText1 = (TextView) contentView.findViewById(R.id.h5_bt_text1);
btMenu1 = (TextView) contentView.findViewById(R.id.h5_bt_options1);
//add view to list
h5NavOptionsList.add(h5NavOptions);
h5NavOptionsList.add(h5NavOptions1);
btIconList.add(btIcon);
btIconList.add(btIcon1);
btTextList.add(btText);
btTextList.add(btText1);
btMenuList.add(btMenu);
btMenuList.add(btMenu1);
btText.setOnClickListener(this);
btIcon.setOnClickListener(this);
btText1.setOnClickListener(this);
btIcon1.setOnClickListener(this);
btMenu.setOnClickListener(this);
btMenu1.setOnClickListener(this);
}
/**
* 容器調用此方法獲得主標題內容
*/
@Override
public String getTitle() {
return title;
}
/**
* 容器調用此方法設定主標題內容
*/
@Override
public void setTitle(String s) {
title = s;
mTitleView.setText(s);
}
/**
* 容器調用此方法設定副標題內容
*/
@Override
public void setSubTitle(String s) {
mSubTitleView.setVisibility(View.VISIBLE);
mSubTitleView.setText(s);
}
/**
* 暫時忽略,可不實現
*/
@Override
public void setImgTitle(Bitmap bitmap) {
}
/**
* 暫時忽略,可不實現
*/
@Override
public void setImgTitle(Bitmap bitmap, String s) {
}
/**
* 容器設定是否顯示關閉按鈕
*/
@Override
public void showCloseButton(boolean b) {
mCloseButton.setVisibility(b ? View.VISIBLE : View.GONE);
}
/**
* 容器擷取標題列 View
*/
@Override
public View getContentView() {
return contentView;
}
/**
* 容器擷取標題列背景用於設定背景色
*/
@Override
public ColorDrawable getContentBgView() {
return contentView.getContentBgView();
}
/**
* 容器擷取主標題 View
* 不可為空白
*/
@Override
public TextView getMainTitleView() {
return mTitleView;
}
/**
* 容器擷取副標題 View
* 不可為空白
*/
@Override
public TextView getSubTitleView() {
return mSubTitleView;
}
/**
* 設定是否展示返回按鈕
*/
@Override
public void showBackButton(boolean b) {
mBackButton.setVisibility(b ? View.VISIBLE : View.GONE);
}
/**
* 設定是否顯示右上方功能表項目
*/
@Override
public void showOptionMenu(boolean isShow) {
if (isShow) {
switch (visibleOptionNum) {
case 1:
h5NavOptions.setVisibility(View.VISIBLE);
break;
case 2:
h5NavOptions.setVisibility(View.VISIBLE);
h5NavOptions1.setVisibility(View.VISIBLE);
break;
}
} else {
h5NavOptions.setVisibility(View.GONE);
h5NavOptions1.setVisibility(View.GONE);
}
}
/**
* 設定右上方功能表項目展示類型,可為表徵圖、文字
*/
@Override
public void setOptionType(H5Param.OptionType optionType) {
setOptionType(optionType, 0, true);
}
/**
* 設定右上方功能表項目展示類型,可為表徵圖、文字
* @param byIndex 是否只對某個功能表項目設定展示類型
*/
@Override
public void setOptionType(H5Param.OptionType type, int num, boolean byIndex) {
boolean icon = false;
boolean text = false;
boolean menu = false;
if (type == H5Param.OptionType.ICON) {
icon = true;
} else if (type == H5Param.OptionType.TEXT) {
text = true;
} else if (type == H5Param.OptionType.MENU) {
menu = true;
}
ctrlbtText(num, text ? View.VISIBLE : View.GONE, byIndex);
ctrlbtIcon(num, icon ? View.VISIBLE : View.INVISIBLE, byIndex);
ctrlbtMenu(num, menu ? View.VISIBLE : View.INVISIBLE, byIndex);
}
//view visible control
private boolean isOutOfBound(int num, int length) {
if (length == 0) {
return true;
}
return length < num;
}
private void ctrlbtText(int num, int visible, boolean byIndex) {
if (isOutOfBound(num, btTextList.size())) {
return;
}
if (byIndex) {
btTextList.get(num).setVisibility(visible);
} else {
for (int i = 0; i < num; i++) {
btTextList.get(i).setVisibility(visible);
}
}
}
private void ctrlbtIcon(int num, int visible, boolean byIndex) {
if (isOutOfBound(num, btIconList.size())) {
return;
}
if (byIndex) {
btIconList.get(num).setVisibility(visible);
} else {
for (int i = 0; i < num; i++) {
btIconList.get(i).setVisibility(visible);
}
}
}
private void ctrlbtMenu(int num, int visible, boolean byIndex) {
if (isOutOfBound(num, btMenuList.size())) {
return;
}
if (byIndex) {
btMenuList.get(num).setVisibility(visible);
} else {
for (int i = 0; i < num; i++) {
btMenuList.get(i).setVisibility(visible);
}
}
}
/**
* 設定是否在標題列上顯示載入狀態,可選擇實現方式
*/
@Override
public void showTitleLoading(boolean b) {
}
/**
* 可忽略
*/
@Override
public void showTitleDisclaimer(boolean b) {
}
// 設定右上方按鈕表徵圖
@Override
public void setBtIcon(Bitmap btIcon, int index) {
if (isOutOfBound(index, btIconList.size())) {
return;
}
btIconList.get(index).setImageBitmap(btIcon);
}
@Override
public void setH5Page(H5Page h5Page) {
this.h5Page = h5Page;
}
/**
* 根據 JS 傳遞過來的參數設定右上方菜單
*/
@Override
public void setOptionMenu(JSONObject params) {
boolean reset = H5Utils.getBoolean(params, "reset", false);
boolean override = H5Utils.getBoolean(params, "override", false);
JSONArray menus = H5Utils.getJSONArray(params, "menus", null);
if (reset) {
h5NavOptions1.setVisibility(View.GONE);
setOptionType(H5Param.OptionType.MENU, 0, true);
visibleOptionNum = 1;
return;
}
if (menus != null && !menus.isEmpty()) {
visibleOptionNum = 0;
if (override) {
int menuSize = menus.size() > 2 ? 2 : menus.size();
for (int i = 0; i < menuSize; i++) {
// h5NavOptionsList.get(i).setVisibility(View.VISIBLE);
JSONObject menusItem = menus.getJSONObject(i);
setOptionMenuInternal(menusItem, i);
visibleOptionNum++;
}
} else {
visibleOptionNum = 2;
// h5NavOptionsList.get(1).setVisibility(View.VISIBLE);
JSONObject menusItem = menus.getJSONObject(0);
setOptionMenuInternal(menusItem, 1);
}
} else {
setOptionMenuInternal(params, 0);
visibleOptionNum = 1;
}
}
private void setOptionMenuInternal(JSONObject params, int index) {
String title = H5Utils.getString(params, "title");
String icon = H5Utils.getString(params, "icon");
String icontype = H5Utils.getString(params, "icontype");
String contentDesc = H5Utils.getString(params, "contentDesc");
String colorText = H5Utils.getString(params, "color");
// default white color
int color = 0xFF108ee9;
if (!TextUtils.isEmpty(colorText)) {
try {
color = Color.parseColor(colorText);
} catch (Throwable ignore) {
//can not find logutil
}
color = 0xFF000000 | color;
btTextList.get(index).setTextColor(color);
} else {
int currentColor = mTitleView.getCurrentTextColor();
currentColor = 0xFF000000 | currentColor;
H5Log.d(TAG, "setOptionMenuInternal currentColor is " + currentColor);
if (currentColor != 0xFF111111) {
btText.setTextColor(0xFFFFFFFF);
btText1.setTextColor(0xFFFFFFFF);
} else {
btText.setTextColor(0xFF108ee9);
btText1.setTextColor(0xFF108ee9);
}
}
if (!TextUtils.isEmpty(title)) {
title = title.trim();
btTextList.get(index).setText(title);
setOptionType(H5Param.OptionType.TEXT, index, true);
btTextList.get(index).setContentDescription(title);
} else if (!TextUtils.isEmpty(icon) || !TextUtils.isEmpty(icontype)) {
if (!TextUtils.isEmpty(contentDesc)) {
btIconList.get(index).setContentDescription(contentDesc);
}
}
}
/**
* 容器擷取返回按鈕和標題內容之間的分割線
* 可返回空
*/
@Override
public View getDivider() {
return vDivider;
}
/**
* 容器擷取標題列和 Web 頁面間的分割線
* 不可為空白
*/
@Override
public View getHdividerInTitle() {
return hDivider;
}
/**
* 容器擷取下拉式功能表彈出位置的錨點 View
*/
@Override
public View getPopAnchor() {
return btMenu;
}
/**
* 容器重設標題列背景色
*/
@Override
public void resetTitleColor(int color) {
}
/**
* 暫時忽略
*/
@Override
public void switchToWhiteTheme() {
}
/**
* 暫時忽略
*/
@Override
public void switchToBlueTheme() {
}
/**
* 容器頁面銷毀時觸發,此處可釋放被引用的 View
*/
@Override
public void releaseViewList() {
if (h5NavOptionsList != null) {
h5NavOptionsList.clear();
}
if (btIconList != null) {
btIconList.clear();
}
if (btTextList != null) {
btTextList.clear();
}
if (btMenuList != null) {
btMenuList.clear();
}
}
/**
* 容器設定沈浸式標題列顏色
*/
@Override
public void openTranslucentStatusBarSupport(int color) {
if (H5StatusBarUtils.isSupport()) {
int statusBarHeight = H5StatusBarUtils.getStatusBarHeight(mContext);
if (statusBarHeight == 0) { //保護,萬一有 rom 沒辦法拿到狀態列高度的話,則在這裡不生效。
return;
}
LinearLayout.LayoutParams layoutParams =
(LinearLayout.LayoutParams) statusBarAdjustView.getLayoutParams();
layoutParams.height = statusBarHeight;
statusBarAdjustView.setLayoutParams(layoutParams);
statusBarAdjustView.setVisibility(View.VISIBLE);
try {
H5StatusBarUtils.setTransparentColor((Activity) mContext, color);
} catch (Exception e) {
H5Log.e(TAG, e);
}
}
}
/**
* 暫時忽略
*/
@Override
public void switchToTitleBar() {
}
/**
* 暫時忽略
*/
@Override
public View setTitleBarSearch(Bundle bundle) {
return null;
}
/**
* 暫時忽略
*/
@Override
public void setBackCloseBtnImage(String s) {
}
/**
* 設定標題列字型顏色
*/
@Override
public void setTitleTxtColor(int i) {
mTitleView.setTextColor(i);
mSubTitleView.setTextColor(i);
}
/**
* 容器擷取右上方菜單 View, 必須是 ViewGroup 及子類
*/
@Override
public View getOptionMenuContainer() {
return h5NavOptions;
}
/**
* 容器根據位置擷取右上方菜單 View,必須是 ViewGroup 及子類
*/
@Override
public View getOptionMenuContainer(int index) {
switch (index) {
case 0:
return h5NavOptions;
case 1:
return h5NavOptions1;
default:
return getOptionMenuContainer();
}
}
/**
* 暫時忽略
*/
@Override
public void setIH5TinyPopMenu(IH5TinyPopMenu tinyPopMenu) {
this.h5TinyPopMenu = tinyPopMenu;
}
/**
* 暫時忽略
*/
@Override
public IH5TinyPopMenu getH5TinyPopMenu() {
return null;
}
/**
* 暫時忽略
*/
@Override
public void setTitleView(View view) {
}
/**
* 暫時忽略
*/
@Override
public void initTitleSegControl(JSONObject jsonObject) {
}
/**
* 暫時忽略
*/
@Override
public void enableTitleSegControl(boolean b) {
}
/**
* 暫時忽略
*/
@Override
public void enableBackButtonBackground(boolean b) {
}
/**
* 處理標題列上不同控制項的點擊事件
* 如果 JS 需要收到事件,需按照該代碼中呈現的方式發送事件給 JS
* 比如點擊返回按鈕,則發送 H5Plugin.CommonEvents.H5_TOOLBAR_BACK 事件
*/
@Override
public void onClick(View view) {
if (h5Page == null) {
return ;
}
String eventName = null;
JSONObject data = null;
if (view == mBackButton) {
eventName = H5Plugin.CommonEvents.H5_TOOLBAR_BACK; // 發送後退事件
} else if (view == mCloseButton) {
eventName = H5Plugin.CommonEvents.H5_TOOLBAR_CLOSE; // 發送關閉頁面事件
}else if (view.equals(btIcon) || view.equals(btText)) {
eventName = H5Plugin.CommonEvents.H5_TITLEBAR_OPTIONS;
data = new JSONObject();
data.put("index", 0);
} else if (view.equals(btIcon1) || view.equals(btText1)) {
eventName = H5Plugin.CommonEvents.H5_TITLEBAR_OPTIONS;
data = new JSONObject();
data.put("index", 1);
} else if (view.equals(btMenu) || view.equals(btMenu1)) {
eventName = H5Plugin.CommonEvents.H5_TITLEBAR_OPTIONS;
data = new JSONObject();
data.put("fromMenu", true);
data.put("index", view.equals(btMenu) ? 0 : 1);
} else if (view.equals(mTitleView)) {
eventName = H5Plugin.CommonEvents.H5_TITLEBAR_TITLE;
} else if (view.equals(mSubTitleView)) {
eventName = H5Plugin.CommonEvents.H5_TITLEBAR_SUBTITLE;
}
if (!TextUtils.isEmpty(eventName)) {
h5Page.sendEvent(eventName, data);
}
}
}
h5_navigation_bar.xml
<?xml version="1.0" encoding="utf-8"?>
<com.alipay.mobile.nebula.view.H5TitleBarFrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/h5_title_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent">
<LinearLayout
android:id="@+id/h5_rl_title_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:orientation="vertical">
<View
android:id="@+id/h5_status_bar_adjust_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"/>
<RelativeLayout
android:id="@+id/h5_title_bar_layout"
android:layout_width="match_parent"
android:layout_height="48dp">
<ImageButton
android:id="@+id/h5_tv_nav_back"
android:layout_width="48dp"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:background="@android:color/transparent"
android:scaleType="centerInside"
android:padding="12dp"
android:src="@drawable/back"/>
<ImageButton
android:id="@+id/h5_nav_close"
android:layout_width="48dp"
android:layout_height="match_parent"
android:layout_centerVertical="true"
android:padding="12dp"
android:layout_marginLeft="-6dp"
android:layout_toRightOf="@+id/h5_tv_nav_back"
android:background="@android:color/transparent"
android:clickable="true"
android:scaleType="centerInside"
android:src="@drawable/close"/>
<View
android:id="@+id/h5_v_divider"
android:layout_width="0.7dp"
android:layout_height="24dp"
android:layout_centerVertical="true"
android:layout_gravity="center"
android:layout_marginRight="12dp"
android:layout_toRightOf="@+id/h5_nav_close"
tools:ignore="ContentDescription"/>
<RelativeLayout
android:id="@+id/h5_rl_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:gravity="center">
<LinearLayout
android:id="@+id/h5_ll_title"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/h5_tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:singleLine="true"
android:textColor="@android:color/white"
android:textSize="16dp" />
<ImageView
android:id="@+id/h5_tv_title_img"
android:layout_width="wrap_content"
android:layout_height="36dp"
android:scaleType="centerInside"
android:visibility="gone"/>
</FrameLayout>
<TextView
android:id="@+id/h5_tv_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textColor="@android:color/white"
android:textSize="12dp"
android:visibility="gone"
tools:visibility="visible" />
</LinearLayout>
</RelativeLayout>
<!-- optionmenu0-->
<FrameLayout
android:id="@+id/h5_nav_options"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginLeft="6dp">
<ImageButton
android:id="@+id/h5_bt_image"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_gravity="center|right"
android:layout_marginRight="12dp"
android:background="@android:color/transparent"
android:padding="4dp"
android:scaleType="fitCenter"
android:visibility="gone"/>
<TextView
android:id="@+id/h5_bt_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center|right"
android:layout_marginRight="12dp"
android:background="@null"
android:ellipsize="end"
android:maxLength="8"
android:singleLine="true"
android:textColor="#ffffff"
android:textSize="16dp"/>
<TextView
android:id="@+id/h5_bt_options"
android:layout_width="48dp"
android:layout_height="match_parent"
android:background="@null"
android:gravity="center"
android:textSize="23dp"
android:visibility="gone"
tools:visibility="gone" />
</FrameLayout>
<!-- optionmenu1-->
<FrameLayout
android:id="@+id/h5_nav_options1"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_centerVertical="true"
android:layout_marginLeft="6dp"
android:layout_toLeftOf="@id/h5_nav_options"
android:visibility="gone"
tools:visibility="visible">
<ImageButton
android:id="@+id/h5_bt_image1"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_gravity="center|right"
android:layout_marginRight="12dp"
android:background="@android:color/transparent"
android:padding="4dp"
android:scaleType="fitCenter"
android:visibility="gone"/>
<TextView
android:id="@+id/h5_bt_text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center|right"
android:layout_marginRight="12dp"
android:background="@null"
android:ellipsize="end"
android:maxLength="8"
android:singleLine="true"
android:textColor="#108ee9"
android:textSize="16dp"/>
</FrameLayout>
</RelativeLayout>
<View
android:id="@+id/h5_h_divider_intitle"
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@android:color/white"
android:visibility="gone"/>
</LinearLayout>
</com.alipay.mobile.nebula.view.H5TitleBarFrameLayout>