HarmonyOS 鸿蒙Next中预览器和模拟器与真机显示有差异

HarmonyOS 鸿蒙Next中预览器和模拟器与真机显示有差异 本地模拟器 直接是在ide中创建了 mate60pro 分辨率是1260x2720 dpi 520,预览器中也是这个参数 但是同一个页面下 预览器和模拟器 与真机显示的不一样 ,使用display.getDefaultDisplaySync(); 得出真机的densityDPI是442, 如果将预览器和模拟器的参数设置成442的话 模拟器显示正常的 预览器显示就出问题了 字体变的很小。 这种情况该怎么办?

cke_2968.png

cke_9537.png

cke_10230.png


更多关于HarmonyOS 鸿蒙Next中预览器和模拟器与真机显示有差异的实战教程也可以访问 https://www.itying.com/category-93-b0.html

12 回复

开发者您好,您之前反馈的问题已经解决,请您升级6.0.2版本验证。https://developer.huawei.com/consumer/cn/download/

更多关于HarmonyOS 鸿蒙Next中预览器和模拟器与真机显示有差异的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


我测试了下老版的IDE(5.1.1(19))显示是正常的,随即我用新版的IDE更换sdk19。都是macOS 26.1 (25B78) 发现还是有这个问题, mate60pro 在设置缩放到最小就是分辨率1260x2720 dpi 442 预览器设置分辨率1260x2720 dpi 442 就会复现这个预览器的问题

以下是 Index.ets

import { window } from '@kit.ArkUI';
import home from './home'

@Entry
@Component
struct Index {
  uiContext = this.getUIContext();

  aboutToAppear(): void {
    window.getLastWindow(this.uiContext.getHostContext()).then(win => {
      win.setWindowLayoutFullScreen(true) //这个地方设置false  会导致预览器页面白屏
    })
  }
  build() {
    Tabs({
      barPosition: BarPosition.End,
    }) {
      TabContent() {
        home()
      }.tabBar('首页')
      TabContent() {
        home()
      }.tabBar('个人')

      TabContent() {
          home()
      }.tabBar('推荐')

      TabContent() {
          home()
      }.tabBar('消息')

    }
    .width('100%')
    .height('100%')
    .barHeight(90) // 这地方设置高度 初始时字体大小也不对
  }
}

然后是home.ets

@Component
export default struct home {
  // 标题
  @Builder
  title(title: string) {
    Text(title).fontSize(30).width('100%').textAlign(TextAlign.Start).padding({
      top: 20
    })
  }

  //内容
  build() {
    Column() {
      Text('每日推荐').fontSize(30).width('100%')
      Scroll(){
        this.title('每日推荐')
      }
      this.title('每日推荐')
    }
    .height('100%')
    .width('100%')
    .padding({
      top:200,
      left:100
    })
  }
}

尊敬的开发者,您好!感谢您的反馈,问题正在加速处理中,还请关注后续版本,感谢您的理解与支持。

HarmonyOS的分布式文件系统让我在多设备间共享文件变得更加方便。

嗯嗯 我发现不是这个@Builder导致的 ,现在是发现在首页使用Tabs时 第一个TabContent中的子组件,其他的TabContent都是好的   第一个里面如果引入了@builder 还是 @components 在Scorll下都会导致字体失效 cke_2458.pngcke_3652.pngcke_4791.png

这边按照你的方式大概写了下,预览的时候好像也是正确的,换成最新版本的IDE也是这样吗?我的代码如下:

// xxx.ets
@Entry
@Component
struct TabsExample {
  @State fontColor: string = '#182431';
  @State selectedFontColor: string = '#007DFF';
  @State currentIndex: number = 0;
  @State selectedIndex: number = 0;
  private controller: TabsController = new TabsController();

  @Builder tabBuilder(index: number, name: string) {
    Column() {
      Text(name)
        .fontColor(this.selectedIndex === index ? this.selectedFontColor : this.fontColor)
        .fontSize(16)
        .fontWeight(this.selectedIndex === index ? 500 : 400)
        .lineHeight(22)
        .margin({ top: 17, bottom: 7 })
      Divider()
        .strokeWidth(2)
        .color('#007DFF')
        .opacity(this.selectedIndex === index ? 1 : 0)
    }.width('100%')
  }

  build() {
    Column() {
      Tabs({ barPosition: BarPosition.Start, index: this.currentIndex, controller: this.controller }) {
        TabContent() {
          Column(){
            Column().width('100%').height('10%').backgroundColor('#00CB87')
            home()
          }
        }.tabBar(this.tabBuilder(0, 'green'))

        TabContent() {
          Column() {
            Column().width('100%').height('20%').backgroundColor('#007DFF')
            home()
          }
        }.tabBar(this.tabBuilder(1, 'blue'))

        TabContent() {
          Column().width('100%').height('100%').backgroundColor('#FFBF00')
        }.tabBar(this.tabBuilder(2, 'yellow'))

        TabContent() {
          Column().width('100%').height('100%').backgroundColor('#E67C92')
        }.tabBar(this.tabBuilder(3, 'pink'))
      }
      .vertical(false)
      .barMode(BarMode.Fixed)
      .barWidth(360)
      .barHeight(56)
      .animationDuration(400)
      .onChange((index: number) => {
        // currentIndex控制TabContent显示页签
        this.currentIndex = index;
        this.selectedIndex = index;
      })
      .onAnimationStart((index: number, targetIndex: number, event: TabsAnimationEvent) => {
        if (index === targetIndex) {
          return;
        }
        // selectedIndex控制自定义TabBar内Image和Text颜色切换
        this.selectedIndex = targetIndex;
      })
      .width(360)
      .height(296)
      .margin({ top: 52 })
      .backgroundColor('#F1F3F5')
    }.width('100%')
  }
}


@Component
struct home{

  @Builder
  title(title: string) {
    Text(title).fontSize(30).width('100%').textAlign(TextAlign.Start).padding({
      left: 20,
      top: 20
    })
  }

  build() {
    Column(){
      Text('首页').fontSize('30px').width('100%').padding({ left: 20 })
      Scroll(){
        this.title('每日推荐')
      }
      this.title('每日推荐')
      Scroll(){
        Column(){
          Column(){
            this.title('每日推荐')
          }
        }
      }
    }
  }
}

如果换了IDE的版本还是不行,麻烦提供下可以复现的demo呢,

【背景知识】

【解决方案】 引入display工具,添加如下代码,获取真机屏幕尺寸。

import { display } from '@kit.ArkUI'

display.getAllDisplays((err, data) => {
  let screenWidth: number = data[0].width
  let screenHeight: number = data[0].height
  console.log('width = ' + screenWidth + ', height = ' + screenHeight + ', dpi = '+display.getDefaultDisplaySync().densityDPI)
})

在设置->显示中修改了界面缩放到最小,用上述代码可以获取到screenWidth和screenHeight,检查下预览器的分辨率是否一致,设置为获取到的screenWidth和screenHeight试下呢。

我在将真机的缩放设置最小,得到的是width = 1260, height = 2720, dpi = 442 将预览器参数设置为此参数后 ,发现首页显示是异常的 @builder创建的UI片段 中的字体 和 外部同样的字体大小一致 但是@builder创建的UI片段 中的字体显示的很小,

@Builder title(title: string) {
  Text(title).fontSize(30).width('100%').textAlign(TextAlign.Start).padding({
    left: 20,
    top: 20
  })
}

Text('首页').fontSize(30)

每日推荐

Text(‘首页’).fontSize(‘30px’).width(‘100%’).padding({left:20}) 通过@builder创建的片段 字体单位会变成px 哪怕将@builder中的字体大小换成Text(title).fontSize(“30fp”) 在build() 中 字体还是会转换成30px,

鸿蒙Next中预览器和模拟器与真机显示差异主要由渲染引擎、系统资源和硬件差异导致。预览器基于轻量化引擎,模拟器在虚拟环境中运行,而真机使用完整的鸿蒙系统并调用实际GPU。三者环境不同,可能导致UI布局、组件渲染或动效的细微差别。

这是一个典型的设备像素密度(densityDPI)配置差异导致的UI适配问题。根本原因在于预览器、模拟器和真机使用了不同的逻辑像素密度基准。

问题分析:

  1. 核心差异:您创建的Mate 60 Pro模拟器配置的DPI为520,而真机实测为442。预览器通常默认跟随当前选中的模拟器或设备的配置。
  2. 影响机制:HarmonyOS应用开发中,布局尺寸(如vp)和字体尺寸(如fp)会根据设备的densityDPI进行换算,以在不同屏幕密度的设备上呈现近似物理尺寸的视觉效果。densityDPI值不同,1vp对应的物理像素数就不同。
    • 在DPI 520的设备上,1vp换算的物理像素更多。
    • 在DPI 442的真机上,1vp换算的物理像素较少。
  3. 现象解释
    • 预览器/模拟器(520 DPI) vs 真机(442 DPI):由于模拟器DPI更高,相同的vp值会渲染出更大的物理像素区域,因此在模拟器上看起来“正常”的布局,在真机上会因为实际渲染区域变小而显得拥挤或错位。
    • 调整模拟器DPI至442后:模拟器与真机基准一致,所以显示正常。
    • 预览器字体变小:当您将预览器参数也设为442 DPI后,预览器依据新的DPI重新计算vpfp。由于基准密度降低,fp(字体像素)换算出的物理像素数减少,导致视觉上字体变小。这恰恰证明了预览器正在正确应用新的密度参数。

解决方案:

问题的关键不是让工具显示一致,而是确保您的UI布局代码能够正确适配不同的屏幕密度。不应以固定某个DPI下的显示效果为“标准”。

  1. 使用正确的密度配置进行开发:建议将本地模拟器的densityDPI设置为与目标真机一致(例如442)。这样可以在开发阶段获得最接近真机的预览效果,尽早发现适配问题。
  2. 采用响应式与弹性布局
    • 核心布局尺寸应尽量使用vp(虚拟像素)而非px
    • 字体尺寸使用fp,并注意其会根据系统的字体大小设置进行缩放。
    • 对于需要精细控制或需要满屏、等分的场景,优先使用百分比、Flex布局、Grid布局或ConstraintLayout,而非固定vp值。
    • 使用资源限定词(如res/目录下的-vp-*子目录)为不同的屏幕宽度提供差异化的布局或尺寸值。
  3. 在多种设备配置上测试:利用云测服务或更换不同DPI配置的本地模拟器(如标准密度设备),验证UI在不同屏幕密度下的表现是否符合预期。
  4. 理解预览器的局限性:预览器主要用于快速查看布局框架和大致比例,其渲染环境与真机或模拟器存在固有差异。最终验证务必以真机或功能完整的本地模拟器为准。

总结: 真机densityDPI为442是客观事实。您应将模拟器配置为此值作为主要开发环境。预览器显示的变化正是对您参数更改的正确反馈。当前首要任务是检查并优化您的UI代码,确保其使用相对单位(vp/fp)和弹性布局方案,从而在密度为442的真机上也能正确显示。

回到顶部