img

案例介绍

本教程将介绍如何实现新闻应用动态标签的高级功能。我们将实现标签栏的主题色管理、新闻列表的动画效果等高级特性。

代码实现

@Entry
@Component
struct DynamicTabContentExample {
  @State currentIndex: number = 0
  private tabsController: TabsController = new TabsController()
  
  // 获取带透明度的颜色
  getAlphaColor(color: string, alpha: number): string {
    if (color.startsWith('#') && color.length === 7) {
      const r = parseInt(color.slice(1, 3), 16)
      const g = parseInt(color.slice(3, 5), 16)
      const b = parseInt(color.slice(5, 7), 16)
      return `rgba(${r}, ${g}, ${b}, ${alpha})`
    }
    return color
  }

  build() {
    Column() {
      Tabs({ controller: this.tabsController, index: this.currentIndex }) {
        ForEach(this.newsCategories, (category, index) => {
          TabContent() {
            List() {
              ForEach(this.newsData[category.id], (news, newsIndex) => {
                ListItem() {
                  if (news.hasImage) {
                    Row({ space: 12 }) {
                      Column({ space: 4 }) {
                        Text(news.title)
                          .fontSize(16)
                          .fontWeight(FontWeight.Medium)
                          .maxLines(2)
                          .textOverflow({ overflow: TextOverflow.Ellipsis })
                        
                        Row({ space: 8 }) {
                          Text(news.source)
                            .fontSize(12)
                            .fontColor('#666666')
                          
                          Text(news.time)
                            .fontSize(12)
                            .fontColor('#666666')
                        }
                      }
                      .layoutWeight(1)
                      .alignItems(HorizontalAlign.Start)
                      
                      Stack() {
                        Text('图')
                          .fontSize(16)
                          .fontColor('#FFFFFF')
                      }
                      .width(80)
                      .height(60)
                      .backgroundColor(category.color)
                      .borderRadius(4)
                    }
                    .width('100%')
                    .padding(16)
                  } else {
                    Column({ space: 4 }) {
                      Text(news.title)
                        .fontSize(16)
                        .fontWeight(FontWeight.Medium)
                        .maxLines(2)
                        .textOverflow({ overflow: TextOverflow.Ellipsis })
                      
                      Row({ space: 8 }) {
                        Text(news.source)
                          .fontSize(12)
                          .fontColor('#666666')
                        
                        Text(news.time)
                          .fontSize(12)
                          .fontColor('#666666')
                      }
                    }
                    .width('100%')
                    .padding(16)
                  }
                }
                .height(news.hasImage ? 92 : 72)
                .opacity(this.getItemOpacity(newsIndex))
                .animation({
                  duration: 300,
                  curve: Curve.EaseInOut,
                  delay: newsIndex * 50
                })
              })
            }
            .width('100%')
            .height('100%')
            .divider({ strokeWidth: 1, color: '#F1F3F5' })
          }
          .tabBar(this.CustomTabBar(category, index))
        })
      }
      .vertical(false)
      .scrollable(true)
      .barMode(BarMode.Scrollable)
      .barWidth('100%')
      .barHeight(48)
      .onChange((index: number) => {
        this.handleTabChange(index)
      })
    }
  }

  // 获取列表项透明度
  getItemOpacity(index: number): number {
    return Math.min(1, 0.3 + index * 0.1)
  }

  // 自定义标签栏
  @Builder
  CustomTabBar(category: { id: string, title: string, color: string }, index: number) {
    Text(category.title)
      .fontSize(16)
      .fontWeight(this.currentIndex === index ? FontWeight.Bold : FontWeight.Normal)
      .fontColor(this.currentIndex === index ? category.color : '#666666')
      .height('100%')
      .padding({ left: 16, right: 16 })
      .textAlign(TextAlign.Center)
      .borderRadius(16)
      .backgroundColor(this.currentIndex === index ? 
        this.getAlphaColor(category.color, 0.1) : 'transparent')
      .animation({
        duration: 250,
        curve: Curve.EaseInOut
      })
  }

  // 处理标签切换
  handleTabChange(index: number) {
    animateTo({
      duration: 300,
      curve: Curve.EaseInOut,
      onFinish: () => {
        this.currentIndex = index
      }
    }, () => {
      // 这里可以添加切换过程中的动画效果
    })
  }
}

代码详解

1. 主题色管理

getAlphaColor(color: string, alpha: number): string {
  if (color.startsWith('#') && color.length === 7) {
    const r = parseInt(color.slice(1, 3), 16)
    const g = parseInt(color.slice(3, 5), 16)
    const b = parseInt(color.slice(5, 7), 16)
    return `rgba(${r}, ${g}, ${b}, ${alpha})`
  }
  return color
}

主题色特点:

  • 支持透明度调整
  • 颜色格式转换
  • 统一的色彩管理
  • 增强视觉效果

2. 列表项动画

.opacity(this.getItemOpacity(newsIndex))
.animation({
  duration: 300,
  curve: Curve.EaseInOut,
  delay: newsIndex * 50
})

getItemOpacity(index: number): number {
  return Math.min(1, 0.3 + index * 0.1)
}

动画特点:

  • 渐进式透明度
  • 延迟加载效果
  • 平滑的动画曲线
  • 提升视觉体验

3. 标签栏动画

@Builder
CustomTabBar(category: { id: string, title: string, color: string }, index: number) {
  Text(category.title)
    .backgroundColor(this.currentIndex === index ? 
      this.getAlphaColor(category.color, 0.1) : 'transparent')
    .animation({
      duration: 250,
      curve: Curve.EaseInOut
    })
}

标签栏特点:

  • 平滑的状态切换
  • 主题色背景渐变
  • 文字样式动画
  • 统一的动画时间

4. 标签切换动画

handleTabChange(index: number) {
  animateTo({
    duration: 300,
    curve: Curve.EaseInOut,
    onFinish: () => {
      this.currentIndex = index
    }
  }, () => {
    // 切换动画效果
  })
}

切换特点:

  • 流畅的过渡效果
  • 完成回调处理
  • 可自定义动画
  • 优化用户体验

总结

本教程展示了如何实现新闻应用动态标签的高级功能。通过实现主题色管理、列表动画和标签切换效果,我们提升了应用的视觉体验。重点关注了动画的流畅性和主题样式的统一性,为用户提供了更加精致的新闻浏览体验。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