Skip to content

pref(rn): 优化全尺寸 linear-gradient 背景渲染时机 - #2521

Open
dos1in wants to merge 14 commits into
didi:masterfrom
dos1in:pref/rn-gradient-image
Open

dos1in wants to merge 14 commits into
didi:masterfrom
dos1in:pref/rn-gradient-image

Conversation

@dos1in

@dos1in dos1in commented Jun 11, 2026

Copy link
Copy Markdown
Member

改动说明

优化 Android/Harmony 渐变背景的首次渲染,减少不必要的 onLayout 等待,保留 iOS 原有兼容处理。

  • iOS:百分比宽高的渐变仍依赖 layout。布局宽高存在 0 值时,将渐变宽高暂设为 0;布局恢复后使用百分比宽高渲染。
  • Android/Harmony:百分比宽高的渐变仅在需要根据尺寸计算对角方向角度时等待 layout。普通固定角度渐变直接使用百分比宽高同步渲染,不再进行零尺寸特殊处理。
  • 百分比背景定位:各平台仍等待 layout 计算偏移。
  • 沿用原有宽高布局方式,不引入四边撑满布局,也不增加渐变卸载、重新挂载逻辑。

业务侧无需修改模板或样式。

优化 RN 全尺寸 linear-gradient 背景的首次渲染,避免无差别等待 onLayout

  • 仅对无偏移、非对角方向的 100% 100% 渐变使用四边撑满布局,直接渲染。
  • 存在背景偏移、非全尺寸或需计算对角方向时,保留 master 的布局路径和零尺寸保护。
  • 布局判断与样式生成共用优化条件,避免两者不一致;保留 master 的尺寸缓存和固定尺寸对角渐变处理。

例如容器宽度为 200background-position: 20px 0 时,渐变仍保持宽度 200,向右偏移并裁剪,不会被 left: 20; right: 0 压缩成 180

验证

  • 29 项渐变相关 Jest 测试通过,相关 ESLint 检查通过。
  • 覆盖 Android/Harmony 同步渲染、正负偏移、部分百分比尺寸、对角角度计算、百分比定位,以及 iOS 零尺寸恢复。
  • 业务验证用例:父节点 wx:showfalse 切换为 true,子节点使用 linear-gradientbackground-size: 100% 100%,随后反复隐藏、显示。
  • 三平台业务测试过程见录屏;单元测试不代替原生绘制验证。
  • RN 运行时 Jest:14 个测试套件、183 项测试通过;相关 ESLint 和 diff 检查通过。
  • 新增组件测试覆盖全尺寸直接渲染、正负偏移、零尺寸恢复及全尺寸与百分比尺寸切换。
平台 验证结果与范围
Android 15 模拟器 前一版修复方案的原生绘制专项:使用 react-native-linear-gradient 2.8.3 原生源码和 Yoga 布局输出验证偏移;7 个用例归零、更新颜色后恢复像素一致。包含 1 个原 PR 对照用例,其恢复成功不代表偏移布局正确。
iOS 18.4 模拟器 同上,7 个用例恢复像素一致。
鸿蒙真机 Harmony 6.1.1.120 在RN 容器运行从当前提交提取的渐变解析、布局和 useWrapImage Hook,检查全尺寸、正负偏移、居中、对角及半尺寸等 7 种布局;自动和手动归零后均恢复显示。

鸿蒙验证使用真实 React Hooks、RN 布局回调及宿主原生渐变组件,但不包含完整 .mpx 页面编译和业务生命周期。三端验证均不作为首帧性能量化结果。

平台截图

Android iOS 鸿蒙
Android 15:偏移布局与恢复验证 iOS 18.4:偏移布局与恢复验证 鸿蒙真机:当前修复版本恢复后的七种渐变布局

实际业务运行效果:

before.mp4
after.mp4

Comment thread packages/webpack-plugin/lib/runtime/components/react/mpx-view.tsx Outdated
@dos1in

dos1in commented Jul 1, 2026

Copy link
Copy Markdown
Member Author
valid-show-hide.mp4

验证看起没问题,验证逻辑如下:

<template>
  <view class="page">
    <view class="stage">
      <view
        key="bg-wx-show-linear-1"
        enable-background="{{ true }}"
        wx:show="{{ showGradient }}"
        class="gradient"
      >
        <text class="text">wx:show false -> true</text>
      </view>
    </view>

    <view class="button" bindtap="replay">
      <text class="button-text">重放</text>
    </view>
  </view>
</template>

<script>
  import { createPage } from '@mpxjs/core'

  createPage({
    data: {
      showGradient: false,
    },

    onReady() {
      this.replay()
    },

    methods: {
      replay() {
        this.setData({ showGradient: false })

        setTimeout(() => {
          this.setData({ showGradient: true })
        }, 800)
      },
    },
  })
</script>

