HarmonyOS鸿蒙Next中如何实现平滑渐变过渡

HarmonyOS鸿蒙Next中如何实现平滑渐变过渡 鸿蒙如何实现下面IOS这样的渐变过渡,试了多种方法都不理想。

cke_3020.png

代码

cke_2143.png


更多关于HarmonyOS鸿蒙Next中如何实现平滑渐变过渡的实战教程也可以访问 https://www.itying.com/category-93-b0.html

16 回复

【背景知识】

  • linearGradient设置组件的颜色渐变效果,支持方向控制和多颜色配置。
  • colors参数的约束:ResourceColor表示填充的颜色,number表示指定颜色所处的位置,取值范围为[0,1.0],0表示需要设置渐变色的容器的开始处,1.0表示容器的结尾处。想要实现多个颜色渐变效果时,多个数组中number参数建议递增设置,如后一个数组number参数比前一个数组number小的话,按照等于前一个数组number的值处理。

【解决方案】

可以使用linearGradient实现颜色渐变,可以随意控制渐变的方向和颜色。

示例代码如下:

@Entry
@Component
struct Index {
  build() {
    Stack(){
      Stack() {
        //顶部图片区域
        this.ImageBuilder()
        //内容区域
        // this.ContentBuilder()
      }
      .alignSelf(ItemAlign.End)
      .width("100%")
      .height("100%")
      .align(Alignment.TopStart)
      .margin({top:300})
      .overlay(this.createOverlayBuilder())
      .blendMode(BlendMode.SRC_OVER, BlendApplyType.OFFSCREEN)
      .opacity(0.9)
    }
    .background(
      this.BgImageBuilder
    )
  }

  @Builder
  ImageBuilder() {
    Image($r('app.media.image'))
      .width('100%')
      .height("80%")
  }

  @Builder
  BgImageBuilder() {
    Image($r('app.media.background'))
      .width('100%')
      .height('100%')
      .objectFit(ImageFit.Cover)
  }

  @Builder
  createOverlayBuilder() {
    Stack()
      .height('100%')
      .width('100%')
      .linearGradient({
        direction: GradientDirection.Bottom,
        colors: [['#00FFFFFF', 0.0],
          ['#FFFFFFFF', 0.13]]
      })
      .blendMode(BlendMode.DST_IN, BlendApplyType.OFFSCREEN)
      .hitTestBehavior(HitTestMode.None)
  }
}

更多关于HarmonyOS鸿蒙Next中如何实现平滑渐变过渡的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


这段代码是一个鸿蒙(HarmonyOS)ArkTS UI框架的组件定义,用于构建一个具有复杂视觉层次和图像效果的页面。其核心设计思想是通过多层叠加(Stack)图像混合(Blend Mode) 来创造景深和渐变融合的视觉效果。

以下是对代码结构的详细分析:

1. 整体布局与结构

代码定义了一个名为 Index 的组件,这通常是应用的入口页面。其主体是一个两层嵌套的 Stack 布局:

  • 外层Stack:作为根容器,设置了全屏的背景图片 (BgImageBuilder)。
  • 内层Stack:作为内容容器,内部规划了顶部图片区域和内容区域(后者被注释),并通过一系列样式和效果属性进行定位与渲染。

这种嵌套Stack的设计是构建复杂、分层UI的常用手法,类似于Flutter等框架中的实现思路。

2. 视觉效果实现解析

代码通过多个属性实现了专业的视觉效果:

  • 背景与前景图像

    • BgImageBuilder 提供全屏覆盖、保持比例的静态背景 (ImageFit.Cover)。
    • ImageBuilder 在内容层顶部显示另一张主图,高度占80%。
  • 定位与间距

    • 内层Stack通过 .margin({top:300}) 向下偏移,为顶部图片留出空间,并通过 .align(Alignment.TopStart) 确保内容从顶部开始排列。
  • 核心视觉效果(叠加层与混合模式): 这是代码最精巧的部分,通过 overlayblendMode 属性实现。

    1. .overlay(this.createOverlayBuilder()):在内层Stack上覆盖一个自定义的渐变层。

