flutter开发实战-轮播Swiper更改Custom_layout样式中Widget层级

flutter开发实战-轮播Swiper更改Custom_layout样式中Widget层级

在之前的开发过程中,需要实现卡片轮播效果,但是卡片轮播需要中间大、两边小一些的效果,这里就使用到了Swiper。具体效果如视频所示
添加链接描述
这里需要的效果是中间大、两边小一些,中间的卡片在最上层,两边的卡片会被中间的卡片挡住一部分。所以需要处理一下Custom_layout样式中Widget层级关系。
在这里插入图片描述

一、引入Swiper

在工程的pubspec.yaml中引入swiper

  # 轮播图
  flutter_swiper_null_safety: ^1.0.2
    

二、Swiper使用

Swiper无限轮播

通过Swiper()来构建轮播图控件,可以同步不同的属性搭配不同的效果

默认效果

Container(
    height: 200,
    child: new Swiper(
        itemBuilder: (BuildContext context,int index){
            return new Image.network(imgs[index],fit: BoxFit.cover,);
        },
        itemCount: imgs.length,
        pagination: new SwiperPagination(),//如果不填则不显示指示点
        control: new SwiperControl(),//如果不填则不显示左右按钮
    ),
),
    

3D卡片滚动

Container(
    height:  200,
    child: new Swiper(
        itemBuilder: (BuildContext context, int index) {
            return new Image.network(imgs[index],fit: BoxFit.cover,);
        },
        itemCount: imgs.length,
        viewportFraction: 0.8,
        scale: 0.9,
    ),
),
    

无限卡片堆叠

Container(
    height: 200,
    child: new Swiper(
        itemBuilder: (BuildContext context, int index) {
            return new Image.network(imgs[index],fit: BoxFit.cover,);
        },
        itemCount: imgs.length,
        itemWidth: 300.0,
        layout: SwiperLayout.STACK,
    ),
),
    

无限卡片堆叠2

Container(
    height: 200,
    child: new Swiper(
        itemBuilder: (BuildContext context, int index) {
            return new Image.network(imgs[index],fit: BoxFit.cover,);
        },
        itemCount: imgs.length,
        itemWidth: 300.0,
        itemHeight: 300.0,
        layout: SwiperLayout.TINDER,
    ),
),
    

自定义效果

Container(
    height: 200,
    child: new Swiper(
    layout: SwiperLayout.CUSTOM,
    customLayoutOption: new CustomLayoutOption(
        startIndex: -1,
        stateCount: 3
    ).addRotate([
        -45.0/180,
        0.0,
        45.0/180
    ]).addTranslate([
        new Offset(-370.0, -40.0),
        new Offset(0.0, 0.0),
        new Offset(370.0, -40.0)
    ]),
    itemWidth: 300.0,
    itemHeight: 200.0,
    itemBuilder: (context, index) {
        return new Image.network(imgs[index],fit: BoxFit.cover,);
    },
    itemCount: imgs.length),
)
    

三、更改Custom_layout样式中Widget层级

需要的效果是中间大、两边小一些,中间的卡片在最上层,两边的卡片会被中间的卡片挡住一部分

这里使用的是SwiperLayout.CUSTOM,

这里就需要查看源码,更改Custom_layout样式中Widget层级关系,更改Stack的子Widget层级关系,需要调整中间的卡片在最上层。

找到Custom_layout.dart的源码,找到Widget _buildAnimation(BuildContext context, Widget? w)。

需要更改list,重新排列list

if (list.isNotEmpty) {
      int length = list.length;
      int mid = length~/2;

      List<Widget> transList = [];
      for (int i = mid; i >= 0; i--) {
        List<Widget> subList = [];
        for (int index = 0; index < length; index++) {
          int abs = (index - mid).abs();
          if (abs == i) {
            subList.add(list[index]);
          }
        }
        transList.addAll(subList);
      }

      print("transList:${transList}");
      if (transList.isNotEmpty && transList.length == list.length) {
        list = transList;
      }
    }
    

更改后的_buildAnimation代码如下

