前言
最近在做手游sdk 开发 之前能是使用 Pupop来实现弹窗的的效果 虽然能够实现弹窗抽象 在没有ui的地发也能弹出 但是存在问题在横版游戏的接入的时候弹出会变形也会遮挡键盘。现在就换一种实现方式。
之前存在问题的版本
横屏
竖屏
我们可以清楚观察到我们使用popup的方式实现的效果是有缺陷的,横屏的时候跟竖屏的时候效果不一样。
使用子窗口来实现的弹窗效果
竖版
横版
具体实现
弹窗布局代码
less
import { router } from '@kit.ArkUI'
/**
* 自定义中间弹窗
*/
//线条样式
@Extend(Line) function lineStyle(){
.width('100%')
.height(1)
.backgroundColor($r('app.color.line_color'))
}
//黑色字体样式
@Extend(Text) function blackTextStyle(){
.fontColor($r('app.color.black_text_color'))
.fontSize(18)
.fontWeight(FontWeight.Medium)
}
@Extend(TextInput) function inputStyle(){
.placeholderColor($r('app.color.placeholder_color'))
.height(45)
.fontSize(18)
.backgroundColor($r('app.color.background'))
.width('100%')
.padding({left:0})
.margin({top:12})
}
@Entry
@Component
struct GameSdkLogin {
build() {
Column() {
Column(){
Row(){
Text('账号').blackTextStyle()
TextInput({placeholder:'请输入账号'})
.width('100%')
.height(35)
.type(InputType.Normal)
.margin(5)
.onChange((value:string)=>{
}).margin({left:20})
.onSecurityStateChange(((isShowPassword: boolean) => {
// 更新密码显示状态
console.info('isShowPassword', isShowPassword)
})).backgroundColor("#00000000")
.layoutWeight(1)
.borderRadius(8)
}.justifyContent(FlexAlign.SpaceBetween)
.width('100%')
.margin({top:20,right:20,left:20})
Line().lineStyle().margin({left:80,right:10})
Row(){
Text('密码').blackTextStyle()
TextInput({placeholder:'请输入密码'})
.width('100%')
.height(35)
.type(InputType.Normal)
.margin(5)
.onChange((value:string)=>{
}).margin({left:20})
.onSecurityStateChange(((isShowPassword: boolean) => {
// 更新密码显示状态
console.info('isShowPassword', isShowPassword)
})).backgroundColor("#00000000")
.layoutWeight(1)
.borderRadius(8)
}.justifyContent(FlexAlign.SpaceBetween)
.width('100%')
.margin({top:8,right:20,left:20})
Line().lineStyle().margin({left:80,right:10})
//Line().lineStyle().margin({left:80,right:10})
Row({space:10}){
Button('登录',{type:ButtonType.Capsule})
.width('90%')
.height(40)
.fontSize(16)
.fontWeight(FontWeight.Medium)
.backgroundColor($r('app.color.login_button_color'))
.margin({top:47,bottom:12})
.onClick(()=>{
}).layoutWeight(1)
Button('注册',{type:ButtonType.Capsule})
.width('90%')
.height(40)
.fontSize(16)
.fontWeight(FontWeight.Medium)
.backgroundColor($r('app.color.login_button_color'))
.margin({top:47,bottom:12})
.onClick(()=>{
}).layoutWeight(1)
}.justifyContent(FlexAlign.SpaceBetween)
.width('100%')
.margin({right:20,left:20})
}.width("100%")
.height("100%")
.margin({top:20,right:20,left:20,bottom:20})
}.height("100%")
.width("100%")
.backgroundColor("#fff5f1f1")
.borderRadius(10)
}
}
子窗口实现逻辑
我们需要在 EntryAbility 里面把我们的 window.WindowStage传入到我们的ZgSdk 弹窗管理器的初始化方法中
javascript
onWindowStageCreate(windowStage: window.WindowStage): void {
// Main window is created, set main page for this ability
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
ZgSdk.getInstance().init(windowStage);
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.');
});
}
显示弹窗
javascript
this.windowClass?.createSubWindow("login", (err: BusinessError, win) => {
win.setUIContent('pages/GameSdkLogin');
win.showWindow();
}
弹窗居中显示
ini
this.sub_windowClass = win;
console.info('Succeeded in creating the subwindow. Data: ' + JSON.stringify(win));
// 2.子窗口创建成功后,设置子窗口的位置、大小及相关属性等。
// 获取屏幕尺寸
let width = 0
let height = 0
// 登录窗口尺寸
let login_width = 1000
let login_height = 800
try {
let displayClass = display.getDefaultDisplaySync();
width = displayClass.width
height = displayClass.height
} catch (error) {
console.error('Error while centering the window:', error);
}
// 计算窗口位置
let x = (width - login_width)/2
let y = (height - login_height)/2
this.sub_windowClass.moveWindowTo(x,y, (err: BusinessError) => {
let errCode: number = err.code;
if (errCode) {
console.error('Failed to move the window. Cause:' + JSON.stringify(err));
return;
}
console.info('Succeeded in moving the window.');
});
设置弹窗大小
typescript
this.sub_windowClass.resize(login_width, login_height, (err: BusinessError) => {
let errCode: number = err.code;
if (errCode) {
console.error('Failed to change the window size. Cause:' + JSON.stringify(err));
return;
}
console.info('Succeeded in changing the window size.');
});
完整代码
typescript
import { window } from "@kit.ArkUI";
import { BusinessError } from "@kit.BasicServicesKit";
import { display } from '@kit.ArkUI';
export class ZgSdk {
private static instance: ZgSdk;
private constructor() {
// 私有构造函数
}
public static getInstance(): ZgSdk {
if (!ZgSdk.instance) {
ZgSdk.instance = new ZgSdk();
}
return ZgSdk.instance;
}
private windowClass: window.WindowStage | null = null
private sub_windowClass: window.Window | null = null;
public init(windowStage: window.WindowStage){
this.windowClass = windowStage ;
}
public gameLogin(){
if(this.windowClass!=null){
this.windowClass?.createSubWindow("login", (err: BusinessError, win) => {
win.setUIContent('pages/GameSdkLogin');
win.showWindow();
this.sub_windowClass = win;
console.info('Succeeded in creating the subwindow. Data: ' + JSON.stringify(win));
// 2.子窗口创建成功后,设置子窗口的位置、大小及相关属性等。
// 获取屏幕尺寸
let width = 0
let height = 0
// 登录窗口尺寸
let login_width = 1000
let login_height = 800
try {
let displayClass = display.getDefaultDisplaySync();
width = displayClass.width
height = displayClass.height
} catch (error) {
console.error('Error while centering the window:', error);
}
// 计算窗口位置
let x = (width - login_width)/2
let y = (height - login_height)/2
this.sub_windowClass.moveWindowTo(x,y, (err: BusinessError) => {
let errCode: number = err.code;
if (errCode) {
console.error('Failed to move the window. Cause:' + JSON.stringify(err));
return;
}
console.info('Succeeded in moving the window.');
});
this.sub_windowClass.resize(login_width, login_height, (err: BusinessError) => {
let errCode: number = err.code;
if (errCode) {
console.error('Failed to change the window size. Cause:' + JSON.stringify(err));
return;
}
console.info('Succeeded in changing the window size.');
});
})
}else {
console.log("windowClass 为空")
}
}
public onWindowStageDestroy() {
// 开发者可以在适当的时机,如子窗口上点击关闭按钮等,销毁子窗口。并不一定需要在onWindowStageDestroy调用,这里仅作展示
}
}
最后总结
华为也是推荐我们使用子窗口来实现类似自定义弹窗的的效果,最开始是使用自定义的弹窗 但是需要在我们的page目录下面去注册。,这种方式不可取,后面我改成了popup但是在横屏上面显示变形,所以我这最后决定使用子窗口来实现。 。今天的文章就讲到这里有兴趣的同学可以继续研究 如果你觉得文章还不错麻烦给我三连 关注点赞和转发 如果了解更多鸿蒙开发的知识 可以关注坚果派公众号 。 谢谢
团队介绍
团队介绍:坚果派由坚果等人创建,团队由12位华为HDE以及若干热爱鸿蒙的开发者和其他领域的三十余位万粉博主运营。专注于分享 HarmonyOS/OpenHarmony,ArkUI-X,元服务,仓颉,团队成员聚集在北京,上海,南京,深圳,广州,宁夏等地,目前已开发鸿蒙 原生应用,三方库60+,欢迎进行课程,项目等合作。