Flutter:gsy_flutter_demo项目学习——布局切换动画、列表滑动监听、列表滑动到指定位置、高斯模糊

news2024/9/21 12:38:46

前言

gsy_flutter_demo是一个关于各种小案例和小问题的方案解决。项目是由flutter大佬恋猫de小郭维护的

项目地址:https://github.com/CarGuo/gsy_flutter_demo

感兴趣的可以看一下大佬的文章:Flutter完整开发实战详解系列,GSY Flutter 系列专栏整合
在这里插入图片描述

关于该项目的学习呢,不会都学习,只会学习自己比较感兴趣的东西。

布局切换动画

动画效果

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

原文地址

Flutter 小技巧之有趣的动画技巧

代码

class YcHomeBody extends StatefulWidget {
  const YcHomeBody({Key? key, required this.width, required this.height})
      : super(key: key);
  // 容器的宽高
  final double width;
  final double height;
  
  State<YcHomeBody> createState() => _YcHomeBodyState();
}

class _YcHomeBodyState extends State<YcHomeBody>
    with SingleTickerProviderStateMixin {
  int currentIndex = 0;

  
  initState() {
    super.initState();

    //  创建吗一个定时器
    Timer.periodic(const Duration(seconds: 2), (timer) {
      setState(() {
        currentIndex += 1;
        if (currentIndex == 100) {
          currentIndex = 0;
        }
        // print("当前值:$currentIndex");
      });
    });
  }

  PositionedItemData getIndexPosition(int index, Size size) {
    switch (index) {
      case 0:
        return PositionedItemData(
          width: size.width / 2 - 5,
          height: size.height,
          left: 0,
          top: 0,
        );

      case 1:
        return PositionedItemData(
          width: size.width / 2 - 5,
          height: size.height / 2 - 5,
          left: size.width / 2 + 5,
          top: 0,
        );

      case 2:
        return PositionedItemData(
          width: size.width / 2 - 5,
          height: size.height,
          left: size.width / 2 + 5,
          top: size.height / 2 + 5,
        );
    }
    return PositionedItemData(
      width: size.width / 2 - 5,
      height: size.height,
      left: 0,
      top: 0,
    );
  }

  
  Widget build(BuildContext context) {
    return Center(
        child: Container(
      height: widget.height,
      width: widget.width,
      margin: const EdgeInsets.symmetric(horizontal: 20),
      // 根据父widget的约束条件来构建自身的布局,适合在需要根据父widget的约束条件来动态调整布局的场景中使用
      child: LayoutBuilder(
        builder: (BuildContext context, BoxConstraints constraints) {
          var f = getIndexPosition(currentIndex % 3, constraints.biggest);
          var s = getIndexPosition((currentIndex + 1) % 3, constraints.biggest);
          var t = getIndexPosition((currentIndex + 2) % 3, constraints.biggest);
          return Stack(
            fit: StackFit.expand,
            children: [
              // InkWell为其子widget提供水波纹效果和触摸事件处理
              PositionItem(f,
                  child: InkWell(
                    onTap: () {
                      // print("red");
                    },
                    child: Container(color: Colors.redAccent),
                  )),
              PositionItem(s,
                  child: InkWell(
                    onTap: () {
                      //print("green");
                    },
                    child: Container(color: Colors.greenAccent),
                  )),
              PositionItem(t,
                  child: InkWell(
                    onTap: () {
                      // print("yello");
                    },
                    child: Container(color: Colors.yellowAccent),
                  )),
            ],
          );
        },
      ),
    ));
  }
}

class PositionItem extends StatelessWidget {
  final PositionedItemData data;
  final Widget child;

  const PositionItem(this.data, {Key? key, required this.child})
      : super(key: key);

  
  Widget build(BuildContext context) {
    // AnimatedPositioned 用于动画定位位置的widget
    return AnimatedPositioned(
      duration: const Duration(seconds: 1), // 动画持续时间
      curve: Curves.fastOutSlowIn, // 动画曲线
      left: data.left,
      top: data.top,
      // AnimatedContainer,根据指定的时间段自动过渡其属性,用于实现大小的过渡
      child: AnimatedContainer(
        duration: const Duration(seconds: 1),
        curve: Curves.fastOutSlowIn,
        width: data.width,
        height: data.height,
        child: child,
      ),
    );
  }
}

// 用于规范元素的宽高和位置
class PositionedItemData {
  final double left;
  final double top;
  final double width;
  final double height;

