项目演示

在这里插入图片描述
在这里插入图片描述

第一章 Stack布局概述

1.1 什么是Stack布局

在鸿蒙HarmonyOS ArkUI框架中,Stack是一种层叠布局容器,它允许子组件按照声明顺序依次入栈,后一个子组件覆盖前一个子组件。这种布局方式类似于CSS中的position: absolute或者Android中的FrameLayout,是实现复杂UI叠加效果的基础组件。

Stack布局的核心特点:

  • 层叠性:子组件在垂直于屏幕的方向上堆叠
  • 覆盖性:后声明的子组件位于上层,会覆盖先声明的子组件
  • 灵活性:支持多种对齐方式,可精确控制子组件位置

1.2 Stack布局的应用场景

Stack布局在实际开发中有着广泛的应用,主要包括以下场景:

场景一:图片叠加效果

Stack() {
  Image('background.jpg')
    .width('100%')
    .height(200)
  Text('图片标题')
    .fontColor('#FFFFFF')
    .fontSize(18)
}

场景二:悬浮按钮

Stack() {
  Column() {
    // 主内容区域
  }
  .width('100%')
  .height('100%')
  
  Button('悬浮按钮')
    .position({ x: 20, y: 20 })
}

场景三:遮罩层

Stack() {
  // 底层内容
  Column() {
    // 页面内容
  }
  
  // 遮罩层
  if (showMask) {
    Blank()
      .width('100%')
      .height('100%')
      .backgroundColor('rgba(0, 0, 0, 0.5)')
  }
}

1.3 Stack与其他布局容器的对比

布局容器 排列方式 适用场景 特点
Column 垂直排列 列表、表单 子组件沿垂直方向依次排列
Row 水平排列 导航栏、工具栏 子组件沿水平方向依次排列
Flex 弹性布局 复杂自适应布局 灵活的主轴和交叉轴控制
Stack 层叠排列 叠加效果、悬浮元素 子组件在垂直方向堆叠
RelativeContainer 相对定位 复杂相对布局 基于锚点的相对定位

第二章 Stack组件API详解

2.1 Stack构造函数

2.1.1 基本接口
Stack(value?: { alignContent?: Alignment })

参数说明:

参数名 类型 必填 默认值 说明
alignContent Alignment Alignment.Center 设置子组件在容器内的对齐方式
2.1.2 Alignment枚举值

Alignment枚举定义了子组件在Stack容器中的对齐方式,包含以下取值:

枚举值 数值 对齐效果
Alignment.TopStart 0 顶部左对齐
Alignment.Top 1 顶部居中对齐
Alignment.TopEnd 2 顶部右对齐
Alignment.Start 3 左对齐(垂直居中)
Alignment.Center 4 水平和垂直居中对齐
Alignment.End 5 右对齐(垂直居中)
Alignment.BottomStart 6 底部左对齐
Alignment.Bottom 7 底部居中对齐
Alignment.BottomEnd 8 底部右对齐
2.1.3 代码示例
@Entry
@Component
struct StackAlignExample {
  build() {
    Column({ space: 10 }) {
      // 顶部对齐
      Stack({ alignContent: Alignment.Top }) {
        Text('Top')
          .backgroundColor(Color.Yellow)
      }
      .width('100%')
      .height(80)
      .backgroundColor(Color.Gray)

      // 居中对齐(默认)
      Stack({ alignContent: Alignment.Center }) {
        Text('Center')
          .backgroundColor(Color.Yellow)
      }
      .width('100%')
      .height(80)
      .backgroundColor(Color.Gray)

      // 底部对齐
      Stack({ alignContent: Alignment.Bottom }) {
        Text('Bottom')
          .backgroundColor(Color.Yellow)
      }
      .width('100%')
      .height(80)
      .backgroundColor(Color.Gray)
    }
    .padding(20)
    .height('100%')
  }
}

2.2 Stack属性

2.2.1 alignContent属性

除了通过构造函数设置alignContent外,还可以通过属性链方式设置:

Stack() {
  Text('内容')
}
.width('100%')
.height(100)
.alignContent(Alignment.Center)

注意事项:

  • 当同时通过构造函数和属性链设置alignContent时,后设置的属性生效
  • alignContent属性对所有子组件生效,无法单独控制某个子组件的对齐方式
2.2.2 通用属性

Stack组件支持所有通用属性,主要包括:

尺寸属性:

  • width(value: Length | Resource) - 设置宽度
  • height(value: Length | Resource) - 设置高度
  • size({ width?: Length | Resource, height?: Length | Resource }) - 同时设置宽高

背景属性:

  • backgroundColor(value: ResourceColor) - 设置背景颜色
  • backgroundImage(value: Resource) - 设置背景图片
  • backgroundImageSize(value: ImageSize) - 设置背景图片大小

边框属性:

  • border(value: BorderOptions) - 设置边框
  • borderRadius(value: Length | Resource) - 设置圆角

内边距属性:

  • padding(value: Length | Resource | Padding) - 设置内边距

外边距属性:

  • margin(value: Length | Resource | Margin) - 设置外边距

2.3 Stack事件

Stack组件支持所有通用事件,主要包括:

触摸事件:

  • onClick(event: (event?: ClickEvent) => void) - 点击事件
  • onTouch(event: (event: TouchEvent) => void) - 触摸事件
  • onDoubleClick(event: (event?: ClickEvent) => void) - 双击事件

手势事件:

  • onPan(event: (event: PanGestureEvent) => void) - 滑动手势
  • onPinch(event: (event: PinchGestureEvent) => void) - 捏合手势
  • onRotate(event: (event: RotateGestureEvent) => void) - 旋转手势

焦点事件:

  • onFocus(event: () => void) - 获取焦点事件
  • onBlur(event: () => void) - 失去焦点事件

第三章 Stack布局核心技术:alignContent

3.1 alignContent的作用机制

alignContent参数用于控制Stack容器内所有子组件的对齐方式。它决定了子组件在容器内的位置分布。

工作原理:

  1. Stack容器先确定自身的尺寸(通过width和height属性)
  2. 然后根据alignContent的值计算子组件的偏移量
  3. 所有子组件按照相同的偏移量进行定位

示例分析:

Stack({ alignContent: Alignment.Center }) {
  Text('第一层级')
    .width('80%')
    .height('80%')
    .backgroundColor(Color.Red)
  
  Text('第二层级')
    .width('60%')
    .height('60%')
    .backgroundColor(Color.Green)
  
  Text('第三层级')
    .width('40%')
    .height('40%')
    .backgroundColor(Color.Blue)
}
.width('100%')
.height(200)

在这个例子中:

  • Stack容器高度为200
  • 第一个Text高度为160(200 * 80%),垂直方向偏移为(200 - 160) / 2 = 20
  • 第二个Text高度为120(200 * 60%),垂直方向偏移为(200 - 120) / 2 = 40
  • 第三个Text高度为80(200 * 40%),垂直方向偏移为(200 - 80) / 2 = 60

水平方向的计算方式类似。

3.2 alignContent与子组件align属性的区别

在Stack布局中,子组件也可以设置align属性,但它与容器的alignContent有本质区别:

属性 作用范围 优先级 说明
Stack.alignContent 所有子组件 容器级别的对齐设置
子组件.align 单个子组件 子组件级别的对齐设置,会覆盖容器设置

示例对比:

Stack({ alignContent: Alignment.Center }) {
  // 继承容器的居中对齐
  Text('继承容器对齐')
    .backgroundColor(Color.Red)
  
  // 覆盖容器设置,使用顶部对齐
  Text('自定义对齐')
    .backgroundColor(Color.Blue)
    .align(Alignment.Top)
}
.width('100%')
.height(150)
.backgroundColor(Color.Gray)

3.3 alignContent与position属性的配合使用

position属性可以精确控制子组件的位置,与alignContent配合使用可以实现更灵活的布局:

Stack({ alignContent: Alignment.Center }) {
  // 居中对齐(受alignContent影响)
  Text('居中内容')
    .backgroundColor(Color.Yellow)
  
  // 使用position精确定位,不受alignContent影响
  Text('精确位置')
    .backgroundColor(Color.Green)
    .position({ x: 20, y: 20 })
}
.width('100%')
.height(200)

注意: 使用position属性后,子组件的位置完全由position决定,不再受alignContent影响。

第四章 Stack布局实践案例

4.1 案例一:图片卡片布局

需求描述:
实现一个图片卡片,包含背景图片、标题、描述和标签。

