优化 TitleBar 和 Index 页面

This commit is contained in:
2024-04-02 15:01:03 +08:00
parent c0854269a9
commit 99aaff6876
12 changed files with 396 additions and 72 deletions

View File

@@ -1,81 +1,121 @@
import { ComponentConst } from './ComponentConst'
export enum TitleBarMenuType{
/**
* 不显示
*/
None = 0,
/**
* 显示Icon
*/
Icon = 1,
/**
* 显示文本
*/
Text = 2
}
@Preview
@Component
export struct TitleBar {
@State barHeight: number = 48;
@State menuPadding: number = 8;
@Prop title: ResourceStr;
@State leftText: ResourceStr = "Back";
@State leftTextVisible: Visibility = Visibility.Hidden;
@State leftIconVisible: Visibility = Visibility.Visible;
@Prop barHeight: number = 48;
@Prop menuPadding: number = 8;
@State rightText: ResourceStr = "Menu";
@State rightTextVisible: Visibility = Visibility.Hidden;
@State rightIconVisible: Visibility = Visibility.Hidden;
@Prop leftText: ResourceStr = "";
@Prop leftIcon: Resource = $r("app.media.ic_chevron_left");
@Prop leftMenuType: TitleBarMenuType = TitleBarMenuType.Icon;
@State title: ResourceStr = "Title";
@State titleTextAlign: TextAlign = TextAlign.Start;
@State titleVisible: Visibility = Visibility.Visible;
@Prop rightText: ResourceStr = "";
@Prop rightIcon: Resource = $r("app.media.ic_close");
@Prop rightMenuType: TitleBarMenuType = TitleBarMenuType.Icon;
@Prop titleTextAlign: TextAlign = TextAlign.Start;
@Prop titleVisible: Visibility = Visibility.Visible;
onLeftClicked?: Function;
onRightClicked?: Function;
@Styles setWidthAndHeight() {
.height(this.barHeight).width(this.barHeight)
}
build() {
Row() {
RelativeContainer() {
Button() {
Stack() {
Text(this.leftText).textAlign(TextAlign.Center)
.width(this.barHeight).height(this.barHeight).textAlign(TextAlign.Center)
.visibility(this.leftTextVisible)
Image($r("app.media.ic_chevron_left"))
.width(this.barHeight).height(this.barHeight).padding(this.menuPadding)
.visibility(this.leftIconVisible)
if (this.leftMenuType != TitleBarMenuType.None) {
Button() {
if (this.leftMenuType == TitleBarMenuType.Icon) {
Image(this.leftIcon)
.setWidthAndHeight()
.padding(this.menuPadding)
} else {
Text(this.leftText)
.textAlign(TextAlign.Center)
.setWidthAndHeight()
}
}
}.backgroundColor(0xFFFFFF).type(ButtonType.Normal).stateEffect(true)
.onClick((event) => {
this.onLeftClicked?.(event);
}).alignRules({
top: {anchor: ComponentConst.ContainerId, align: VerticalAlign.Top},
left: {anchor: ComponentConst.ContainerId, align: HorizontalAlign.Start},
bottom: {anchor: ComponentConst.ContainerId, align: VerticalAlign.Bottom }
})
.id("left_menu")
Text(this.title).visibility(this.titleVisible).textAlign(this.titleTextAlign).margin({left: this.menuPadding})
.setWidthAndHeight()
.backgroundColor(0xFFFFFF)
.type(ButtonType.Normal)
.stateEffect(true)
.onClick((event) => {
this.onLeftClicked?.(event);
})
.alignRules({
top: { anchor: ComponentConst.ContainerId, align: VerticalAlign.Top},
left: { anchor: "left_menu", align: HorizontalAlign.End},
right: { anchor: "right_menu", align: HorizontalAlign.Start},
bottom: {anchor: ComponentConst.ContainerId, align: VerticalAlign.Bottom }
}).id("center_row")
top: { anchor: ComponentConst.ContainerId, align: VerticalAlign.Top },
left: { anchor: ComponentConst.ContainerId, align: HorizontalAlign.Start },
}).id("left_menu")
}
Stack(){
if (this.titleVisible == Visibility.Visible) {
Text(this.title)
.textAlign(this.titleTextAlign)
.margin({
left: this.leftMenuType != TitleBarMenuType.None ? this.barHeight : 0,
right: this.leftMenuType != TitleBarMenuType.None ? this.barHeight : 0
})
.padding({left: this.leftMenuType != TitleBarMenuType.None ? 0 : this.menuPadding})
.alignRules({
top: { anchor: ComponentConst.ContainerId, align: VerticalAlign.Top },
left: {
anchor: this.leftMenuType != TitleBarMenuType.None ? "left_menu" : ComponentConst.ContainerId,
align: HorizontalAlign.Start
},
right: {
anchor: this.leftMenuType != TitleBarMenuType.None ? "right_menu" : ComponentConst.ContainerId,
align: HorizontalAlign.End
},
bottom: { anchor: ComponentConst.ContainerId, align: VerticalAlign.Bottom }
})
.id("title")
}
if (this.rightMenuType != TitleBarMenuType.None) {
Button() {
Image($r("app.media.ic_close"))
.width(this.barHeight).height(this.barHeight)
.padding(this.menuPadding)
}.backgroundColor(0xFFFFFF).type(ButtonType.Normal).stateEffect(true).visibility(this.rightIconVisible)
if (this.rightMenuType == TitleBarMenuType.Icon) {
Image(this.rightIcon)
.setWidthAndHeight().padding(this.menuPadding)
} else {
Text(this.rightText)
.textAlign(TextAlign.Center)
.setWidthAndHeight()
}
}
.setWidthAndHeight()
.backgroundColor(0xFFFFFF)
.type(ButtonType.Normal)
.stateEffect(true)
.onClick((event) => {
this.onRightClicked?.(event);
});
Button() {
Text(this.rightText).textAlign(TextAlign.Center)
.width(this.barHeight).height(this.barHeight).textAlign(TextAlign.Center)
}.backgroundColor(0xFFFFFF).type(ButtonType.Normal).stateEffect(true).visibility(this.rightTextVisible)
.onClick((event) => {
this.onRightClicked?.(event);
});
}.alignRules({
top: {anchor: ComponentConst.ContainerId, align: VerticalAlign.Top},
right: {anchor: ComponentConst.ContainerId, align: HorizontalAlign.End},
bottom: {anchor: ComponentConst.ContainerId, align: VerticalAlign.Bottom }
})
.id("right_menu")
})
.alignRules({
top: { anchor: ComponentConst.ContainerId, align: VerticalAlign.Top },
right: { anchor: ComponentConst.ContainerId, align: HorizontalAlign.End },
}).id("right_menu")
}
}
.width('100%').height('100%')
}.height(this.barHeight)