  PositionedItemData({
    required this.left,
    required this.top,
    required this.width,
    required this.height,
  });
}

使用

YcHomeBody(width: 240, height: 300,)

列表滑动监听

class _MyHomePageState extends State<MyHomePage> {
  // 是否到底
  bool isEnd = false;
  // 偏移量
  int offset = 0;
  // 通知
  String notify = '';
  // 列表container
  final ScrollController _controller = ScrollController();

  
  void initState() {
    super.initState();

    _controller.addListener(() {
      setState(() {
        // 这里进行取整,不然小数位数太多
        offset = _controller.offset.floor();
        // 判断当前滚动位置的像素值是否等于可滚动区域最大值
        isEnd =
            _controller.position.pixels == _controller.position.maxScrollExtent;
      });
    });
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: NotificationListener(
          onNotification: (dynamic notification) {
            // 在这里处理滚动通知
            if (notification is ScrollStartNotification) {
              // 滚动开始
              notify = "滚动开始";
            } else if (notification is ScrollUpdateNotification) {
              // 滚动更新
              notify = "滚动更新";
            } else if (notification is ScrollEndNotification) {
              // 滚动结束
              notify = "滚动结束";
            }
            setState(() {});
            // 返回true表示阻止通知冒泡,返回false则继续向上传递通知
            return false;
          },
          child: ListView.builder(
              itemCount: 100,
              controller: _controller,
              itemBuilder: (context, index) {
                return Card(
                    child: Container(
                  height: 60,
                  alignment: Alignment.centerLeft,
                  child: Text("Item $index"),
                ));
              })),
      // 页脚按钮
      persistentFooterButtons: [
        Align(
          alignment: Alignment.center,
          child: Text("通知:$notify,偏移量:$offset,到达底部:${isEnd ? '是' : '否'}"),
        )
      ], // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

在这里插入图片描述
NotificationListener是一个widget,用于监听并处理各种通知。它可以将通知分发给子widget,并根据需要执行相应的操作

列表滑动到指定位置

作者提供了两种实现方式,一种是使用第三库,另一种是需要自己进行计算。本着能使用第三方库就使用第三库的原则,我们使用第三库来实现。

官方地址
https://pub-web.flutter-io.cn/packages/scroll_to_index

安装

flutter pub add scroll_to_index
class _MyHomePageState extends State<MyHomePage> {
  // 列表container
  late final AutoScrollController _controller;

  // 列表项高度,100~300间的整数
  List<int> items =
      List.generate(50, (index) => 100 + math.Random().nextInt(300 - 100));

  
  void initState() {
    super.initState();
    //  初始化
    _controller = AutoScrollController(
        viewportBoundaryGetter: () => Rect.fromLTRB(0, 0, 0,
            MediaQuery.of(context).padding.bottom), // 获取底部边界值,保证滚动到底部时,内容不会被遮挡
        axis: Axis.vertical);
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: ListView.builder(
          itemCount: 50,
          controller: _controller,
          itemBuilder: (context, index) {
            return AutoScrollTag(
                key: ValueKey(index),
                controller: _controller,
                index: index,
                highlightColor: Colors.black.withOpacity(0.1),
                child: Container(
                  height: items[index] + 0.0,
                  alignment: Alignment.topCenter,
                  margin: const EdgeInsets.all(10),
                  decoration: BoxDecoration(
                      border: Border.all(color: Colors.blue, width: 1),
                      borderRadius: BorderRadius.circular(10)),
                  child: Text("items ${index + 1},height:${items[index]}"),
                ));
          }),
      // 页脚按钮
      persistentFooterButtons: [
        ElevatedButton(
            onPressed: () async {
              // 滚动
              await _controller.scrollToIndex(0,
                  preferPosition: AutoScrollPosition.begin); // 以列表的上边框为准
              //   高亮
              _controller.highlight(0);
            },
            child: const Text("第1个")),
        ElevatedButton(
            onPressed: () async {
              // 滚动
              await _controller.scrollToIndex(19,
                  preferPosition: AutoScrollPosition.begin);
              //   高亮
              _controller.highlight(19);
            },
            child: const Text("第20个"))
      ], // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

在这里插入图片描述

高斯模糊

Stack(
        children: [
          Positioned(
              child: Image.network(
            'https://scpic2.chinaz.net/files/default/imgs/2023-07-24/f81ebfa03646059a_s.jpg',
            fit: BoxFit.fill,
            width: MediaQuery.of(context).size.width,
            height: MediaQuery.of(context).size.height,
          ),
          ),
        //  高斯模糊
          Center(
            child: SizedBox(
              width: 300,
              height: 300,
              child: ClipRRect(
              borderRadius: BorderRadius.circular(15.0),
                child: BackdropFilter(
                  // 设置视频和垂直方向的模糊程度
                  filter: ImageFilter.blur(sigmaX: 8.0,sigmaY: 8.0),
                  child: const Text("高斯模糊"),
                ),
              ),
            ),
          )
        ],
      )

在这里插入图片描述

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

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

相关文章

7月无代码资讯|Gartner报告:低代码处于峰值期;轻流5.0发布全面升级

栏目导读&#xff1a;无代码资讯栏目从全球视角出发&#xff0c;带您了解无代码相关最新资讯。 TOP3 大事件 1、Mendix 10将AI和ML融入低代码平台 &#xff0c;助力企业实现组合式数字解决方案交付 在快速变化的商业环境中&#xff0c;所有企业都面临着如何有效地交付业务成果的…

IT技术面试中常见的问题及解答技巧

在IT技术面试中&#xff0c;面试官常常会问到一些常见的问题&#xff0c;针对这些问题&#xff0c;我们可以充分准备和提前准备一些解答技巧。下面我将分享一些我个人的经验和观察&#xff0c;希望对大家有所帮助。 请介绍一下你的项目经验。 在回答这个问题时&#xff0c;我们…

Hadoop学习指南:探索大数据时代的重要组成——Hadoop运行模式(上)

Hadoop运行模式 前言Hadoop运行模式1 本地运行模式&#xff08;官方WordCount&#xff09;2 完全分布式运行模式&#xff08;开发重点&#xff09;2.1 虚拟机准备2.2 编写集群分发脚本xsync1&#xff09;scp&#xff08;secure copy&#xff09;安全拷贝2&#xff09;rsync 远程…

基于Springboot 猪场管理系统-计算机毕设 附源码11779

Springboot 猪场管理系统 摘要 信息化社会内需要与之针对性的信息获取途径&#xff0c;但是途径的扩展基本上为人们所努力的方向&#xff0c;由于站在的角度存在偏差&#xff0c;人们经常能够获得不同类型信息&#xff0c;这也是技术最为难以攻克的课题。针对猪场管理系统等问题…

Linux--获取子进程退出码的代码

#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/wait.h>int main (void) {pid_t id fork();if (id 0) {int cnt 5; // 循环5次// childwhile (1) {// 五秒…

【Linux命令200例】paste一个用于合并文件的命令行实用工具

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;全栈领域新星创作者✌&#xff0c;2023年6月csdn上海赛道top4。 &#x1f3c6;本文已收录于专栏&#xff1a;Linux命令大全。 &#x1f3c6;本专栏我们会通过具体的系统的命令讲解加上鲜活的实操案例对各个命令进行深入…

[安洵杯-不是文件上传]代码审计+文件上传+insert注入

文章目录 [安洵杯-不是文件上传]代码审计文件上传insert注入mysql特性 [安洵杯-不是文件上传]代码审计文件上传insert注入 首页是一个文件上传页面 测试只能上传图片&#xff0c;是白名单 题目给出了源码&#xff1a; upload.php <!DOCTYPE html> <html> <h…

00|Oracle学习(卸载、安装、创建删除数据库/数据库实例)

Oracle 12c卸载 1 如果数据库配置了自动存储管理&#xff08;ASM&#xff09;先删除聚类同步服务CSS。DOS指令&#xff1a; localconfig delete2 进入“任务管理器”&#xff08;ctrlshiftEsc&#xff09;&#xff0c;将所有运行中的Oracle进程全关闭。 3 在开始菜单中&#…

Jupyter Notebook 7重磅发布,新增多个特性!

本文分享Jupyter Notebook大版本v7.0.0更新亮点&#xff0c;及简单测试&#xff01; 近日&#xff0c;Jupyter Notebook大版本v7.0.0更新&#xff0c;Jupyter Notebook 7基于JupyterLab&#xff0c;因此它包含了过去几年JupyterLab中添加的许多新功能和改进&#xff0c;部分亮…

Python异步编程|ASGI 与 Django(附源码)

异步服务网关接口&#xff08;Asynchronous Server Gateway Interface&#xff0c;ASGI&#xff09;秉承WSGI统一网关接口原则&#xff0c;在异步服务、框架和应用之间提供一个标准接口&#xff0c;同时兼容WSGI。 01、ASGI ASGI是根据统一接口的思想重新设计的新标准&#xf…

【iOS】—— UIKit相关问题

文章目录 UIKit常用的UIKit组件懒加载的优势 CALayer和UIView区别关系 UITableViewUITableView遵循的两个delegate以及必须实现的方法上述四个必须实现方法执行顺序其他方法的执行顺序&#xff1a; UICollectionView和UITableView的区别UICollectionViewFlowLayout和UICollecti…

谐音标注外语发音的学习方式,早该终结了!

语言学习的热潮席卷全国&#xff0c;在多数80、90后记忆里尤为深刻&#xff0c;部分对外语过敏的同学&#xff0c;就像溺水的鱼&#xff0c;使劲扑棱也无济于事&#xff0c;难受但是死不了&#xff0c;在懵懂的年纪就被“摧残”了整个青春。 记忆中遇到记不住读音的单词&#x…

一文了解Angular、React 和 Vue.js的区别

前端开发人员在开始一个新项目时首先要回答的问题是&#xff1a;我应该选择哪个框架&#xff1f; 哪个框架更适合我的需求&#xff1f; 在本文中&#xff0c;我们将向您快速概述当前使用的最常见的前端框架&#xff0c;旨在帮助您选择最能满足您需求的框架。这些框架是 Angular…

1400*B. Swaps(排序)

Example input 3 2 3 1 4 2 3 5 3 1 2 4 6 5 7 5 9 1 3 2 4 6 10 8 output 0 2 3 题意&#xff1a; 每次交换相邻的两个数&#xff0c;问两个数列共同交换多少次&#xff0c;可以使得第一个数列的首个数字小于第二个数列的首个数字&#xff0c;求最少的交换次数。 解析&am…

springBootAdmin监控内存日志堆栈

概述 我的spring-boot版本&#xff1a;2.7.7 我的spring-boot-admin版本&#xff1a;2.7.10 jdk:1.8 平时测试环境服务不多的情况下&#xff0c;用linux命令看下日志和堆栈也不麻烦。但是要是服务数量上来了&#xff0c;有10几个服务这个时候用命令看已经有点麻烦了。特别是对…

安装了pyintaller后出现:‘pyinstaller‘ 不是内部或外部命令,也不是可运行的程序或批处理文件。

2023年7月31日&#xff0c;周一上午 我昨天晚上也遇到了这个问题&#xff0c;后来解决了 目录 出错原因解决方法怎么找到Scripts文件夹 出错原因 出现这个错误是因为你没给python的Scripts文件夹添加环境变量&#xff0c; Scripts存放着pip安装包时产生的可执行文件。 解决…

线性代数的学习和整理2:线性代数的基础知识(整理ing)

目录 0 写在前面的话 网上推荐的线性代数的课程 1 线性代数和矩阵的各种概念 1.1 各种逻辑图 2 关于线性代数入门的各种灵魂发问 2.1 什么是线性&#xff0c;什么是线性相关 &#xff1f; 为什么叫线性变换&#xff1f; 为什么叫线性代数&#xff1f; 2.2 线性代数是人造…

轻量级的工作流引擎:提质增效+灵活简便+拖拽式设计

低代码开发市场现在正是蓬勃发展的时期&#xff0c;由于低代码技术平台能够为当代企业节省很多宝贵时间&#xff0c;实现提质增效的办公效率&#xff0c;因此获得了大家的认可与喜爱。其中&#xff0c;工作流引擎是当中的主要功能&#xff0c;其拖拽式设计、易操作等优势特点也…

Linux 学习记录60(ARM篇)

Linux 学习记录60(ARM篇) 本文目录 Linux 学习记录60(ARM篇)一、SPI总线1. 概念2. 硬件连接 二、SPI总线协议三、SPI总线通信模式四、对比IIC总线和SPI总线1. 相同点2. 不同点 思维导图 一、SPI总线 1. 概念 1、SPI总结是Motorola首先提出的全双工三线/四线同步串行总线 2、采…

财务管理软件:推动企业数字化转型的关键驱动力

数字化转型是当下热议的话题&#xff0c;如今许多企业纷纷走向了数字化转型的道路。到底什么是数字化转型呢&#xff1f;财务管理软件如何帮助企业实现数字化转型&#xff1f; 什么是数字化转型&#xff1f; 数字化转型的核心要义是要将适应物质经济的发展方式转变为适应数字经…