@Entry
@Component
struct ImageCardExample {
  build() {
    Stack({ alignContent: Alignment.Bottom }) {
      // 背景图片
      Image('https://images.unsplash.com/photo-1506905925346-21bda4d32df4')
        .width('100%')
        .height(250)
        .borderRadius(16)
        .objectFit(ImageFit.Cover)
      
      // 渐变遮罩
      LinearGradient({
        direction: GradientDirection.Bottom,
        colors: [
          'rgba(0, 0, 0, 0.7)',
          'rgba(0, 0, 0, 0)'
        ]
      })
        .width('100%')
        .height(120)
        .align(Alignment.Bottom)
      
      // 内容区域
      Column() {
        Text('山川风景')
          .fontSize(22)
          .fontWeight(FontWeight.Bold)
          .fontColor('#FFFFFF')
        
        Text('壮丽的自然风光,令人心旷神怡')
          .fontSize(14)
          .fontColor('#FFFFFF')
          .opacity(0.8)
          .margin({ top: 4 })
        
        Row({ space: 8 }) {
          Text('自然风光')
            .fontSize(12)
            .fontColor('#FFFFFF')
            .backgroundColor('#007DFF')
            .padding({ top: 2, bottom: 2, left: 8, right: 8 })
            .borderRadius(4)
          
          Text('摄影')
            .fontSize(12)
            .fontColor('#FFFFFF')
            .backgroundColor('#6366F1')
            .padding({ top: 2, bottom: 2, left: 8, right: 8 })
            .borderRadius(4)
        }
        .margin({ top: 8 })
      }
      .padding(16)
      .align(Alignment.Bottom)
    }
    .width('90%')
    .borderRadius(16)
    .shadow({ radius: 10, color: 'rgba(0, 0, 0, 0.2)', offsetY: 4 })
  }
}

布局分析:

  1. Stack容器使用alignContent: Alignment.Bottom使所有子组件底部对齐
  2. 背景图片使用objectFit(ImageFit.Cover)确保覆盖整个区域
  3. 渐变遮罩使用LinearGradient实现从底部向上的渐变效果
  4. 内容区域使用Column垂直排列,包含标题、描述和标签

4.2 案例二:悬浮按钮布局

需求描述:
实现一个带有悬浮操作按钮的列表页面。

@Entry
@Component
struct FloatingButtonExample {
  @State listData: string[] = ['项目1', '项目2', '项目3', '项目4', '项目5']
  
  build() {
    Stack({ alignContent: Alignment.Center }) {
      // 列表内容
      Column({ space: 10 }) {
        ForEach(this.listData, (item: string, index: number) => {
          Text(item)
            .fontSize(16)
            .fontColor('#333333')
            .width('100%')
            .height(50)
            .padding({ left: 16 })
            .backgroundColor('#FFFFFF')
            .borderRadius(8)
            .align(Alignment.CenterLeft)
            .shadow({ radius: 2, color: 'rgba(0, 0, 0, 0.05)' })
        })
      }
      .width('90%')
      .padding({ top: 20 })
      
      // 悬浮按钮
      Row({ space: 12 }) {
        // 删除按钮
        Button() {
          Image($r('app.media.delete_icon'))
            .width(24)
            .height(24)
        }
        .width(56)
        .height(56)
        .backgroundColor('#EF4444')
        .borderRadius(28)
        .shadow({ radius: 8, color: 'rgba(239, 68, 68, 0.3)', offsetY: 4 })
        
        // 添加按钮
        Button() {
          Image($r('app.media.add_icon'))
            .width(24)
            .height(24)
        }
        .width(56)
        .height(56)
        .backgroundColor('#007DFF')
        .borderRadius(28)
        .shadow({ radius: 8, color: 'rgba(0, 125, 255, 0.3)', offsetY: 4 })
      }
      .position({ x: '30%', y: '85%' })
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F5F5F5')
  }
}

布局分析:

  1. Stack容器作为根容器,包含列表和悬浮按钮
  2. 列表使用Column和ForEach动态渲染
  3. 悬浮按钮使用Row水平排列两个圆形按钮
  4. 使用position属性精确控制悬浮按钮的位置

4.3 案例三:登录页面布局

需求描述:
实现一个带有背景图和渐变遮罩的登录页面。

@Entry
@Component
struct LoginPageExample {
  @State username: string = ''
  @State password: string = ''
  
  build() {
    Stack({ alignContent: Alignment.Center }) {
      // 背景图片
      Image('https://images.unsplash.com/photo-1507525428034-b723cf961d3e')
        .width('100%')
        .height('100%')
        .objectFit(ImageFit.Cover)
      
      // 渐变遮罩层
      LinearGradient({
        direction: GradientDirection.Top,
        colors: [
          'rgba(0, 0, 0, 0.6)',
          'rgba(0, 0, 0, 0.4)',
          'rgba(0, 0, 0, 0.8)'
        ]
      })
        .width('100%')
        .height('100%')
      
      // 登录表单
      Column({ space: 20 }) {
        // 标题区域
        Column({ space: 8 }) {
          Text('欢迎登录')
            .fontSize(32)
            .fontWeight(FontWeight.Bold)
            .fontColor('#FFFFFF')
          
          Text('请输入您的账号信息')
            .fontSize(14)
            .fontColor('#FFFFFF')
            .opacity(0.7)
        }
        
        // 输入框区域
        Column({ space: 16 }) {
          // 用户名输入框
          Column() {
            TextInput({ placeholder: '用户名', text: this.username })
              .fontSize(16)
              .fontColor('#FFFFFF')
              .placeholderColor('rgba(255, 255, 255, 0.5)')
              .backgroundColor('rgba(255, 255, 255, 0.1)')
              .borderRadius(12)
              .padding({ top: 16, bottom: 16, left: 20, right: 20 })
              .onChange((value: string) => {
                this.username = value
              })
          }
          
          // 密码输入框
          Column() {
            TextInput({ placeholder: '密码', text: this.password })
              .fontSize(16)
              .fontColor('#FFFFFF')
              .placeholderColor('rgba(255, 255, 255, 0.5)')
              .backgroundColor('rgba(255, 255, 255, 0.1)')
              .borderRadius(12)
              .padding({ top: 16, bottom: 16, left: 20, right: 20 })
              .type(InputType.Password)
              .onChange((value: string) => {
                this.password = value
              })
          }
        }
        
        // 登录按钮
        Button('登录')
          .width('100%')
          .height(48)
          .backgroundColor('#007DFF')
          .fontColor('#FFFFFF')
          .fontSize(18)
          .fontWeight(FontWeight.Medium)
          .borderRadius(12)
          .margin({ top: 20 })
        
        // 其他选项
        Row({ space: 20 }) {
          Text('忘记密码?')
            .fontSize(14)
            .fontColor('#FFFFFF')
            .opacity(0.7)
          
          Text('注册账号')
            .fontSize(14)
            .fontColor('#007DFF')
        }
        .margin({ top: 16 })
      }
      .width('85%')
    }
    .width('100%')
    .height('100%')
  }
}

布局分析:

  1. Stack容器使用alignContent: Alignment.Center使登录表单居中显示
  2. 背景图片使用objectFit(ImageFit.Cover)覆盖整个屏幕
  3. 渐变遮罩使用三层渐变,增强视觉层次感
  4. 登录表单使用Column垂直排列,包含标题、输入框、按钮和链接

4.4 案例四:进度条布局

需求描述:
实现一个带有数字显示的圆形进度条。

@Entry
@Component
struct CircularProgressExample {
  @State progress: number = 65
  
  build() {
    Stack({ alignContent: Alignment.Center }) {
      // 背景圆环
      Circle()
        .width(120)
        .height(120)
        .fill(Color.Transparent)
        .strokeWidth(12)
        .stroke(Color.Gray)
        .opacity(0.2)
      
      // 进度圆环
      Circle()
        .width(120)
        .height(120)
        .fill(Color.Transparent)
        .strokeWidth(12)
        .stroke(Color.Green)
        .strokeDashArray([2 * Math.PI * 60])
        .strokeDashOffset(2 * Math.PI * 60 * (1 - this.progress / 100))
        .rotate({ angle: -90 })
      
      // 中心文字
      Column({ space: 4 }) {
        Text(this.progress + '%')
          .fontSize(32)
          .fontWeight(FontWeight.Bold)
          .fontColor('#333333')
        
        Text('完成进度')
          .fontSize(12)
          .fontColor('#999999')
      }
    }
    .width('100%')
    .height(200)
  }
}

布局分析:

  1. Stack容器使用alignContent: Alignment.Center使所有元素居中
  2. 背景圆环使用灰色半透明样式
  3. 进度圆环使用strokeDashArraystrokeDashOffset实现进度效果
  4. 中心文字使用Column垂直排列,显示进度百分比和标签

第五章 Stack布局进阶技巧

5.1 Stack嵌套使用

Stack可以嵌套使用,实现更复杂的布局效果:

Stack({ alignContent: Alignment.Center }) {
  // 外层Stack
  Stack({ alignContent: Alignment.Top }) {
    Text('外层顶部')
      .backgroundColor(Color.Red)
  }
  .width('100%')
  .height(100)
  
  // 内层Stack
  Stack({ alignContent: Alignment.Bottom }) {
    Text('内层底部')
      .backgroundColor(Color.Blue)
  }
  .width('100%')
  .height(100)
}
.width('100%')
.height(200)
.backgroundColor(Color.Gray)

注意事项:

  • 嵌套的Stack各自独立计算对齐方式
  • 内层Stack的尺寸受外层Stack约束
  • 过多的嵌套会影响性能,建议控制在3层以内

5.2 Stack与Flex/Column/Row混合使用

Stack可以与其他布局容器混合使用,实现复杂的布局需求:

Stack({ alignContent: Alignment.Center }) {
  // 背景层
  Row() {
    Text('背景内容')
      .backgroundColor(Color.Yellow)
  }
  .width('100%')
  .height('100%')
  
  // 内容层
  Column({ space: 10 }) {
    Text('标题')
      .fontSize(24)
      .fontWeight(FontWeight.Bold)
    
    Text('描述文字')
      .fontSize(16)
  }
  .width('80%')
}
.width('100%')
.height(200)

使用场景:

  • 当需要同时实现层叠效果和线性排列时
  • 当需要在背景上叠加多个内容区块时
  • 当需要实现复杂的响应式布局时

5.3 条件渲染与Stack

在Stack中可以使用条件渲染控制子组件的显示和隐藏:

@Entry
@Component
struct ConditionalRenderExample {
  @State showTip: boolean = true
  
  build() {
    Stack({ alignContent: Alignment.Center }) {
      Text('主内容')
        .fontSize(20)
      
      // 条件渲染的提示信息
      if (this.showTip) {
        Text('提示信息')
          .fontSize(14)
          .fontColor('#FFFFFF')
          .backgroundColor('#FF6B35')
          .padding({ top: 8, bottom: 8, left: 16, right: 16 })
          .borderRadius(20)
          .position({ x: '10%', y: '30%' })
      }
    }
    .width('100%')
    .height(200)
    .backgroundColor(Color.Gray)
  }
}

应用场景:

  • 加载状态显示
  • 错误提示信息
  • 用户引导提示
  • 弹窗遮罩层

5.4 动画效果与Stack

Stack布局非常适合实现动画效果:

@Entry
@Component
struct StackAnimationExample {
  @State scale: number = 1
  @State opacity: number = 1
  
  build() {
    Stack({ alignContent: Alignment.Center }) {
      Text('动画内容')
        .fontSize(24)
        .fontColor('#FFFFFF')
        .backgroundColor('#007DFF')
        .padding({ top: 20, bottom: 20, left: 40, right: 40 })
        .borderRadius(12)
        .scale({ x: this.scale, y: this.scale })
        .opacity(this.opacity)
    }
    .width('100%')
    .height(200)
    .backgroundColor(Color.Gray)
    .onClick(() => {
      animateTo({ duration: 500, curve: Curve.EaseInOut }, () => {
        this.scale = this.scale === 1 ? 1.2 : 1
        this.opacity = this.opacity === 1 ? 0.8 : 1
      })
    })
  }
}

动画类型:

  • 缩放动画(scale)
  • 透明度动画(opacity)
  • 旋转动画(rotate)
  • 位移动画(translate)
  • 组合动画

第六章 Stack布局性能优化

6.1 性能问题分析

Stack布局在以下情况下可能会出现性能问题:

问题一:过多的子组件

Stack() {
  // 不推荐:过多子组件会导致渲染性能下降
  ForEach(largeDataList, (item) => {
    Text(item)
  })
}

问题二:频繁的状态更新

@State items: string[] = []

build() {
  Stack() {
    // 不推荐:频繁更新会导致Stack重新渲染
    ForEach(this.items, (item) => {
      Text(item)
    })
  }
}

问题三:嵌套过深

Stack() {
  Stack() {
    Stack() {
      // 不推荐:三层以上嵌套会影响布局计算性能
      Text('内容')
    }
  }
}

6.2 性能优化策略

策略一:控制子组件数量

// 推荐:使用懒加载或分页加载
Stack() {
  ForEach(this.visibleItems, (item) => {
    Text(item)
  })
}

策略二:使用@Builder提取重复组件

@Builder
buildItem(item: string) {
  Text(item)
    .fontSize(16)
    .backgroundColor('#FFFFFF')
}

build() {
  Stack() {
    this.buildItem('项目1')
    this.buildItem('项目2')
  }
}

策略三:避免不必要的重渲染

// 推荐:使用@Prop或@Link传递状态,避免父组件不必要的重渲染
@Component
struct ChildComponent {
  @Prop text: string
  