<style lang="stylus" scoped>
  .page
    padding 32rpx
    background-color #f5f6f8
    min-height 100vh

  .stage
    position relative
    border-radius 18rpx
    overflow hidden
    background-color #e9edf2

  .gradient
    height 220rpx
    display flex
    align-items center
    justify-content center
    background-image linear-gradient(90deg, #00e1bf 0%, #00bed3 100%)
    background-repeat no-repeat
    background-size 100% 100%

  .text
    color #fff
    font-size 30rpx
    font-weight 600

  .button
    margin-top 24rpx
    height 72rpx
    display flex
    align-items center
    justify-content center
    background-color #14d0b4

  .button-text
    color #fff
    font-size 26rpx
</style>

Comment thread packages/webpack-plugin/lib/runtime/components/react/mpx-view.tsx Outdated
@dos1in
dos1in marked this pull request as draft July 9, 2026 09:04
@dos1in

dos1in commented Jul 9, 2026

Copy link
Copy Markdown
Member Author

ios 平台兼容性有问题,处理中。

@dos1in
dos1in marked this pull request as ready for review September 9, 2026 03:31
@hiyuki

hiyuki commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator

上面说的这个case确认过了吗?iOS下wx:show由false变为true后是否能够正常撑开渲染?

@dos1in

dos1in commented Sep 9, 2026

Copy link
Copy Markdown
Member Author

上面说的这个case确认过了吗?iOS下wx:show由false变为true后是否能够正常撑开渲染?

iOS 渐变绘制链路存在问题,mpx层目前无法处理,现在方案是根据平台只给android/harmony 优化,验证 demo 如下:

父节点 wx:show + 子节点渐变背景、background-size: 100% 100% 的场景

<template>
  <view class="page">
    <view bindtap="pageTap">tap me</view>
    <view wx:show="{{show}}">
      <view class="panel-wrapper" enable-background="{{true}}">
        3333
      </view>
    </view>
  </view>
</template>

<script>
  import { createPage } from '@mpxjs/core'

  createPage({
    data: {
      show: false
    },
    methods: {
      pageTap () {
        this.show = !this.show
      }
    }
  })
</script>

<style lang="stylus">
  .page
    width 100vw
    height 100vh
    padding-top 200px

  .panel-wrapper
    width 100px
    height 100px
    background-image linear-gradient(179deg, #fff 0%, #000 76%)
    background-size 100% 100%
    border 1px solid #fff
    box-shadow 0px 2px 6px 0px rgba(0, 49, 99, 0.08)
    border-radius 12px
    overflow hidden
    display flex
    flex-direction column
    color red
</style>

<script type="application/json">
  {
    "usingComponents": {}
  }
</script>

Comment thread packages/webpack-plugin/lib/runtime/components/react/mpx-view.tsx
Comment thread packages/webpack-plugin/lib/runtime/components/react/mpx-view.tsx
@dos1in
dos1in marked this pull request as draft September 14, 2026 06:57
@hiyuki

hiyuki commented Sep 14, 2026

Copy link
Copy Markdown
Collaborator

如果需要分平台处理iOS无法处理的话,是不是把之前先设置为0,layout之后再设置正确dimensions的条件添加上iOS限定即可,见相关comment所示。

之前加这个逻辑本身是为了处理iOS百分比高宽在wx:show场景下不能正常更新视图的问题,当前的目标如果消除非iOS环境下这个onLayout的等待的话,应该不需要引入新的absolute的布局模式,直接用原始的高宽100%同步渲染应该就可以。

@dos1in

dos1in commented Sep 14, 2026

Copy link
Copy Markdown
Member Author

如果需要分平台处理iOS无法处理的话,是不是把之前先设置为0,layout之后再设置正确dimensions的条件添加上iOS限定即可,见相关comment所示。

之前加这个逻辑本身是为了处理iOS百分比高宽在wx:show场景下不能正常更新视图的问题,当前的目标如果消除非iOS环境下这个onLayout的等待的话,应该不需要引入新的absolute的布局模式,直接用原始的高宽100%同步渲染应该就可以。

可以的,改动后需要三个平台一起再回归下,需要花点时间,有结果了再更新问题状态。

@hiyuki

hiyuki commented Sep 14, 2026

Copy link
Copy Markdown
Collaborator

整体逻辑应该是:

  • iOS中linear+百分比高宽依赖layout,保留检测到layout高宽存在0值时将渐变高宽暂设为0的逻辑,后续layout高宽更新无0值后再使用百分比高宽渲染,整体同当前逻辑保持一致
  • Android/Harmony中改为linear+百分比高宽+需要计算渐变角度才依赖layout,不需要保留上面layout高宽为0的特殊逻辑,一直使用百分比高宽渲染,这样对于不需要计算渐变角度的linear可以同步渲染,不需要再等待layout

后续我们观察iOS linear渲染bug修复后就可以将逻辑和Android/Harmony进行拉齐。

@dos1in

dos1in commented Sep 16, 2026

Copy link
Copy Markdown
Member Author

三端验证留痕。

platform-comparison.mp4

@dos1in
dos1in marked this pull request as ready for review September 16, 2026 06:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants