【HarmonyOS】层级轮播卡片效果

news2025/1/10 2:56:39

【HarmonyOS】层级轮播卡片效果

一、功能效果:

在这里插入图片描述
1.上下堆叠由大到小的卡片层叠效果。

2.上层卡片可手势左右滑动,自动左滑动。

3.三层卡片随滑动,内容进行依次切换。

二、开发思路

【完整代码见章节三】

1.最上层使用swiper进行轮播效果的实现。


  
  HeadSwiperLayerView() {
    Swiper(this.swiperController) {
      this.HeadCard()
      this.MiddenCard()
      this.EndCard()
    }
    .loop(true)
    .autoPlay(true)
    .indicator(false)
    .duration(500)
    .curve(Curve.Friction)
    .displayMode(SwiperDisplayMode.STRETCH)
    .onChange(this.monChangeCallBack)
    .onAnimationEnd(this.monAnimationEndCallBack)

  }

  
  HeadCard() {
    Row() {
       if (this.HEAD_INDEX == this.mIndex) {
        Image(this.mImageResource[this.HEAD_INDEX])
          .BGCardCardWidthAndHeight()
          .opacity(this.mCardOpacity)
          .CardAnim()
          .borderWidth(px2vp(2))
          .borderColor(Color.Red)
          .backgroundColor(Color.Blue)

      }
    }
    .BGWidthAndHeight()
  }

// MiddenCard EndCard 卡片依照HeadCard进行创建

2.下层两个卡片使用stack堆叠,依次显示。


  build() {
    Stack({ alignContent: Alignment.Center }) {
      // 最底层卡片
      this.EndLayerView()

      // 中间层卡片
      this.MiddenLayerView()

      // 最上层swiper滑动层
      this.HeadSwiperLayerView()
    }
  }

3.整体卡片内容通过list数据进行链式切换。

  // 卡片图片资源池
   mImageResource: Array<string | Resource > = [
    $r("app.media.icon_img1"),
    $r("app.media.icon_img2"),
    $r("app.media.icon_img3"),
    $r("app.media.icon_img4"),
    $r("app.media.icon_img5"),
  ];
  



4.调整切换的index下标数据,控制数据切换,和逻辑计算。

  getImageResource(current: number, mIndex: number) {
    let currentPage: string | Resource = ''
    if (current == this.END_INDEX) {
      if (mIndex == this.HEAD_INDEX) {
        currentPage = this.mImageResource[2];
      } else if (mIndex == this.MIDDEN_INDEX) {
        currentPage = this.mImageResource[0];
      } else if (mIndex == this.END_INDEX) {
        currentPage = this.mImageResource[1];
      }
    } else if (current == this.MIDDEN_INDEX) {
      if (mIndex >= 2) {
        currentPage = this.mImageResource[0];
      } else {
        currentPage = this.mImageResource[mIndex+1];
      }
    } else if (current == this.HEAD_INDEX) {
      currentPage = this.mImageResource[this.mIndex];
    }

    return currentPage;
  }

5.细磨效果,添加透明度动画润色过渡操作的效果。(为了效果更好后续也可添加移动,放大缩小等。示例代码只是添加了透明度。)

三、DEMO示例代码:

滑动组件View
SlidingCardView.ets



/**
 * 层叠轮播图
 */

export default struct SlidingCardView {
  // 滑动层 透明背景宽高
  private BG_WIDTH: number = px2vp(800);
  private BG_HEIGHT: number = px2vp(800);
  // 滑动层 可视卡片宽高
  private BG_CARD_WIDTH: number = px2vp(700);
  private BG_CARD_HEIGHT: number = px2vp(800);
  private CARD_ANIM_START: number = 0.1;
  private CARD_ANIM_END: number = 1;
  private LAYER_CARD_ANIM_START: number = 0.9;
  private LAYER_CARD_ANIM_END: number = 1;
  // 移动下标
   mIndex: number = 0;

   mCardOpacity: number = this.CARD_ANIM_END;
   mLayerOpacity: number = this.LAYER_CARD_ANIM_END;
  // 卡片图片资源池
   mImageResource: Array<string | Resource > = [
    $r("app.media.icon_img1"),
    $r("app.media.icon_img2"),
    $r("app.media.icon_img3"),
    $r("app.media.icon_img4"),
    $r("app.media.icon_img5"),
  ];
  private swiperController: SwiperController = new SwiperController();
  private END_INDEX: number = 2;
  private MIDDEN_INDEX: number = 1;
  private HEAD_INDEX: number = 0;