  build() {
    Text(this.text)
  }
}

@Entry
@Component
struct ParentComponent {
  @State count: number = 0
  @State text: string = '固定文本'
  
  build() {
    Stack() {
      // 只有text变化时才会重渲染
      ChildComponent({ text: this.text })
    }
    .onClick(() => {
      this.count++
    })
  }
}

策略四:使用LazyForEach优化列表渲染

Stack() {
  // 推荐:对于大量数据使用LazyForEach
  LazyForEach(this.dataSource, (item) => {
    Text(item)
  })
}

6.3 性能监控与调试

方法一:使用hilog输出性能日志

import { hilog } from '@kit.PerformanceAnalysisKit'

@Entry
@Component
struct PerformanceMonitorExample {
  build() {
    Stack() {
      Text('内容')
    }
    .onAppear(() => {
      hilog.info(0x0000, 'StackPerformance', 'Stack组件已渲染')
    })
  }
}

方法二:使用DevEco Studio性能分析工具

  1. 打开DevEco Studio的Profiler工具
  2. 选择"Performance"选项卡
  3. 运行应用并进行操作
  4. 分析渲染时间和内存使用情况

方法三:使用renderingPerformance API

import { renderingPerformance } from '@kit.ArkUI'

@Entry
@Component
struct RenderingPerformanceExample {
  build() {
    Stack() {
      Text('内容')
    }
    .onAppear(() => {
      const performanceInfo = renderingPerformance.getRenderingPerformanceInfo()
      console.info('渲染性能信息:', JSON.stringify(performanceInfo))
    })
  }
}

第七章 Stack布局最佳实践

7.1 命名规范

组件命名:

  • 使用PascalCase命名组件
  • 组件名应反映其功能或用途
// 推荐
@Component
struct ImageCard {
  build() {
    Stack() {
      // 内容
    }
  }
}

// 不推荐
@Component
struct MyStack {
  build() {
    Stack() {
      // 内容
    }
  }
}

状态变量命名:

  • 使用驼峰命名法
  • 变量名应清晰表达其含义
// 推荐
@State isLoading: boolean = false
@State userName: string = ''

// 不推荐
@State flag: boolean = false
@State name: string = ''

7.2 代码组织

分离关注点:

  • 将UI组件与业务逻辑分离
  • 使用@Builder提取重复的UI片段
@Entry
@Component
struct MainPage {
  @State data: string[] = ['项目1', '项目2', '项目3']
  
  @Builder
  buildHeader() {
    Stack({ alignContent: Alignment.Center }) {
      Text('页面标题')
        .fontSize(24)
        .fontWeight(FontWeight.Bold)
    }
    .width('100%')
    .height(60)
    .backgroundColor('#FFFFFF')
  }
  
  @Builder
  buildItem(item: string) {
    Stack() {
      Text(item)
        .fontSize(16)
    }
    .width('100%')
    .height(50)
    .backgroundColor('#F5F5F5')
    .borderRadius(8)
  }
  
  build() {
    Column() {
      this.buildHeader()
      
      Column({ space: 10 }) {
        ForEach(this.data, (item) => {
          this.buildItem(item)
        })
      }
      .padding(16)
    }
    .width('100%')
    .height('100%')
  }
}

7.3 错误处理

空状态处理:

@Entry
@Component
struct EmptyStateExample {
  @State data: string[] = []
  
  build() {
    Stack({ alignContent: Alignment.Center }) {
      if (this.data.length === 0) {
        // 空状态显示
        Column({ space: 10 }) {
          Image($r('app.media.empty_icon'))
            .width(64)
            .height(64)
          
          Text('暂无数据')
            .fontSize(16)
            .fontColor('#999999')
        }
      } else {
        // 有数据时显示
        Column() {
          ForEach(this.data, (item) => {
            Text(item)
          })
        }
      }
    }
    .width('100%')
    .height('100%')
  }
}

异常状态处理:

@Entry
@Component
struct ErrorStateExample {
  @State error: string = ''
  
