鸿蒙next 子窗口实现弹窗效果

前言

最近在做手游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+,欢迎进行课程,项目等合作。

相关推荐
小藤神37 分钟前
鸿蒙ArtTS 中如何实现地图打卡功能 比如公司打卡 文章配置完整代码
前端·harmonyos·arkts
苏杰豪5 小时前
鸿蒙特效教程09-深入学习animateTo动画
华为·harmonyos
星释5 小时前
鸿蒙Flutter开发故事:不,你不需要鸿蒙化
flutter·华为·harmonyos
Kousi5 小时前
旧时代的船?来看看鸿蒙V1状态管理装饰器
前端·面试·harmonyos
Kousi6 小时前
状态管理V2 鸿蒙开发更好用状态管理的装饰器?
前端·面试·harmonyos
塞尔维亚大汉6 小时前
OpenHarmony轻量系统服务管理|samgr_server功能详解(三)
操作系统·嵌入式·harmonyos
CrazyMo_8 小时前
OpenHarmony 入门——ArkUI 跨页面数据同步和页面级UI状态存储LocalStorage小结(二)
harmonyos·装饰器·openharmony·状态管理·arkui
二流小码农8 小时前
鸿蒙开发:了解分割线
harmonyos
Bruce_Liuxiaowei15 小时前
HarmonyOS Next~鸿蒙系统架构设计解析:分层、模块化与智慧分发的技术革新
华为·harmonyos