View File

@@ -0,0 +1,15 @@
/**
* H5 调用 native的函数
*/
export interface WebScriptCallback {
getCount(): number;
}
/**
* native 调用 H5的函数
*/
export interface WebScriptFunction {
alert(message: string): void;
}

View File

@@ -0,0 +1,68 @@
import web_webview from '@ohos.web.webview';
import { WebScriptCallback, WebScriptFunction } from './WebScript';
@Component
export struct WebView {
private webviewController: web_webview.WebviewController = new web_webview.WebviewController();
controller: WebViewController = new WebViewController();
@Prop webUrl: string = "";
aboutToAppear(): void {
this.controller.setWebviewController(this.webviewController);
}
build() {
Web({ src: this.webUrl, controller: this.webviewController })
.javaScriptAccess(true)// 允许使用 js
.javaScriptProxy({
object: null,
name: "",
methodList: [],
controller: this.webviewController
})
.onPageEnd(() => { this.controller.onPageEnd(this.webviewController.getTitle()) })
.width('100%')
.height('100%');
}
}
interface WebViewCallback {
onPageEnd(title: string): void;
}
export class WebViewController implements WebScriptCallback, WebScriptFunction, WebViewCallback {
private webviewController?: web_webview.WebviewController
constructor() {
}
setWebviewController(webviewController: web_webview.WebviewController) {
this.webviewController = webviewController;
}
refresh() {
this.webviewController?.refresh();
}
getCurrentUrl(): string {
return this.webviewController?.getUrl() ?? "";
}
getCount(): number {
return 0;
}
alert(message: string): void {
this.webviewController?.runJavaScript(`window.alert(${message})`);
}
loadUrl(url: string) {
this.webviewController?.loadUrl(url);
}
onPageEnd(title: string) {
}
}