  build() {
    Stack({ alignContent: Alignment.Center }) {
      if (this.error) {
        Column({ space: 10 }) {
          Image($r('app.media.error_icon'))
            .width(64)
            .height(64)
          
          Text(this.error)
            .fontSize(16)
            .fontColor('#EF4444')
          
          Button('重试')
            .onClick(() => {
              this.error = ''
              // 重新加载数据
            })
        }
      } else {
        // 正常内容
        Text('正常内容')
      }
    }
    .width('100%')
    .height('100%')
  }
}

7.4 测试策略

单元测试:

import { describe, it, expect } from '@ohos/hypium'

export default function StackLayoutTest() {
  describe('Stack布局测试', () => {
    it('测试居中对齐', () => {
      // 验证Stack组件的alignContent属性是否正确工作
      expect(true).assertTrue()
    })
    
    it('测试子组件覆盖顺序', () => {
      // 验证子组件的层叠顺序是否正确
      expect(true).assertTrue()
    })
  })
}

UI测试:

import { hilog } from '@kit.PerformanceAnalysisKit'

@Entry
@Component
struct StackUITest {
  build() {
    Stack({ alignContent: Alignment.Center }) {
      Text('测试内容')
        .onAppear(() => {
          hilog.info(0x0000, 'StackUITest', '测试组件已显示')
        })
    }
    .width('100%')
    .height(200)
  }
}

第八章 Stack布局常见问题与解决方案

8.1 问题一:子组件无法居中显示

问题描述:
设置了alignContent: Alignment.Center,但子组件仍然无法居中显示。

可能原因:

  1. Stack容器没有设置宽度和高度
  2. 子组件使用了position属性
  3. 子组件设置了align属性覆盖了容器的设置

解决方案:

// 正确写法
Stack({ alignContent: Alignment.Center }) {
  Text('居中内容')
}
.width('100%')
.height(200)

// 错误写法
Stack({ alignContent: Alignment.Center }) {
  Text('无法居中')
    .position({ x: 0, y: 0 }) // 使用position后不受alignContent影响
}
// 没有设置宽度和高度

8.2 问题二:子组件重叠显示

问题描述:
多个子组件重叠在一起,无法区分层级。

可能原因:

  1. 子组件尺寸相同或过大
  2. 子组件没有设置背景色或透明度

解决方案:

// 正确写法:通过尺寸和背景色区分层级
Stack({ alignContent: Alignment.Center }) {
  Text('底层')
    .width('100%')
    .height('100%')
    .backgroundColor(Color.Red)
  
  Text('中层')
    .width('80%')
    .height('80%')
    .backgroundColor(Color.Green)
  
  Text('顶层')
    .width('60%')
    .height('60%')
    .backgroundColor(Color.Blue)
}
.width('100%')
.height(200)

8.3 问题三:Stack布局在不同屏幕尺寸下显示异常

问题描述:
在某些屏幕尺寸下,Stack布局显示异常。

可能原因:

  1. 使用了固定尺寸(如px)
  2. 没有考虑响应式布局
  3. 子组件尺寸超出容器范围

解决方案:

// 推荐:使用百分比或自适应尺寸
Stack({ alignContent: Alignment.Center }) {
  Text('自适应内容')
    .width('80%') // 使用百分比
    .maxWidth(400) // 设置最大宽度
}
.width('100%')
.height('100%')

8.4 问题四:Stack嵌套导致布局混乱

问题描述:
嵌套的Stack布局显示混乱,无法达到预期效果。

可能原因:

  1. 嵌套的Stack没有正确设置尺寸
  2. 对齐方式冲突
  3. 子组件溢出

解决方案:

// 推荐:明确设置每个Stack的尺寸
Stack({ alignContent: Alignment.Center }) {
  Stack({ alignContent: Alignment.Top }) {
    Text('内层内容')
  }
  .width('100%') // 明确设置宽度
  .height(100) // 明确设置高度
}
.width('100%')
.height(200)

第九章 Stack布局与其他技术的集成

9.1 Stack与状态管理

使用@State管理状态:

@Entry
@Component
struct StackStateManagement {
  @State count: number = 0
  @State showPanel: boolean = false
  