Widget _buildAnimation(BuildContext context, Widget? w) {
    List<Widget> list = [];

    if (_animationCount != null) {
      double? animationValue = _animation?.value;
      for (int i = 0; i < _animationCount!; ++i) {
        int realIndex = _currentIndex + i + (_startIndex ?? 0);
        realIndex = realIndex % widget.itemCount;
        if (realIndex < 0) {
          realIndex += widget.itemCount;
        }
        if (animationValue != null) {
          list.add(_buildItem(i, realIndex, animationValue));
        }
      }
    }

    if (list.isNotEmpty) {
      int length = list.length;
      int mid = length~/2;

      List<Widget> transList = [];
      for (int i = mid; i >= 0; i--) {
        List<Widget> subList = [];
        for (int index = 0; index < length; index++) {
          int abs = (index - mid).abs();
          if (abs == i) {
            subList.add(list[index]);
          }
        }
        transList.addAll(subList);
      }

      print("transList:${transList}");
      if (transList.isNotEmpty && transList.length == list.length) {
        list = transList;
      }
    }

    return new GestureDetector(
      behavior: HitTestBehavior.opaque,
      onPanStart: _onPanStart,
      onPanEnd: _onPanEnd,
      onPanUpdate: _onPanUpdate,
      child: new ClipRect(
        child: new Center(
          child: _buildContainer(list),
        ),
      ),
    );
  }
    

四、实现中间大、两边小一些,中间的卡片在最上层,两边的卡片会被中间的卡片挡住的效果

需要实现效果的时候,我们需要使用Swiper的custom,使用CustomLayoutOption添加addScale和addOpacity以及addTranslate来确定不同的卡片的缩放大小、透明度、以及offset

代码如下

Swiper(
              autoplay: true,
              layout: SwiperLayout.CUSTOM,
              customLayoutOption:
                  CustomLayoutOption(startIndex: 0, stateCount: 5)
                    ..addScale([
                      0.6,
                      0.8,
                      1.0,
                      0.8,
                      0.6,
                    ], Alignment.center)
                    ..addOpacity([
                      1.0,
                      1.0,
                      1.0,
                      1.0,
                      1.0,
                    ])
                    ..addTranslate([
                      Offset(-180.0, 0),
                      Offset(-80.0, 0),
                      Offset(0.0, 0.0),
                      Offset(80.0, 0),
                      Offset(180.0, 0),
                    ]),
              itemWidth: 230.0,
              itemHeight: 230.0,
              itemBuilder: (context, index) {
                return SwiperCard(imageUrl: imageUrls[index]);
              },
              itemCount: imageUrls.length,
            )
    

页面的完整代码如下

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_swiper_null_safety/flutter_swiper_null_safety.dart';

class SwiperPage extends StatefulWidget {
  const SwiperPage({super.key});

  @override
  State<SwiperPage> createState() => _SwiperPageState();
}

class _SwiperPageState extends State<SwiperPage> {
  List<String> imageUrls = [];

  @override
  void initState() {
    // TODO: implement initState
    imageUrls = [
      "https://d-ssl.dtstatic.com/uploads/blog/202301/08/20230108192142_ff632.thumb.1000_0.jpeg_webp",
      "https://d-ssl.dtstatic.com/uploads/blog/202301/08/20230108192143_f4355.thumb.1000_0.jpeg_webp",
      "https://d-ssl.dtstatic.com/uploads/blog/202301/08/20230108192146_0aaf2.thumb.1000_0.jpeg_webp",
      "https://d-ssl.dtstatic.com/uploads/blog/202301/08/20230108192148_357ff.thumb.1000_0.jpeg_webp",
      "https://d-ssl.dtstatic.com/uploads/blog/202301/08/20230108192149_92c71.thumb.1000_0.jpeg_webp"
    ];
    super.initState();
  }

  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    Size screenSize = MediaQuery.of(context).size;
    return Scaffold(
      appBar: AppBar(
        title: const Text('SwiperPage'),
      ),
      body: Container(
        width: screenSize.width,
        height: screenSize.height,
        child: Stack(
          alignment: Alignment.center,
          children: [
            Swiper(
              autoplay: true,
              layout: SwiperLayout.CUSTOM,
              customLayoutOption:
                  CustomLayoutOption(startIndex: 0, stateCount: 5)
                    ..addScale([
                      0.6,
                      0.8,
                      1.0,
                      0.8,
                      0.6,
                    ], Alignment.center)
                    ..addOpacity([
                      1.0,
                      1.0,
                      1.0,
                      1.0,
                      1.0,
                    ])
                    ..addTranslate([
                      Offset(-180.0, 0),
                      Offset(-80.0, 0),
                      Offset(0.0, 0.0),
                      Offset(80.0, 0),
                      Offset(180.0, 0),
                    ]),
              itemWidth: 230.0,
              itemHeight: 230.0,
              itemBuilder: (context, index) {
                return SwiperCard(imageUrl: imageUrls[index]);
              },
              itemCount: imageUrls.length,
            )
          ],
        ),
      ),
    );
  }
}