View File

@@ -0,0 +1,110 @@
export interface EmitterItem {
key: string
listener: Function
}
type XYEmitterAllType = string | object | boolean | number | Object | Number | BigInt;
export class Emitter {
private static instance: Emitter;
private static events: Map<string, EmitterItem[]> = new Map
private static viscosityData: Map<string, XYEmitterAllType[]> = new Map
public static getInstance(): Emitter {
if (!Emitter.instance) {
Emitter.instance = new Emitter();
}
return Emitter.instance;
}
/**
* 添加监听
* @param key
* @param listener
* @returns
*/
public on(key: string, listener: Function): EmitterItem {
let item: EmitterItem = {key: key, listener: listener};
if (typeof listener !== "function") {
throw new TypeError('the listener not a function')
}
let items: EmitterItem[] | undefined = Emitter.events.get(key);
if (!items) {
items = []
}
items.push(item)
Emitter.events.set(key, items)
if (Emitter.viscosityData.has(key)) {
let value = Emitter.viscosityData.get(key)
if (value == undefined) {
listener();
} else {
listener(...value);
}
}
return item
}
/**
* 取消监听
* @param listener
*/
public off(listener: EmitterItem): void {
let items = Emitter.events.get(listener.key)
if (!items) {
return;
}
items = items.filter((it)=> {
return it !== listener;
})
Emitter.events.set(listener.key, items);
}
/**
* 发布普通消息
* @param key
* @param args
*/
public emmit<T>(key: string, ...args: T[]) {
let items = Emitter.events.get(key)
if (!items || items.length == 0) {
return;
}
items.forEach((item: EmitterItem, index: number) => {
if (typeof item.listener === 'function') {
item.listener(...args)
}
});
}
/**
* 发布粘性消息
* @param key
* @param args
*/
public emmitViscosity<T>(key: string, ...args: T[]) {
this.emmit(key, ...args);
Emitter.viscosityData.set(key, args as XYEmitterAllType[]);
}
/**
* 移除粘性消息
* @param key
*/
public deleteViscosity<T>(key: string) {
if (Emitter.viscosityData.has(key)) {
Emitter.viscosityData.delete(key)
}
}
/**
* 删除所有监听
*/
public removeAllListener() {
Emitter.events = new Map;
}
}

View File

@@ -0,0 +1,5 @@
export class WebViewEventKey {
public static readonly TitleEvent: string = "web_view_event_title";
public static readonly DarkModeChangedEvent: string = "web_view_event_dark_mode_changed";
public static readonly UrlChangedEvent: string = "web_view_event_url_change_changed";
}

View File

@@ -1,3 +0,0 @@
export function add(a:number, b:number) {
return a + b;
}

View File

@@ -0,0 +1,17 @@
export class CommonRes {
private constructor() {
}
public static getIconRefresh(): Resource {
return $r("app.media.ic_refresh");
}
public static getIconBack(): Resource {
return $r("app.media.ic_chevron_left");
}
public static getIconClose(): Resource {
return $r("app.media.ic_close");
}
}

View File

@@ -9,6 +9,11 @@
"2in1"
],
"deliveryWithInstall": true,
"pages": "$profile:main_pages"
"pages": "$profile:main_pages",
"requestPermissions": [
{
"name" : "ohos.permission.INTERNET"
}
]
}
}

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>refresh</title><path d="M17.65,6.35C16.2,4.9 14.21,4 12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20C15.73,20 18.84,17.45 19.73,14H17.65C16.83,16.33 14.61,18 12,18A6,6 0 0,1 6,12A6,6 0 0,1 12,6C13.66,6 15.14,6.69 16.22,7.78L13,11H20V4L17.65,6.35Z" /></svg>

After

Width:  |  Height:  |  Size: 311 B