鸿蒙开发画廊效果

news2024/9/22 19:33:38
鸿蒙开发画廊效果:

画廊这种效果确实不错,看起来高端大气。在Android那边已经有不少案例了,但是鸿蒙这边还是很少。今天来分享一个。

先看下效果图:

在这里插入图片描述没法弄gif,就是左右可以看到前一张,下一张。
也可以看我b站完整的视频:https://www.bilibili.com/video/BV13eHre7EK9/

实现思路:

Swiper的onGestureSwipe里面算偏移量

部分参考代码:
@Component
export struct CardSwiper {
  // 卡片数据源
  data: BaseDataSource<UserDataBean> = new BaseDataSource()
  // 卡片偏移度列表
  @State private cardsOffset: number[] = [];
  // 屏幕宽度
  private displayWidth: number = 0;
  // Swiper 两侧的偏移量
  private swiperMargin: number = CommonConstants.SWIPER_MARGIN;
  // Swiper 当前索引值
  @State private currentSwiperIndex: number = 0;
  private readonly DEVICESIZE: number = 600; // 依据Navigation的mode属性说明,如使用Auto,窗口宽度>=600vp时,采用Split模式显示;窗口宽度<600vp时,采用Stack模式显示。

  onChange?:(index:number)=>void
  controller: SwiperController = new SwiperController();

  aboutToAppear(): void {
    // 获取屏幕大小,用于后续计算卡片的偏移量
    const displayData: display.Display = display.getDefaultDisplaySync();
    this.displayWidth = px2vp(displayData.width);
    if ((display.isFoldable() && display.getFoldStatus() === display.FoldStatus.FOLD_STATUS_EXPANDED) || this.displayWidth >= this.DEVICESIZE) {
      this.displayWidth = px2vp(displayData.width) / 2;
    }
    // 计算当前卡片及关联卡片的偏移量
    this.calculateOffset(0);

  }