class SwiperCard extends StatelessWidget {
  const SwiperCard({
    super.key,
    required this.imageUrl,
  });

  final String imageUrl;

  @override
  Widget build(BuildContext context) {
    return Container(
      width: 230,
      height: 230,
      clipBehavior: Clip.hardEdge,
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.all(
          Radius.circular(10),
        ),
        border: Border.all(
          color: Color(0xFF5C6BC0),
          style: BorderStyle.solid,
          width: 3,
        ),
        boxShadow: [
          BoxShadow(
            color: Color(0xFFE8EAF6),
            offset: Offset(0, -5),
            blurRadius: 10,
          )
        ],
      ),
      child: Stack(alignment: Alignment.center, children: [
        Positioned(
          top: 0,
          child: Image.network(
            imageUrl,
            width: 230,
            height: 230,
          ),
        ),
      ]),
    );
  }
}

    

最终实现了效果。

五、小结

flutter开发实战-轮播Swiper更改Custom_layout样式中Widget层级

学习记录,每天不停进步。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

仅仅通过提示词,GPT-4可以被引导成为多个领域的特定专家

The Power of Prompting&#xff1a;提示的力量&#xff0c;仅通过提示&#xff0c;GPT-4可以被引导成为多个领域的特定专家。微软研究院发布了一项研究&#xff0c;展示了在仅使用提策略的情况下让GPT 4在医学基准测试中表现得像一个专家。研究显示&#xff0c;GPT-4在相同的基…

依据小兔鲜项目,总结Javascript数组常用方法

find 在向购物车添加某种规格的商品时&#xff0c;查找购物车列表中是否已经存在该规格的商品 find()方法传入一个回调函数&#xff0c;代表对数组每一项item的校验要求 返回数组中第一个符合条件的元素的值&#xff0c;如果没有则返回undefined const item cartList.value…

【LeetCode热题100】【双指针】盛最多水的容器

给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 说明&#xff1a;你不能倾斜容器。 示例…

Java架构师技术为业务赋能

目录 1 概论2 天猫的难言之隐3 如何拆解技术难点-三段论4 天猫线的破局之道-双引擎回归测试框架5 架构师的心理游戏-解决问题从转换思维开始6 技术助力业务的两个方向7 阿里新零售部门如何培养技术团队的业务知识8 如何围绕业务特点制定技术发展路线-阿里系和抖音案例9 阿里系业…

Ubuntu20.04安装ROS2

官方参考文章 Ubuntu (Debian) — ROS 2 Documentation: Foxy documentation curl密钥问题 sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg curl: (7) Failed to connect to raw.githubus…

pytorch 模型量化quantization

pytorch 模型量化quantization 1.workflow1.1 PTQ1.2 QAT 2. demo2.1 构建resnet101_quantization模型2.2 PTQ2.3 QAT 参考文献 pytorch框架提供了三种量化方法&#xff0c;包括&#xff1a; Dynamic QuantizationPost-Training Static Quantization&#xff08;PTQ&#xff0…

wordpress安装之Linux解压缩安装

本次教程是为了让大家少走弯路&#xff0c;可以更直观的去认识我们不懂的知识面。 首先我们安装解压缩的软件 命令如下&#xff1a; yum install -y unzip 上一篇我们讲到传输文件了 这篇我们把传输过来的压缩包解压并进行安装。follow me&#xff01; 我们输入命令 unzi…

【数值计算方法(黄明游)】矩阵特征值与特征向量的计算(五):Householder方法【理论到程序】

文章目录 一、Jacobi 旋转法二、Jacobi 过关法三、Householder 方法1. 旋转变换a. 旋转变换的选择b. 旋转变换的顺序 2. Householder矩阵&#xff08;Householder Matrix&#xff09;a. H矩阵的定义b. H变换的几何解释c. H变换的应用场景 3. H变换过程详解a. 过程介绍b. 细节解…

