Flutter-自定义图片3D画廊

2024-03-19 07:52

本文主要是介绍Flutter-自定义图片3D画廊,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

效果

111.gif

需求
  • 3D画廊效果
设计内容
  • Stack
  • GestureDetector
  • Transform
  • Positioned
  • 数学三角函数
代码实现

具体代码大概300行

import 'dart:math';import 'package:flutter/material.dart';
import 'package:flutter_xy/widgets/xy_app_bar.dart';import '../../r.dart';class ImageSwitchPage extends StatefulWidget {const ImageSwitchPage({Key? key}) : super(key: key);@overrideState<ImageSwitchPage> createState() => _ImageSwitchPageState();
}class _ImageSwitchPageState extends State<ImageSwitchPage> {var imgList = [R.img1_jpg,R.img2_jpg,R.img3_jpg,];var deviationRatio = 0.8;@overrideWidget build(BuildContext context) {return Scaffold(appBar: XYAppBar(title: "3D画廊",onBack: () {Navigator.pop(context);},),body: Center(child: Column(children: [Expanded(child: ImageSwitchWidget(deviationRatio: deviationRatio,childWidth: 150,childHeight: 150,children: [Image.asset(R.image1_webp,),Image.asset(R.image2_webp,),Image.asset(R.image3_jpg,),Image.asset(R.image4_webp,),Image.asset(R.image5_webp,),Image.asset(R.image6_webp,),Image.asset(R.image7_webp,),]),),Slider(value: deviationRatio,onChanged: (value) {setState(() {deviationRatio = value;});},)],),),);}
}class ImageSwitchWidget extends StatefulWidget {const ImageSwitchWidget({Key? key,this.children,this.childWidth = 80,this.childHeight = 80,this.deviationRatio = 0.8,this.minScale = 0.4,this.circleScale = 1,}) : super(key: key);//所有的子控件final List<Widget>? children;//每个子控件的宽final double childWidth;//每个子控件的高final double childHeight;//偏移X系数  0-1final double deviationRatio;//最小缩放比 子控件的滑动时最小比例final double minScale;//圆形缩放系数final double circleScale;@overrideState<StatefulWidget> createState() => ImageSwitchState();
}class ImageSwitchState extends State<ImageSwitchWidget>with TickerProviderStateMixin {//所有子布局的位置信息List<Point> childPointList = [];//滑动系数final slipRatio = 0.5;//开始角度double startAngle = 0;//旋转角度double rotateAngle = 0.0;//按下时X坐标double downX = 0.0;//按下时的角度double downAngle = 0.0;//大小late Size size;//半径double radius = 0.0;late AnimationController _controller;late Animation<double> animation;late double velocityX;@overridevoid initState() {super.initState();_controller = AnimationController(vsync: this,duration: const Duration(milliseconds: 1000),);animation = CurvedAnimation(parent: _controller,curve: Curves.linearToEaseOut,);animation = Tween<double>(begin: 1, end: 0).animate(animation)..addListener(() {//当前速度var velocity = animation.value * -velocityX;var offsetX = radius != 0 ? velocity * 5 / (2 * pi * radius) : velocity;rotateAngle += offsetX;setState(() => {});})..addStatusListener((status) {if (status == AnimationStatus.completed) {}});}@overridevoid dispose() {_controller.dispose();super.dispose();}///子控件集List<Point> _childPointList({Size size = Size.zero}) {size = Size(max(widget.childWidth, size.width * widget.circleScale),max(widget.childWidth, size.height * widget.circleScale),);childPointList.clear(); //清空之前的数据if (widget.children?.isNotEmpty ?? false) {//子控件数量int count = widget.children?.length ?? 0;//平均角度double averageAngle = 360 / count;//半径radius = size.width / 2 - widget.childWidth / 2;for (int i = 0; i < count; i++) {//当前子控件的角度double angle = startAngle + averageAngle * i - rotateAngle;//当前子控件的中心点坐标  x=width/2+sin(a)*R   y=height/2+cos(a)*Rvar centerX = size.width / 2 + sin(radian(angle)) * radius;var centerY = size.height / 2 +cos(radian(angle)) * radius * cos(pi / 2 * widget.deviationRatio);var minScale = min(widget.minScale, 0.99);var scale = (1 - minScale) / 2 * (1 + cos(radian(angle - startAngle))) +minScale;childPointList.add(Point(centerX,centerY,widget.childWidth * scale,widget.childHeight * scale,centerX - widget.childWidth * scale / 2,centerY - widget.childHeight * scale / 2,centerX + widget.childWidth * scale / 2,centerY + widget.childHeight * scale / 2,scale,angle,i,));}childPointList.sort((a, b) {return a.scale.compareTo(b.scale);});}return childPointList;}@overrideWidget build(BuildContext context) {return LayoutBuilder(builder: (BuildContext context,BoxConstraints constraints,) {var minSize = min(constraints.maxWidth, constraints.maxHeight);size = Size(minSize, minSize);return GestureDetector(///水平滑动按下onHorizontalDragDown: (DragDownDetails details) {_controller.stop();},///水平滑动开始onHorizontalDragStart: (DragStartDetails details) {//记录拖动开始时当前的选择角度值downAngle = rotateAngle;//记录拖动开始时的x坐标downX = details.globalPosition.dx;},///水平滑动中onHorizontalDragUpdate: (DragUpdateDetails details) {//滑动中X坐标值var updateX = details.globalPosition.dx;//计算当前旋转角度值并刷新rotateAngle = (downX - updateX) * slipRatio + downAngle;if (mounted) setState(() {});},///水平滑动结束onHorizontalDragEnd: (DragEndDetails details) {//x方向上每秒速度的像素数velocityX = details.velocity.pixelsPerSecond.dx;_controller.reset();_controller.forward();},///滑动取消onHorizontalDragCancel: () {},behavior: HitTestBehavior.opaque,child: CustomPaint(size: size,child: Stack(children: _childPointList(size: size).map((Point point) {return Positioned(width: point.width,left: point.left,top: point.top,child: Transform(transform: Matrix4.rotationY(radian(point.angle)),alignment: AlignmentDirectional.center,child: Container(decoration: BoxDecoration(boxShadow: [BoxShadow(color: Colors.grey.withOpacity(0.5),blurRadius: 16,offset: const Offset(0, 16),),],),child: widget.children![point.index],),),);},).toList(),),),);});}///角度转弧度///弧度 =度数 * (π / 180)///度数 =弧度 * (180 / π)double radian(double angle) {return angle * pi / 180;}
}///子控件属性对象
class Point {Point(this.centerX, this.centerY, this.width, this.height, this.left,this.top, this.right, this.bottom, this.scale, this.angle, this.index);double centerX;double centerY;double width;double height;double left;double top;double right;double bottom;double scale;double angle;int index;
}