  getImageResource(current: number, mIndex: number) {
    let currentPage: string | Resource = ''
    if (current == this.END_INDEX) {
      if (mIndex == this.HEAD_INDEX) {
        currentPage = this.mImageResource[2];
      } else if (mIndex == this.MIDDEN_INDEX) {
        currentPage = this.mImageResource[0];
      } else if (mIndex == this.END_INDEX) {
        currentPage = this.mImageResource[1];
      }
    } else if (current == this.MIDDEN_INDEX) {
      if (mIndex >= 2) {
        currentPage = this.mImageResource[0];
      } else {
        currentPage = this.mImageResource[mIndex+1];
      }
    } else if (current == this.HEAD_INDEX) {
      currentPage = this.mImageResource[this.mIndex];
    }

    return currentPage;
  }

  private monAnimationEndCallBack = (): void => {
    this.mLayerOpacity = 0.9;
  }

  private monChangeCallBack = (index: number): void => {
    this.mIndex = index;
    this.mCardOpacity = this.CARD_ANIM_START;
    this.mLayerOpacity = this.LAYER_CARD_ANIM_START;
    setTimeout(() => {
      this.mCardOpacity = this.CARD_ANIM_END;
      this.mLayerOpacity = this.LAYER_CARD_ANIM_END;
    }, 100);
  }

  
  EndLayerView() {
    Row() {
      Blank()
      Image(this.getImageResource(this.END_INDEX, this.mIndex))
        .width(px2vp(500))
        .height(px2vp(600))
        .opacity(this.mLayerOpacity)
        .CardAnim()
        .borderWidth(px2vp(2))
        .borderColor(Color.Red)
        .backgroundColor(Color.Black)
    }
    .width(px2vp(1000))
    .height(px2vp(800))
  }

  
  MiddenLayerView() {
    Row() {
      Blank()
      Image(this.getImageResource(this.MIDDEN_INDEX, this.mIndex))
        .width(px2vp(400))
        .height(px2vp(700))
        .opacity(this.mLayerOpacity)
        .CardAnim()
        .borderWidth(px2vp(2))
        .borderColor(Color.Red)
        .backgroundColor(Color.Red)
    }
    .width(px2vp(800))
    .height(px2vp(800))
  }

  
  HeadCard() {
    Row() {
       if (this.HEAD_INDEX == this.mIndex) {
        Image(this.mImageResource[this.HEAD_INDEX])
          .BGCardCardWidthAndHeight()
          .opacity(this.mCardOpacity)
          .CardAnim()
          .borderWidth(px2vp(2))
          .borderColor(Color.Red)
          .backgroundColor(Color.Blue)

      }
    }
    .BGWidthAndHeight()
  }

  
  MiddenCard() {
    Row() {
      if (this.MIDDEN_INDEX == this.mIndex) {
        Image(this.mImageResource[this.MIDDEN_INDEX])
          .BGCardCardWidthAndHeight()
          .opacity(this.mCardOpacity)
          .CardAnim()
          .borderWidth(px2vp(2))
          .borderColor(Color.Red)
          .backgroundColor(Color.Blue)

       }
    }
    .BGWidthAndHeight()
  }

  
  EndCard() {
    Row() {
      if (this.END_INDEX == this.mIndex) {
        Image(this.mImageResource[this.END_INDEX])
          .BGCardCardWidthAndHeight()
          .opacity(this.mCardOpacity)
          .CardAnim()
          .borderWidth(px2vp(2))
          .borderColor(Color.Red)
          .backgroundColor(Color.Blue)

       }
    }
    .BGWidthAndHeight()
  }

  
  HeadSwiperLayerView() {
    Swiper(this.swiperController) {
      this.HeadCard()
      this.MiddenCard()
      this.EndCard()
    }
    .loop(true)
    .autoPlay(true)
    .indicator(false)
    .duration(500)
    .curve(Curve.Friction)
    .displayMode(SwiperDisplayMode.STRETCH)
    .onChange(this.monChangeCallBack)
    .onAnimationEnd(this.monAnimationEndCallBack)

  }

  
  BGWidthAndHeight(){
    .width(this.BG_WIDTH)
    .height(this.BG_HEIGHT)
  }

  
  BGCardCardWidthAndHeight(){
    .width(this.BG_CARD_WIDTH)
    .height(this.BG_CARD_HEIGHT)
    .borderWidth(px2vp(2))
    .borderColor(Color.Red)
  }

  
  CardAnim(){
    .animation({
      duration: 1000,
      tempo: 1,
      delay: 0,
      curve: Curve.Friction,
      playMode: PlayMode.Normal,
      iterations: 1
    })
  }