厉害,

这个问题一直没有采纳,是不是就是白嫖的?

@Entry
@Component
struct ImageExample1 {
  private_resource1: Resource = $r('app.media.ScreenShot_20251117200138');
  @State image_src: Resource = this.private_resource1;

  build() {
    Column() {
      Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Start }) {
        Stack() {
          Image(this.image_src)
            .width('100%')
            .height('100%')

          Column()
            .width('100%')
            .height('100%')
            .linearGradientBlur(100,
              { fractionStops: [[0, 0], [0, 0.1], [1, 0.2], [1, 1]], direction: GradientDirection.Bottom });
        };
      };
    };
  }
}

也可以试试 shadow.
我简单做了一个demo, 如下, 效果类似.
cke_1228.png
核心代码: 主要控制, offsetY, 和 radius

.backgroundColor(Color.Yellow).shadow({
      type: ShadowType.BLUR,
      offsetY: -30,
      offsetX: 0,
      radius: 60
    })

这个额外渲染相对更费电吧,

我的方案是这样,供你参考

在鸿蒙系统上实现类似iOS的平滑过渡效果,可以通过以下方法:

  • 使用Transition组件:鸿蒙系统提供了 @Transition 装饰器,用于定义页面间的过渡效果。通过设置不同的过渡类型(如淡入淡出、滑动等),可以实现平滑的页面切换效果。
  • 利用Animation API:鸿蒙系统支持属性动画,通过 Animator 、 AnimatorSet 、 ObjectAnimator 等类,可以对组件的属性(如位置、大小、透明度等)进行动态调整,从而实现复杂的动画效果。
  • 结合自定义动画:除了内置的过渡效果,还可以通过自定义动画来实现更精细的控制。例如,使用 animation 和 animateTo 接口,可以在代码中显式定义动画效果,如渐变、旋转、缩放等。

注意事项

  • 性能优化:确保动画效果不会导致界面卡顿,可以通过减少不必要的计算和优化资源加载来提高性能。
  • 用户体验:保持动画的流畅性和自然性,避免过于复杂或突兀的效果,以提升用户体验。

通过以上方法,可以在鸿蒙系统上实现类似iOS的平滑过渡效果。

可以试试下面这两种方案

方案一:使用组件通用样式属性 linearGradientBlur(推荐)

此方案通过组件的线性渐变模糊属性直接实现,适用于图片或组件背景的平滑渐变模糊效果:

import { GradientDirection } from '@kit.ArkUI';

@Entry
@Component
struct ImageExample {
  privateResource: Resource = $r('app.media.icon'); // 替换为实际资源

  build() {
    Column() {
      Image(this.privateResource)
        .linearGradientBlur(60, {  // 模糊半径(数值越大越模糊)
          fractionStops: [
            [0, 0],     // 起始位置(0%)无模糊
            [0, 0.33],  // 33%位置开始渐变
            [1, 0.66],  // 66%位置完全模糊
            [1, 1]      // 结束位置(100%)保持模糊
          ],
          direction: GradientDirection.Bottom // 模糊渐变方向(从下到上)
        })
    }
  }
}

参数说明

  • fractionStops:二维数组定义模糊渐变节点,格式为 [位置比例, 模糊透明度](0~1范围)
  • direction:模糊渐变方向,支持:
    • GradientDirection.Top(从上到下)
    • GradientDirection.Bottom(从下到上)
    • GradientDirection.Left(从左到右)
    • GradientDirection.Right(从右到左)

方案二:结合导航组件动态模糊(特定场景)

若需在导航栏滚动时实现平滑渐变模糊,需配置 scrollEffectOpts 属性:

import { ScrollEffectType, LengthMetrics } from '@kit.ArkUI';

HdsNavigation() {
  // 内容区
}.titleBar({
  scrollEffectOpts: {
    enableScrollEffect: true,
    scrollEffectType: ScrollEffectType.GRADIENT_BLUR, // 渐变模糊类型
    blurEffectiveStartOffset: LengthMetrics.vp(0),    // 模糊生效起始位置(0vp)
    blurEffectiveEndOffset: LengthMetrics.vp(20)      // 模糊完全生效位置(20vp)
  }
})

