【每日学点HarmonyOS Next知识】getContext问题、清除Web缓存、弹层的点击事件透传、去除间隙、侧滑菜单设置
【每日学点HarmonyOS Next知识】getContext问题、清除Web缓存、弹层的点击事件透传、去除间隙、侧滑菜单设置
1、HarmonyOS getContext()获取不到?
在两个不同的页面分别使用bindPopup与bindSheet弹出相同的弹窗,点击弹窗中的按钮跳转H5页面,其中bindPopup会闪退,报错Error message:Cannot read property resourceManager of undefined
SourceCode:const resourceManager = context.resourceManager; getContext()获取不到。而bindSheet正常打开h5页面
getContext()获取不到,导致resourceManager 为undefined
在ability内使用this.context
在ui侧可使用getcontext
2、HarmonyOS 如何清除Web缓存?
如何清除Web组件加载网页后产生的资源(图片等)的缓存
可以使用removeCache()方法。参考地址:https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-webview-V5#removecache
removeCache(clearRom: boolean): void
清除应用中的资源缓存文件,此方法将会清除同一应用中所有webview的缓存文件。
可以通过在data/storage/el2/base/cache/web/Cache目录下查看Webview的缓存。
3、HarmonyOS 弹层的点击事件透传处理?
实现一套各个页面均可弹层的功能,涉及到弹层的点击事件透传处理
希望可以获取到点击的位置,弹层内的像素点,并获取到透明度,来判断点击事件是否需要透传到底部场景。
当前根据点击坐标获取透明度的整体链路,因组件截图api是异步接口,事件拦截需要同步接口,无法达成整体链路。
参考代码:
@Entry
@Component
struct HitTestPage {
@State message: string = 'Hello World';
build() {
Stack() {
Column()
.onTouch((event: TouchEvent)=> {
if (event.type == TouchType.Down) {
console.info("点击了:底部的界面")
}
})
.height('100%')
.width('100%')
.backgroundColor(Color.Green)
Column() {
Text()
.backgroundColor(Color.Black)
.onTouch((event: TouchEvent)=> {
event.stopPropagation()
if (event.type == TouchType.Down) {
console.info("点击了:文本")
}
})
.height(100)
.width(100)
}
.onTouch((event: TouchEvent)=> {
if (event.type == TouchType.Down) {
console.info("点击了:上面的界面")
}
})
.hitTestBehavior(HitTestMode.Transparent)
.backgroundColor(Color.Transparent)
.height('100%')
.width('100%')
}
.height('100%')
.width('100%')
}
}
//Index.ets
import { PageTwo } from './pageTwo';
export class NavParam {
dialogHeightChangeBack?: (dialogHeight: number) => void
constructor( dialogHeightChangeBack?: (dialogHeight: number) => void) {
this.dialogHeightChangeBack = dialogHeightChangeBack
}
}
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
@Provide('pageInfos') pageInfos: NavPathStack = new NavPathStack()
@StorageLink("windowHeight") windowHeight: number = 0
@State contentHeight: number = 100;
private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
@Builder
PageMap(name: string, param: NavParam) {
if (name === 'pageTwo') {
PageTwo({dialogHeightChangeBlock: param.dialogHeightChangeBack});
}
}
aboutToAppear() {
console.info("testTag: 当前windowHeight" + this,this.windowHeight);
this.contentHeight = px2vp(this.windowHeight);
}
build() {
Navigation(this.pageInfos) {
Column() {
Row().height(50)
Button("pageOne")
.fontSize(30)
.type(ButtonType.Capsule)
.fontWeight(FontWeight.Bold)
.onClick(() => {
this.pageInfos.pushPath({ name: 'pageTwo', param: new NavParam(
(dialogHeight: number) => {
if (dialogHeight == 0) {
animateTo({ duration: 250 }, () => {
this.contentHeight = px2vp(this.windowHeight);
})
} else {
this.contentHeight = px2vp(this.windowHeight) - dialogHeight;
}
})
});
})
List({ space: 20, initialIndex: 0 }) {
ForEach(this.arr, (item: number) => {
ListItem() {
Text('' + item)
.width('100%').height(100).fontSize(16)
.textAlign(TextAlign.Center).borderRadius(10).backgroundColor(0xFFFFFF)
}
}, (item: string) => item)
}
.listDirection(Axis.Vertical) // 排列方向
.scrollBar(BarState.Off)
.friction(0.6)
.divider({ strokeWidth: 2, color: 0xFFFFFF, startMargin: 20, endMargin: 20 }) // 每行之间的分界线
.edgeEffect(EdgeEffect.Spring) // 边缘效果设置为Spring
.width('90%')
}
.justifyContent(FlexAlign.Center)
.width('100%')
.height(this.contentHeight)
.hitTestBehavior(HitTestMode.Transparent)
.onTouch((event: TouchEvent) => {
if (event.type == TouchType.Down) {
console.info('事件穿透:colume点击了')
}
})
}
.navDestination(this.PageMap)
.onTouchIntercept((event: TouchEvent) => {
if (event.type == TouchType.Down) {
console.info('事件穿透:navigation点击了')
}
return HitTestMode.Transparent
})
}
}
//PageTwo.ets
@Component
export struct PageTwo {
@State isShow: boolean = true;
gravity: Alignment = Alignment.Bottom
transitionEdge: TransitionEdge = TransitionEdge.BOTTOM
@Consume('pageInfos') pageInfos: NavPathStack;
@State gestureHeight: number = 500;
dialogHeightChangeBlock?: (dialogHeight: number) => void;
private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
scrollOffsetY: number = 0;
private scrollerForList: Scroller = new Scroller()
@State canHandleScroll: boolean = true;
aboutToAppear() {
this.callBackHeight(this.gestureHeight);
}
callBackHeight(height: number) {
if (this.dialogHeightChangeBlock) {
this.dialogHeightChangeBlock!(height);
}
}
build() {
NavDestination() {
//背景层
Stack({ alignContent: this.gravity }) {
//内容区
Stack({ alignContent: this.gravity }) {
if (this.isShow) {
//手势层
Stack({ alignContent: Alignment.Top }) {
Column() {
List({ space: 20, initialIndex: 0, scroller: this.scrollerForList }) {
ForEach(this.arr, (item: number) => {
ListItem() {
Text('' + item)
.width('100%')
.height(100)
.fontSize(16)
.textAlign(TextAlign.Center)
.borderRadius(10)
.backgroundColor(0xFFFFFF)
}
}, (item: string) => item)
}
.enableScrollInteraction(this.canHandleScroll)
.listDirection(Axis.Vertical) // 排列方向
.scrollBar(BarState.Off)
.friction(0.6)
.divider({ strokeWidth: 2, color: 0xFFFFFF, startMargin: 20, endMargin: 20 }) // 每行之间的分界线
.edgeEffect(EdgeEffect.Spring) // 边缘效果设置为Spring
.onScroll((scrollOffset: number, scrollState: ScrollState) => {
this.scrollOffsetY += scrollOffset;
console.info("list: y偏移量 " + this.scrollOffsetY);
if (this.scrollOffsetY <= 0) {
this.scrollerForList.scrollTo({xOffset:0,yOffset:0,animation:false});
this.scrollOffsetY = 0;
this.canHandleScroll = false;
}
})
.height('100%')
.width('100%')
}
}
.borderRadius(6)
.transition(TransitionEffect.move(this.transitionEdge).animation({ duration: 250, curve: Curve.Smooth }))
.position({ x: 0, y: 0 })
.height("100%")
.width("100%")
.clip(true)
.backgroundColor(Color.White)
}
}
.width("100%")
.height(this.gestureHeight)
.parallelGesture(
PanGesture({ direction: PanDirection.Vertical, fingers: 1 })
.onActionUpdate((event: GestureEvent) => {
if (!this.canHandleScroll) {
console.info("testTag: y偏移量 " + event.offsetY);
let temHeight = 500;
temHeight -= event.offsetY;
if (temHeight >= 500) {
this.gestureHeight = 500;
} else {
this.gestureHeight = temHeight;
}
this.callBackHeight(this.gestureHeight);
}
})
.onActionEnd((event: GestureEvent) => {
if (!this.canHandleScroll) {
console.info("testTag: 动画结束y偏移量 " + event.offsetY);
let temHeight = 500;
temHeight -= event.offsetY;
if (temHeight < 250) {
this.closeDialogAction()
} else if (temHeight >= 250 && temHeight < 500) {
let duration = (500 - temHeight) / 500.0 * 250.0;
animateTo({ duration: duration }, () => {
this.gestureHeight = 500;
this.callBackHeight(this.gestureHeight);
})
}
this.canHandleScroll = true;
}
})
)
}
.onClick(() => {
// this.closeDialogAction()
})
.onTouchIntercept((event: TouchEvent) => {
if (event.type == TouchType.Down) {
console.info('事件穿透:stack点击了')
}
return HitTestMode.Transparent
})
.width('100%')
.height('100%')
.backgroundColor('#33000000')
}
.onBackPressed(() => {
this.closeDialogAction()
return true
})
.hitTestBehavior(HitTestMode.Transparent)
.onTouch((event: TouchEvent) => {
if (event.type == TouchType.Down) {
console.info('事件穿透:dialog点击了')
}
})
.hideTitleBar(true)
.mode(NavDestinationMode.DIALOG)
}
closeDialogAction() {
this.isShow = false;
this.callBackHeight(0);
animateTo({
duration: 100, delay: 250, onFinish: () => {
this.pageInfos.pop()
}
}, () => {
})
}
}
//EntryAbility.ets
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { window } from '@kit.ArkUI';
async function enterImmersion(windowClass: window.Window) {
AppStorage.setOrCreate<number>('windowHeight', windowClass.getWindowProperties().windowRect.height)
AppStorage.setOrCreate<number>('windowWidth', windowClass.getWindowProperties().windowRect.width)
// 监听窗口高度变化
windowClass.on('windowSizeChange', (size)=> {
AppStorage.setOrCreate<number>('windowHeight', size.height)
AppStorage.setOrCreate<number>('windowWidth', size.width)
})
// 设置窗口布局为沉浸式布局
await windowClass.setWindowLayoutFullScreen(true)
await windowClass.setWindowSystemBarEnable(["status", "navigation"])
// 设置状态栏和导航栏的背景为透明
await windowClass.setWindowSystemBarProperties({
navigationBarColor: "#00000000",
statusBarColor: "#00000000",
})
}
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
}
onDestroy(): void {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
}
async onWindowStageCreate(windowStage: window.WindowStage) {
// Main window is created, set main page for this ability
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
let windowClass:window.Window = await windowStage.getMainWindow()
await enterImmersion(windowClass)
windowStage.loadContent('pages/Index', (err) => {
if (err.code) {
hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
return;
}
hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.');
});
}
onWindowStageDestroy(): void {
// Main window is destroyed, release UI related resources
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
}
onForeground(): void {
// Ability has brought to foreground
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
}
onBackground(): void {
// Ability has back to background
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
}
}
4、HarmonyOS 如何去除间隙?
如何去除虚拟键盘与自定义输入框dialog 之间的间隙
之所以设置安全距离,是因为自定义弹窗仅适用于简单提示场景,不能替代页面使用。由于弹窗存在完全避让输入法行为,即在软键盘弹出时,会自动向上抬起软键盘高度,因此如果弹窗高度过大时,可能会导致部分区域不可见。弹窗避让软键盘时,与软键盘之间存在16vp的安全间距。 结合文档说法,可以手动在软键盘弹起时设置offset:{y:16}来抵消安全距离。
参考demo:
//CustomDialog.ets
build{
Column(){
TextArea({
text: "",
placeholder: 'The text area can hold an unlimited amount of text. input your word...',
controller: this.textController
})
.height(200)
.width("100%")
}
//todo 需要在 TextArea的外层组件设置 offset 来抵消安全距离
.offset({
y:16
})
}
//规格选择页面控制器
customDialogController: CustomDialogController = new CustomDialogController({
builder: SpecificationsCustomDialog({
}),
alignment: DialogAlignment.Bottom,
customStyle: true,
autoCancel: false,
//这里设置dy: -16,会将弹窗抬起来
offset: {
dx: 0,
dy: -16
}
});
5、HarmonyOS ListItem侧滑菜单动态设置?
有一个list列表,列表项item有侧滑菜单,但是编辑状态下又没有侧滑菜单,想通过一个开关动态设置侧滑菜单
参考demo:
@Entry
@Component
struct ListItemExample2 {
@State arr: number[] = [0, 1, 2, 3, 4]
@State enterEndDeleteAreaString: string = "not enterEndDeleteArea"
@State exitEndDeleteAreaString: string = "not exitEndDeleteArea"
@State isShow:boolean = true;
@Builder itemEnd() {
Row() {
Button("Delete").margin("4vp")
Button("Set").margin("4vp")
}.padding("4vp").justifyContent(FlexAlign.SpaceEvenly)
}
build() {
Column() {
Button("点击").onClick(()=>{
this.isShow=!this.isShow
console.log(this.isShow+"111111111")
})
List({ space: 10 }) {
ForEach(this.arr, (item: number) => {
ListItem() {
Text("item" + item)
.width('100%')
.height(100)
.fontSize(16)
.textAlign(TextAlign.Center)
.borderRadius(10)
.backgroundColor(0xFFFFFF)
}
.transition({ type: TransitionType.Delete, opacity: 0 })
.swipeAction({
end: this.isShow?{
builder: () => { this.itemEnd() },
onAction: () => {
animateTo({ duration: 1000 }, () => {
let index = this.arr.indexOf(item)
this.arr.splice(index, 1)
})
},
actionAreaDistance: 56,
onEnterActionArea: () => {
this.enterEndDeleteAreaString = "enterEndDeleteArea"
this.exitEndDeleteAreaString = "not exitEndDeleteArea"
},
onExitActionArea: () => {
this.enterEndDeleteAreaString = "not enterEndDeleteArea"
this.exitEndDeleteAreaString = "exitEndDeleteArea"
}
}:undefined
})
}, (item: string) => item)
}
Text(this.enterEndDeleteAreaString).fontSize(20)
Text(this.exitEndDeleteAreaString).fontSize(20)
}
.padding(10)
.backgroundColor(0xDCDCDC)
.width('100%')
.height('100%')
}
}