  build() {
    Column() {
      Swiper(this.controller) {
        LazyForEach(this.data, (item: UserDataBean, index: number) => {
          CardComponent({
            userInfo: item,
            cardOffset: this.cardsOffset[index],
            cardIndex: index,
            showingCard: this.currentSwiperIndex,
            cardWith:this.displayWidth - 160,
            cardHeight:this.displayWidth - 100,
          })
        },(item: UserDataBean,index:number) => `${index}-${JSON.stringify(item)}`)
      }
      .index($$this.currentSwiperIndex)
      .loop(false)
      .prevMargin(this.swiperMargin)
      .nextMargin(this.swiperMargin)
      .duration(CommonConstants.DURATION)
      .curve(Curve.Friction)
      .onChange((index) => {
        this.calculateOffset(index);
        this.onChange?.(index)
      })
      .indicator(false)
      .onGestureSwipe((index, event) => {
        const currentOffset = event.currentOffset;
        // 获取当前卡片(居中)的原始偏移量
        const maxOffset = this.getMaxOffset(index) / 2;
        // 实时维护卡片的偏移量列表,做到跟手效果
        if (currentOffset < 0) {
          // 向左偏移
          /*
           * 此处计算原理为:按照比例设置卡片的偏移量。
           * 当前卡片居中,向左滑动后将在左边,此时卡片偏移量即为 maxOffset * 2(因为向右对齐)。
           * 所以手指能够滑动的最大距离(this.displayWidth)所带来的偏移量即为 maxOffset。
           * 易得公式:卡片实时偏移量 = (手指滑动长度 / 屏幕宽度) * 卡片最大可偏移量 + 当前偏移量。
           * 之后的计算原理相同,将不再赘述。
           */
          this.cardsOffset[index] = (-currentOffset / this.displayWidth) * maxOffset + maxOffset;
          if (this.isIndexValid(index + 1)) {
            // 下一个卡片的偏移量
            const maxOffset = this.getMaxOffset(index + 1) / 2;
            this.cardsOffset[index + 1] = (-currentOffset / this.displayWidth) * maxOffset;
          }
          if (this.isIndexValid(index - 1)) {
            // 上一个卡片的偏移量
            const maxOffset = this.getMaxOffset(index - 1) / 2;
            this.cardsOffset[index - 1] = (currentOffset / this.displayWidth) * maxOffset + 2 * maxOffset;
          }
        } else if (currentOffset > 0) {
          // 向右滑动
          this.cardsOffset[index] = maxOffset - (currentOffset / this.displayWidth) * maxOffset;
          if (this.isIndexValid(index + 1)) {
            const maxOffset = this.getMaxOffset(index + 1) / 2;
            this.cardsOffset[index + 1] = (currentOffset / this.displayWidth) * maxOffset;
          }
          if (this.isIndexValid(index - 1)) {
            const maxOffset = this.getMaxOffset(index - 1) / 2;
            this.cardsOffset[index - 1] = 2 * maxOffset - (currentOffset / this.displayWidth) * maxOffset;
          }
        }
      })
      .onAnimationStart((index, targetIndex) => {
        this.calculateOffset(targetIndex);
      })
      .height('100%')
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }

  /**
   * 计算卡片偏移量,并维护偏移量列表。
   * @param targetIndex { number } swiper target card's index.
   */
  calculateOffset(target: number) {
    let left = target - 1;
    let right = target + 1;

    // 计算上一张卡片的偏移值
    if (this.isIndexValid(left)) {
      this.cardsOffset[left] = this.getMaxOffset(left);
    }
    // 计算当前卡片的偏移值
    if (this.isIndexValid(target)) {
      this.cardsOffset[target] = this.getMaxOffset(target) / 2;
    }
    // 下一张片的偏移值
    if (this.isIndexValid(right)) {
      this.cardsOffset[right] = 0;
    }
  }

  /**
   * 检查卡片索引值的合法性。
   * @param index {number} input card's index.
   * @returns true or false.
   */
  isIndexValid(index: number): boolean {
    return index >= 0 && index < this.data.totalCount();
  }

  /**
   * 计算指定卡片的最大偏移量。
   * @param index {number} target card's index.
   * @returns offset value.
   */
  getMaxOffset(index: number): number {
    /*
     * 这里的偏移量指相对容器左侧的值。
     * 计算公式为:屏幕宽度 - Swiper两侧突出的偏移量 - 卡片自身的宽度。
     * 此值即为卡片可偏移的最大值,也就是卡片右对齐的状态值。
     * 如果居中,则将最大偏移量 / 2。
     */
    //let areaWidth = this.data.getAllData()?.[index]?.areaWidth
    return this.displayWidth - (index===this.currentSwiperIndex?this.displayWidth - 110:this.displayWidth - 160) - 2 * this.swiperMargin;
  }
}
现有的demo项目结构图:

在这里插入图片描述有需要源码或者有问题的可私信我

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

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

相关文章

C# 编译程序引用C++DLL托管动态链接库实例

构建 C# 程序引用CDLL托管动态链接库 前言1、统一框架版本2、统一编译平台3、C 托管动态链接库的优点3.1、C 托管动态链接库引用方便简单3.2、C 托管动态链接库加快了程序构建和重复利用3.3、C 托管动态链接库源代码更加安全 4、构建与 C# 程序进行互操作的C.DLL动态链接库的三…

UTB定位技术能不能精准定位

在当今科技日新月异的时代&#xff0c;定位技术以其广泛的应用场景和不断提升的精度&#xff0c;成为了多个领域的核心支撑。其中&#xff0c;UTB定位技术以其高精度、低延迟和高抗干扰性等特点&#xff0c;在众多定位技术中脱颖而出&#xff0c;成为精准定位领域的佼佼者。那么…

ContentProvider 数据供给方

作用 ContentProvider使用数据库模型的基本表格来提供需要共享的数据 表格每一行表示一条记录&#xff08;都包含"_ID"字段&#xff09;&#xff0c;每一列表示该类型的数据 URI 作用 资源的唯一标识符——提供数据位置 组成 scheme: 一般 "content:/"…

病理AI重点方向:普通HE与免疫组化之间的关系|文献速递·24-09-03

小罗碎碎念 本期推文主题&#xff1a;免疫组化 这一期的推文很有意思&#xff0c;看完第一篇文献就知道了——兽医写的与免疫组化相关的内容——普渡大学兽医学院比较病理学系。 最近一直在了解免疫组化与HE之间的关系&#xff0c;在阅读文献的时候&#xff0c;无意间看到了第…

HashMap底层逻辑理解(数组+链表+红黑树)

jdk1.7底层是由数组链表实现jdk1.8底层是由数组链表红黑树实现 以下都是数组链表红黑树对应的描述&#xff1a; public static void main(String[] args) {HashMap<String, String> map new HashMap<>();map.put("Aa", "Value1");map.put(&…

捷邻系统小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;商品分类管理&#xff0c;商品信息管理&#xff0c;促销产品管理&#xff0c;订单管理&#xff0c;系统管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;商品信息&#…

如何处理海量数据

目录 1.海量数据简介 海量数据的产生 海量数据的处理 2.利用位图解决 题目一 题目二 题目三 题目一变形 3.利用布隆过滤器解决 题目一 4.哈希切割解决 题目一 题目二 5.海量数据处理总结 1.海量数据简介 海量数据的产生 随着互联网的迅速发展&#xff0c;互联…

堆排、快速排序、归并排序等总结

十大经典排序算法大梳理 (动图代码)&#xff08;动态图参考&#xff09; 排序算法平均时间复杂度最差时间复杂度空间复杂度数据对象稳定性冒泡排序O(n2)O(n2)O(1)稳定选择排序O(n2)O(n2)O(1)数组不稳定、链表稳定插入排序O(n2)O(n2)O(1)稳定快速排序O(n*log2n)O(n2)O(log2n)不…

文章解读与仿真程序复现思路——电网技术EI\CSCD\北大核心《省间中长期市场连续运营下考虑耦合安全约束的电力交易联合优化出清模型》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

Docker笔记-Docker容器使用

Docker笔记-Docker容器使用 1、Docker 客户端 docker 客户端非常简单&#xff0c;我们可以直接输入 docker 命令来查看到 Docker 客户端的所有命令选项。 $ docker可以通过命令 docker command --help 更深入的了解指定的 Docker 命令使用方法。 例如我们要查看 docker sta…

用vs附加运行的软件并打断点

需求&#xff1a;给一个代码文件A的第n行打断点。 前提&#xff1a;目标软件已经build完成。并且生成了对应的pdb文件P。 0 将要打断点的代码&#xff0c;所在生成的pdb文件放到exe相同目录下。 1 运行程序。 2 打开vs&#xff0c;并打开文件A。并在n行打上断点。&#xff…

视觉SLAMch4——李群和李代数

一、李群和李代数在SLAM中的定位&#xff08;如何解决SLAM中的问题&#xff09; 在视觉SLAM中&#xff0c;我们的目标之一是估计传感器&#xff08;通常是摄像头&#xff09;在每一时刻的位置和姿态。为了量化估计的好坏&#xff0c;我们需要定义一个误差函数&#xff0c;该函数…

Apache Arrow简介

是什么&#xff1f; (1) Apache Arrow是内存分析开发平台&#xff0c;是Apache的顶级项目。 (2) Apache Arrow是一个开源的跨平台数据层开发框架&#xff0c;主要提供高效的、硬件加速的、内存中数据计算的能力。Apache Arrow的设计初衷是作为“新一代大数据系统的共享基础”&a…

3.5 算术运算指令

&#x1f393; 微机原理考点专栏&#xff08;通篇免费&#xff09; 欢迎来到我的微机原理专栏&#xff01;我将帮助你在最短时间内掌握微机原理的核心内容&#xff0c;为你的考研或期末考试保驾护航。 为什么选择我的视频&#xff1f; 全程考点讲解&#xff1a;每一节视频都…

11、Django Admin启用对计算字段的过滤

重新定义admin.py中的Hero管理模型如下&#xff1a; admin.register(Hero) class HeroAdmin(admin.ModelAdmin):list_display ("name", "is_immortal", "category", "origin", "is_very_benevolent")list_filter ("…

(第四十天)配置完整的考试系统,完成前端和后端并优化,mysql后端,nginx前端,java连接

回顾 1 、使用 harbor 仓库 python --version yum -y update yum -y install python2-pip pip install --upgrade pip 20 .3 -i ....... pip install docker-compose -i ....... sh docker.sh 解压 harbor vim harbor.yml ./prepare ./installed 使用…

智慧储能柜构造揭秘:安科瑞2000ES解决方案打造智慧储能大脑

随着全球能源结构的转型和可再生能源的快速发展&#xff0c;储能技术成为调节能源供需、提高能源利用效率的关键。储能柜作为储能技术的核心组成部分&#xff0c;其构造和功能显得尤为重要。本文将为您详细解析储能柜的构造&#xff0c;并展示其如何成为高效能源管理的智慧核心…

ArcGIS Pro高级技巧:制作带地类编码文字的用地图例

欢迎关注同名微信公众号&#xff0c;更多文章推送&#xff1a; 01 需求分析 这个方法由群友【Erik】提供。 很有意思&#xff0c;看到最后一定会帮你打开思路。 直接上图比较&#xff0c;这是一般情况下简单的用地图例&#xff0c;只有色块&#xff1a; 下面这个是我们想要…

4、Django Admin对自定义的计算字段进行排序

通常&#xff0c;Django会为模型属性字段&#xff0c;自动添加排序功能。当你添加计算字段时&#xff0c;Django不知道如何执行order_by&#xff0c;因此它不会在该字段上添加排序功能。 如果要在计算字段上添加排序&#xff0c;则必须告诉Django需要排序的内容。你可以通过在…

有了这款AI代码神器Coursor,学习Rust不再是难题!

大家好&#xff0c;我是渔夫。 工欲善其事&#xff0c;必先利其器。AI 是未来十年生产力的核心工具&#xff0c;要让 AI 真正转化为生产力&#xff0c;而不仅仅是围观一时的热潮。 今天来聊聊最近又火爆AI圈的AI代码神器 Cursor&#xff0c;它其实是一款 VS Code 的一个分支&am…