学到了,

这么多都没有满意的?也不采纳一个[疑问]

@Entry @Component struct Index { build() { Column() { Column() { Column() .width(‘100%’) .height(‘100%’) .linearGradient({ direction: GradientDirection.Bottom, colors: [[’#000000’, 0.5], [’#00000000’, 1]], }) .blendMode(BlendMode.DST_IN, BlendApplyType.OFFSCREEN)

  }
  .width('100%')
  .height(150)
  .justifyContent(FlexAlign.SpaceBetween)
  .backgroundImageSize(ImageSize.FILL)
  .backgroundImage($r('app.media.ic_cover'))
  .blendMode(BlendMode.SRC_OVER, BlendApplyType.OFFSCREEN)

  Row() {
    Text('内容')
      .fontSize(20)
      .fontWeight(FontWeight.Bold)
      .fontColor(Color.White)
  }.width('100%')
}
.width('100%')
.height('100%')
.backgroundImageSize(ImageSize.FILL)
.backgroundImage($r('app.media.ic_bg'))

} }

你需要升级到最新版本(HarmonyOS6.0.beta1)及以上版本才行。

在HarmonyOS鸿蒙Next中,实现平滑渐变过渡主要使用ArkUI的动画API。通过属性动画(如animateTo)或转场动画(Transition),结合渐变组件(如LinearGradient)或组件状态变化,定义动画参数(时长、曲线等)。关键是在组件的状态(如位置、透明度、颜色)改变时,应用动画效果。例如,在Column或Text组件上绑定动画,当数据变化时触发平滑渐变。

在HarmonyOS Next中实现类似iOS的平滑渐变过渡,核心是使用CanvasRenderingContext2DcreateLinearGradientcreateConicGradient方法,并结合动画。你的代码尝试了@keyframesanimation,但直接操作backgroundlinear-gradient在动态变化时可能不够平滑。

更推荐使用Canvas绘制来实现高性能、可精确控制的渐变动画。以下是关键步骤和示例:

  1. 使用Canvas绘制渐变

    • Canvas组件上,通过RenderingContext创建线性渐变(createLinearGradient)。
    • 定义渐变的色标(addColorStop),色标的位置和颜色可以动态绑定到状态变量。
  2. 实现平滑动画

    • 使用animateTo函数或animation属性,在状态变化时(如点击事件)平滑地过渡色标的值(如位置offset或颜色color)。
    • 例如,可以将渐变的起始/结束点坐标或色标位置与@State变量绑定,并在事件中触发animateTo来改变这些变量。
  3. 优化性能

    • 避免在每一帧都重新创建渐变。可以预先创建好CanvasGradient对象,在动画中只更新其色标值。
    • 使用requestAnimationFrame或HarmonyOS的动画API来驱动帧更新,确保60fps的流畅度。

简单示例代码结构

@Entry
@Component
struct GradientTransition {
  private settings: RenderingContextSettings = new RenderingContextSettings(true)
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
  @State private gradientStops: number[] = [0, 0.5] // 色标位置

  build() {
    Column() {
      Canvas(this.context)
        .onReady(() => {
          // 创建渐变对象
          let gradient = this.context.createLinearGradient(0, 0, 200, 0)
          gradient.addColorStop(this.gradientStops[0], '#ff0000')
          gradient.addColorStop(this.gradientStops[1], '#0000ff')
          this.context.fillStyle = gradient
          this.context.fillRect(0, 0, 200, 200)
        })
        .onClick(() => {
          // 点击时触发平滑过渡
          animateTo({
            duration: 1000,
            curve: Curve.EaseInOut
          }, () => {
            this.gradientStops = [0.2, 0.8] // 更新色标位置
          })
        })
    }
  }
}

这种方法能更精细地控制渐变属性(如角度、颜色、色标位置)的过渡,实现与iOS媲美的平滑效果。如果渐变涉及复杂形状或蒙版,可以结合Clip或使用多个Canvas层叠。

回到顶部