  build() {
    Stack({ alignContent: Alignment.Center }) {
      Text('点击次数: ' + this.count)
        .fontSize(24)
      
      if (this.showPanel) {
        Text('弹出面板')
          .backgroundColor('#007DFF')
          .fontColor('#FFFFFF')
          .padding({ top: 20, bottom: 20, left: 40, right: 40 })
          .borderRadius(12)
      }
    }
    .width('100%')
    .height(200)
    .onClick(() => {
      this.count++
      this.showPanel = !this.showPanel
    })
  }
}

使用@Link实现父子组件通信:

@Component
struct ChildPanel {
  @Link show: boolean
  
  build() {
    Stack() {
      Text('子组件面板')
    }
    .width('100%')
    .height(100)
    .backgroundColor('#007DFF')
    .onClick(() => {
      this.show = false
    })
  }
}

@Entry
@Component
struct ParentPage {
  @State showPanel: boolean = true
  
  build() {
    Stack({ alignContent: Alignment.Center }) {
      ChildPanel({ show: $showPanel })
    }
    .width('100%')
    .height(200)
  }
}

9.2 Stack与路由跳转

import { router } from '@kit.CoreServicesKit'

@Entry
@Component
struct StackRouterExample {
  build() {
    Stack({ alignContent: Alignment.Center }) {
      Text('点击跳转')
        .fontSize(24)
        .onClick(() => {
          router.pushUrl({
            url: 'pages/DetailPage'
          })
        })
      
      // 返回按钮
      Button('返回')
        .position({ x: 20, y: 20 })
        .onClick(() => {
          router.back()
        })
    }
    .width('100%')
    .height('100%')
  }
}

9.3 Stack与数据存储

import { preferences } from '@kit.CoreDataKit'

@Entry
@Component
struct StackStorageExample {
  @State userName: string = ''
  
  aboutToAppear() {
    this.loadUserName()
  }
  
  async loadUserName() {
    const preferencesManager = preferences.getPreferencesSync(this.context, 'user_info')
    this.userName = preferencesManager.get('user_name', '') as string
  }
  
  build() {
    Stack({ alignContent: Alignment.Center }) {
      Text('欢迎, ' + this.userName)
        .fontSize(24)
    }
    .width('100%')
    .height('100%')
  }
}

第十章 Stack布局未来发展趋势

10.1 HarmonyOS NEXT中的Stack优化

性能优化:

  • HarmonyOS NEXT对Stack布局进行了底层优化,减少了布局计算时间
  • 引入了虚拟布局技术,支持更高效的子组件渲染

新特性支持:

  • 支持更多的对齐方式和布局选项
  • 增强了动画和过渡效果支持
  • 提供了更丰富的交互能力

10.2 Stack布局的应用前景

跨平台适配:

  • Stack布局在不同设备上表现一致
  • 支持手机、平板、智慧屏等多种设备

复杂UI场景:

  • 适合实现复杂的叠加效果和交互界面
  • 是构建现代化UI的基础组件

性能与体验:

  • 随着设备性能的提升,Stack布局的应用场景将更加广泛
  • 与其他布局容器配合使用,可实现更复杂的布局需求

附录

A. Alignment枚举值速查表

枚举值 数值 水平对齐 垂直对齐
Alignment.TopStart 0
Alignment.Top 1 居中
Alignment.TopEnd 2
Alignment.Start 3 居中
Alignment.Center 4 居中 居中
Alignment.End 5 居中
Alignment.BottomStart 6
Alignment.Bottom 7 居中
Alignment.BottomEnd 8

B. Stack属性速查表

属性名 类型 说明
width Length | Resource 设置宽度
height Length | Resource 设置高度
backgroundColor ResourceColor 设置背景颜色
borderRadius Length | Resource 设置圆角
padding Length | Resource | Padding 设置内边距
margin Length | Resource | Margin 设置外边距
alignContent Alignment 设置子组件对齐方式

C. 相关资源链接


总结:

Stack布局是鸿蒙HarmonyOS ArkUI框架中重要的布局容器之一,它提供了层叠排列子组件的能力,是实现复杂UI效果的基础。通过合理使用alignContent参数和其他属性,可以实现各种对齐方式和布局效果。在实际开发中,需要注意性能优化和代码组织,以确保应用的流畅运行和可维护性。

随着HarmonyOS NEXT的发展,Stack布局将不断优化和增强,为开发者提供更强大的布局能力和更好的开发体验。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