  build() {
    Stack({ alignContent: Alignment.Center }) {
      // 最底层卡片
      this.EndLayerView()

      // 中间层卡片
      this.MiddenLayerView()

      // 最上层swiper滑动层
      this.HeadSwiperLayerView()
    }
  }
}

入口界面类
Index.ets

import SlidingCardView from './SlidingCardView'



struct Index {

  build() {
    Column(){
      SlidingCardView()
    }
    .width("100%")
    .height("100%")
  }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2255074.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Postman自定义脚本Pre-request-script以及Test

这两个都是我们进行自定义script脚本的地方&#xff0c;分别是在请求执行的前后运行。 我们举两个可能经常运用到的场景。 (一)请求A先执行&#xff0c;请求B使用请求A响应结果作为参数。如果我们不用自定义脚本&#xff0c;可能得先执行请求A&#xff0c;然后手动复制响应结果…

一些引入依赖,提示引入方式报错的问题

背景 当我们使用gulp自动化处理文件的时候&#xff0c;难免会遇到需要按照一定条件过滤的需求&#xff0c;这里博主所遇到问题是&#xff0c;通过文件内容中是否包含 某一串字符串 决定过滤当前的文件 比如&#xff1a; 碰到文件中包含注释 * replace-note 此文件未被引用 ,那…

R语言 | 峰峦图 / 山脊图

目的&#xff1a;为展示不同数据分布的差异。 1. ggplot2 实现 # 准备数据 datmtcars[, c("mpg", "cyl")] colnames(dat)c("value", "type") head(dat) # value type #Mazda RX4 21.0 6 #Mazda RX4 Wag …

6月份stable diffusion animatediff等插件使用指南,又来更新了

插件一直会更新&#xff0c;包含了基本市面上流行的90%插件&#xff0c;好用的插件更是不会错过&#xff0c;往期插件请看往期文章&#xff0c;如果你没有时间一直关注sd更新的进展&#xff0c;请关注我&#xff0c;一个月用几个小时看一下我的文章&#xff0c;最短时间跟进sd。…

jmeter配置

单接口运行没问题&#xff0c;但是批量执行100个线程数发现总是提示请求不合法 最后发现 需要将配置改成 正好回归一下这个配置&#xff1a; Ramp-Up时间&#xff08;秒&#xff09;的定义&#xff1a; Ramp-Up时间是指在JMeter测试中&#xff0c;所有指定的线程&#xff08…

WPF中的VisualState(视觉状态)

以前在设置控件样式或自定义控件时&#xff0c;都是使用触发器来进行样式更改。触发器可以在属性值发生更改时启动操作。 像这样&#xff1a; <Style TargetType"ListBoxItem"><Setter Property"Opacity" Value"0.5" /><Setter …

如何利用Java爬虫获得商品类目

在当今数字化时代&#xff0c;数据已成为企业最宝贵的资产之一。获取和分析数据的能力对于任何希望在市场上保持竞争力的企业来说都是至关重要的。对于电子商务平台和市场研究公司而言&#xff0c;获取商品类目数据尤为重要&#xff0c;因为这些数据可以帮助他们更好地理解市场…

【Linux】程序的编译过程

程序的翻译过程 预处理&#xff08;头文件展开&#xff0c;条件编译&#xff0c;宏替换&#xff0c;去注释&#xff09;编译 &#xff1a;把c变成汇编语言汇编 &#xff1a;把汇编变成二进制&#xff08;不可执行&#xff0c;二进制目标文件&#xff09;链接 &#xff1a;把自…

#渗透测试#SRC漏洞挖掘# 操作系统-windows系统番外练习

免责声明 本教程仅为合法的教学目的而准备&#xff0c;严禁用于任何形式的违法犯罪活动及其他商业行为&#xff0c;在使用本教程前&#xff0c;您应确保该行为符合当地的法律法规&#xff0c;继续阅读即表示您需自行承担所有操作的后果&#xff0c;如有异议&#xff0c;请立即停…

信奥常考点:二叉树的构建(已知中序和 前序或后序 的情况下)

一、题目引入 这是来自CCF-GESP C七级认证 2024年9月的题目。 我们在此不解题&#xff0c;只把树画出来。 CCF-GESP 编程能力认证 C 七级 2024年9月份详细解析-CSDN博客 二、解题过程 我们可以根据先序遍历得出根节点是A&#xff0c;然后我们得到了A的左子树[B D]&#xff08;橙…

自回归模型(AR )

最近看到一些模型使用了自回归方法&#xff0c;这里就学习一下整理一下相关内容方便以后查阅。 自回归模型&#xff08;AR &#xff09; 自回归模型&#xff08;AR &#xff09;AR 模型的引入AR 模型的定义参数的估计方法模型阶数选择平稳性与因果性条件自相关与偏自相关函数优…

筑起厂区安全--叉车安全防护装置全解析

在繁忙的工业生产领域中&#xff0c;叉车作为搬运工&#xff0c;穿梭于仓储与生产线之间。然而&#xff0c;叉车的高效运作背后&#xff0c;也隐藏着诸多安全风险&#xff0c;尤其是在那些空间狭小、物流繁忙的环境中。为了降低这些潜在的危险&#xff0c;叉车安全防护装置便成…

Dropout: 一种减少神经网络过拟合的技术

在深度学习中&#xff0c;过拟合是一个常见的问题&#xff0c;尤其是在模型复杂度较高或训练数据较少的情况下。过拟合意味着模型在训练数据上表现得很好&#xff0c;但在未见过的数据上表现不佳&#xff0c;即泛化能力差。为了解决这个问题&#xff0c;研究者们提出了多种正则…

剖析千益畅行,共享旅游-卡,合规运营与技术赋能双驱下的旅游新篇

在数字化浪潮席卷各行各业的当下&#xff0c;旅游产业与共享经济模式深度融合&#xff0c;催生出旅游卡这类新兴产品。然而&#xff0c;市场乱象丛生&#xff0c;诸多打着 “共享” 幌子的旅游卡弊病百出&#xff0c;让从业者与消费者都深陷困扰。今天&#xff0c;咱们聚焦技术…

2024.11.29——[HCTF 2018]WarmUp 1

拿到题&#xff0c;发现是一张图&#xff0c;查看源代码发现了被注释掉的提示 <!-- source.php--> step 1 在url传参看看这个文件&#xff0c;发现了这道题的源码 step 2 开始审计代码&#xff0c;分析关键函数 //mb_strpos($haystack,$needle,$offset,$encoding):int|…

电压和电流

1.电压&#xff1a;是一个相对的概念。 2.电压的形成。&#xff08;类似于一个泵&#xff0c;中间被隔开&#xff0c;把所有的负电和正电弄在一旁&#xff09; 3.电流的形成&#xff1a;有了电压&#xff0c;才会由电流&#xff08;才会有电子的移动&#xff09;。

泰坦军团品牌焕新:LOGO变更开启电竞细分市场新篇章

深圳世纪创新显示电子有限公司旗下的高端电竞显示器品牌泰坦军团&#xff0c;上月发布通告&#xff0c;自2024年6月起已陆续进行品牌升级和LOGO变更。 泰坦军团自2015年成立以来&#xff0c;凭借先进的技术和顶级的工业设计&#xff0c;已成为众多年轻人首选的游戏显示器品牌&…

Spring框架-IoC的使用(基于XML和注解两种方式)

一、Spring IoC使用-基于XML 1 IoC使用-基于XML 使用SpringIoC组件创建并管理对象 1.1 创建实体类 package com.feng.ioc.bean;import java.util.Date;/*** program: spring-ioc-demo1* description: 学生实体类* author: FF* create: 2024-12-04 18:53**/ public class Stud…

三菱JET伺服CC-Link IE现场网络Basic链接软元件(RYn/RXn)(RWwn/RWrn)

链接软元件(RYn/RXn) 要点 在循环通信中对主站发送给伺服放大器的请求(RYn及RWwn)设定了范围外的值时&#xff0c;将无法反映设定内容。 循环通信的请求报文与响应报文的收发数据被换读为伺服放大器的对象数据(RYn、RXn)。 响应报文的设定值可进行变更。变更初始设定值时&…

解决Unity编辑器Inspector视图中文注释乱码

1.问题介绍 新创建一个脚本&#xff0c;用VS打开编辑&#xff0c;增加一行中文注释保存&#xff0c;在Unity中找到该脚本并选中&#xff0c;Inspector视图中预览的显示内容&#xff0c;该中文注释显示为乱码&#xff0c;如下图所示&#xff1a; 2.图示解决步骤 按上述步骤操作…