全面的.NET微信网页开发之JS-SDK使用步骤、配置信息和接口请求签名生成详解

JSSDK使用步骤 步骤一:绑定安全域名&#xff1a; 先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”。 步骤二:引入JS文件&#xff1a; 在需要调用JS接口的页面引入如下JS文件&#xff0c;&#xff08;支持https&#xff09;&#xff1a;http://…

业务数据治理体系化实施流程学习总结

目录 一、业务数据治理实施流程 步骤 1&#xff1a;发现问题和制定目标 步骤 2&#xff1a;针对问题进行拆解&#xff0c;设计可衡量的指标 步骤 3&#xff1a;制定解决SOP和检查研发标准规范 步骤 4&#xff1a;推广运营&#xff0c;以拿结果为核心目标 步骤 5&#xff…

matlab科学计算

欢迎关注博主 Mindtechnist 或加入【智能科技社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和技术。关…

ARM架构安装RabbitMQ

1.查看centos内核版本 uname -a uname -r2.安装之前的准备工作 安装RabbitMQ必装Erlang(RabbitMQ官网添加链接描述) 2.1.Erlang简介 Erlang是一种通用的面向并发的编程语言&#xff0c;它由瑞典电信设备制造商爱立信所辖的CS-Lab开发&#xff0c;目的是创造一种可以应对…

【Java基础篇 | 面向对象】—— 聊聊什么是多态(下篇)

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【JavaSE_primary】 本专栏旨在分享学习JavaSE的一点学习心得&#xff0c;欢迎大家在评论区讨论&#x1f48c; 目录 一、动态绑定和静态绑…

C++ string类(2)—成员访问、插入、删除、替换、查找和交换操作

目录 一、成员访问 1、[ ]&at 2、front( )&back( ) 二、插入元素 三、删除元素 四、替换元素 五、查找元素 1、查找第一次出现位置 2 、在指定范围内查找 六、交换字符串 七、c_str 八、rfind&substr 一、成员访问 1、[ ]&at 虽然二者功能一样&…

【微信小程序】上传头像 微信小程序内接小程序客服

这里写目录标题 微信小程序上传头像使用button按钮包裹img 微信小程序内接小程序客服使用button按钮跳转客服 微信小程序上传头像 使用button按钮包裹img 原本思路是只使用image标签再加上chooseImg&#xff0c;但发现使用button标签上传头像这种方法更实用。微信小程序文档上…

栈实现队列,力扣

题目地址&#xff1a; 232. 用栈实现队列 - 力扣&#xff08;LeetCode&#xff09; 难度&#xff1a;简单 今天刷栈实现队列&#xff0c;大家有兴趣可以点上看看题目要求&#xff0c;试着做一下。 题目&#xff1a; 请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支…

简单句子成分、阅读技巧

四、段落的主旨题&#xff1a;问这一段讲了什么&#xff08;一般都在段落的第一句话或最后一句话&#xff09; 词汇题的答案一般都在生词的上一句或者下一句 做题步骤&#xff1a; 1、先标段落 2、看题&#xff0c;划出关键词 3、去原文定位&#xff0c;标注中文意思 4、第一遍…

类和对象——(5)定义对象数组

归纳编程学习的感悟&#xff0c; 记录奋斗路上的点滴&#xff0c; 希望能帮到一样刻苦的你&#xff01; 如有不足欢迎指正&#xff01; 共同学习交流&#xff01; &#x1f30e;欢迎各位→点赞 &#x1f44d; 收藏⭐ 留言​&#x1f4dd; 芳华没有草稿纸&#xff0c;我们永久不…

异常(C++)

异常 前言一、程序的错误分类二、异常1. 概念2. 捕获异常的关键字和格式3. 异常的使用异常的原则异常再抛出异常说明注意事项 4. 自定义异常体系5. C标准库的异常体系 三、总结 前言 在程序运行时经常碰到一些错误&#xff0c;例如年龄、身高不能为负&#xff0c;除数为0等&…

阿里微服务质量保障系列:性能监控最佳实践

建设一体化性能监控平台 随着互联网技术的不断发展&#xff0c;企业的业务规模和复杂度也在不断增加。为了保证业务的稳定性和可靠性&#xff0c;企业需要对其系统进行全面的性能监控。而一体化性能监控就是一种集成了多种监控工具和技术的综合性监控方案&#xff0c;可以帮助…