运行看看:
111.gif

详情github : github.com/yixiaolunhui/flutter_xy

这篇关于Flutter-自定义图片3D画廊的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/825290

相关文章

C#实现将Excel表格转换为图片(JPG/ PNG)

《C#实现将Excel表格转换为图片(JPG/PNG)》Excel表格可能会因为不同设备或字体缺失等问题,导致格式错乱或数据显示异常,转换为图片后,能确保数据的排版等保持一致,下面我们看看如何使用C... 目录通过C# 转换Excel工作表到图片通过C# 转换指定单元格区域到图片知识扩展C# 将 Excel

JS+HTML实现在线图片水印添加工具

《JS+HTML实现在线图片水印添加工具》在社交媒体和内容创作日益频繁的今天,如何保护原创内容、展示品牌身份成了一个不得不面对的问题,本文将实现一个完全基于HTML+CSS构建的现代化图片水印在线工具... 目录概述功能亮点使用方法技术解析延伸思考运行效果项目源码下载总结概述在社交媒体和内容创作日益频繁的

使用Node.js制作图片上传服务的详细教程

《使用Node.js制作图片上传服务的详细教程》在现代Web应用开发中,图片上传是一项常见且重要的功能,借助Node.js强大的生态系统,我们可以轻松搭建高效的图片上传服务,本文将深入探讨如何使用No... 目录准备工作搭建 Express 服务器配置 multer 进行图片上传处理图片上传请求完整代码示例

基于Python实现高效PPT转图片工具

《基于Python实现高效PPT转图片工具》在日常工作中,PPT是我们常用的演示工具,但有时候我们需要将PPT的内容提取为图片格式以便于展示或保存,所以本文将用Python实现PPT转PNG工具,希望... 目录1. 概述2. 功能使用2.1 安装依赖2.2 使用步骤2.3 代码实现2.4 GUI界面3.效

Python实现AVIF图片与其他图片格式间的批量转换

《Python实现AVIF图片与其他图片格式间的批量转换》这篇文章主要为大家详细介绍了如何使用Pillow库实现AVIF与其他格式的相互转换,即将AVIF转换为常见的格式,比如JPG或PNG,需要的小... 目录环境配置1.将单个 AVIF 图片转换为 JPG 和 PNG2.批量转换目录下所有 AVIF 图

详解如何通过Python批量转换图片为PDF

《详解如何通过Python批量转换图片为PDF》:本文主要介绍如何基于Python+Tkinter开发的图片批量转PDF工具,可以支持批量添加图片,拖拽等操作,感兴趣的小伙伴可以参考一下... 目录1. 概述2. 功能亮点2.1 主要功能2.2 界面设计3. 使用指南3.1 运行环境3.2 使用步骤4. 核

Java图片压缩三种高效压缩方案详细解析

《Java图片压缩三种高效压缩方案详细解析》图片压缩通常涉及减少图片的尺寸缩放、调整图片的质量(针对JPEG、PNG等)、使用特定的算法来减少图片的数据量等,:本文主要介绍Java图片压缩三种高效... 目录一、基于OpenCV的智能尺寸压缩技术亮点:适用场景:二、JPEG质量参数压缩关键技术:压缩效果对比

使用Python开发一个简单的本地图片服务器

《使用Python开发一个简单的本地图片服务器》本文介绍了如何结合wxPython构建的图形用户界面GUI和Python内建的Web服务器功能,在本地网络中搭建一个私人的,即开即用的网页相册,文中的示... 目录项目目标核心技术栈代码深度解析完整代码工作流程主要功能与优势潜在改进与思考运行结果总结你是否曾经

Python FastAPI+Celery+RabbitMQ实现分布式图片水印处理系统

《PythonFastAPI+Celery+RabbitMQ实现分布式图片水印处理系统》这篇文章主要为大家详细介绍了PythonFastAPI如何结合Celery以及RabbitMQ实现简单的分布式... 实现思路FastAPI 服务器Celery 任务队列RabbitMQ 作为消息代理定时任务处理完整

使用C#代码在PDF文档中添加、删除和替换图片

《使用C#代码在PDF文档中添加、删除和替换图片》在当今数字化文档处理场景中,动态操作PDF文档中的图像已成为企业级应用开发的核心需求之一,本文将介绍如何在.NET平台使用C#代码在PDF文档中添加、... 目录引言用C#添加图片到PDF文档用C#删除PDF文档中的图片用C#替换PDF文档中的图片引言在当