flutter开发实战-hero实现图片预览功能extend_image

flutter开发实战-hero实现图片预览功能extend_image

在开发中,经常遇到需要图片预览,当feed中点击一个图片,开启预览,多个图片可以左右切换swiper,双击图片及手势进行缩放功能。
这个主要实现使用extend_image插件。在点击图片时候使用hero动画进行展示。

Hero简单使用,可以查看https://brucegwo.blog.csdn.net/article/details/134005601

hero实现图片预览功能效果图

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

一、图片GridView

在展示多张图片,使用GridView来展示。

GridView可以构建一个二维网格列表,其默认构造函数定义如下:

  GridView({Key? key,Axis scrollDirection = Axis.vertical,bool reverse = false,ScrollController? controller,bool? primary,ScrollPhysics? physics,bool shrinkWrap = false,EdgeInsetsGeometry? padding,required this.gridDelegate,  //下面解释bool addAutomaticKeepAlives = true,bool addRepaintBoundaries = true,double? cacheExtent, List<Widget> children = const <Widget>[],...})

SliverGridDelegate是一个抽象类,定义了GridView Layout相关接口,子类需要通过实现它们来实现具体的布局算法。

实现展示图片GridView

GridView.builder(gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(maxCrossAxisExtent: 300,crossAxisSpacing: 10,mainAxisSpacing: 10,),itemBuilder: (BuildContext context, int index) {...

完整代码如下

class GridSimplePhotoViewDemo extends StatefulWidget {_GridSimplePhotoViewDemoState createState() =>_GridSimplePhotoViewDemoState();
}class _GridSimplePhotoViewDemoState extends State<GridSimplePhotoViewDemo> {List<String> images = <String>['https://photo.tuchong.com/14649482/f/601672690.jpg','https://photo.tuchong.com/17325605/f/641585173.jpg','https://photo.tuchong.com/3541468/f/256561232.jpg','https://photo.tuchong.com/16709139/f/278778447.jpg','This is an video','https://photo.tuchong.com/5040418/f/43305517.jpg','https://photo.tuchong.com/3019649/f/302699092.jpg'];Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('SimplePhotoView'),),body: Padding(padding: const EdgeInsets.all(10.0),child: GridView.builder(gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(maxCrossAxisExtent: 300,crossAxisSpacing: 10,mainAxisSpacing: 10,),itemBuilder: (BuildContext context, int index) {final String url = images[index];return GestureDetector(child: AspectRatio(aspectRatio: 1.0,child: Hero(tag: url,child: url == 'This is an video'? Container(alignment: Alignment.center,child: const Text('This is an video'),): ExtendedImage.network(url,fit: BoxFit.cover,),),),onTap: () {Navigator.of(context).push(TransparentPageRoute(pageBuilder:(BuildContext context, Animation<double> animation,Animation<double> secondaryAnimation) {return PicSwiper(index: index,pics: images,);}));},);},itemCount: images.length,),),);}
}

二、跳转到Swiper的TransparentPageRoute

当点击跳转到新的页面的时候,可以使用TransparentPageRoute,该类继承与PageRouteBuilder,实现FadeTransition在点击图片展示预览图片的时候,通过渐隐渐显的方式跳转到下一个路由。

Widget _defaultTransitionsBuilder(BuildContext context,Animation<double> animation,Animation<double> secondaryAnimation,Widget child,) {return FadeTransition(opacity: CurvedAnimation(parent: animation,curve: Curves.easeOut,),child: child,);
}

完整代码如下

import 'package:flutter/material.dart';/// Transparent Page Route
class TransparentPageRoute<T> extends PageRouteBuilder<T> {TransparentPageRoute({RouteSettings? settings,required RoutePageBuilder pageBuilder,RouteTransitionsBuilder transitionsBuilder = _defaultTransitionsBuilder,Duration transitionDuration = const Duration(milliseconds: 250),bool barrierDismissible = false,Color? barrierColor,String? barrierLabel,bool maintainState = true,}) : super(settings: settings,opaque: false,pageBuilder: pageBuilder,transitionsBuilder: transitionsBuilder,transitionDuration: transitionDuration,barrierDismissible: barrierDismissible,barrierColor: barrierColor,barrierLabel: barrierLabel,maintainState: maintainState,);
}Widget _defaultTransitionsBuilder(BuildContext context,Animation<double> animation,Animation<double> secondaryAnimation,Widget child,) {return FadeTransition(opacity: CurvedAnimation(parent: animation,curve: Curves.easeOut,),child: child,);
}

三、使用extend_image

在pubspec.yaml引入extend_image

  # extended_imageextended_image: ^7.0.2

当点击图片的时候,传入多张图片,定位到当前的index,多个图片可以左右切换Swiper。这里使用到了ExtendedImageGesturePageView。ExtendedImageGesturePageView与PageView类似,它是为显示缩放/平移图像而设计的。
如果您已经缓存了手势,请记住在正确的时间调用clearGestureDetailsCache()方法。(例如,页面视图页面被丢弃)

ExtendedImageGesturePageView属性

  • cacheGesture 保存手势状态(例如在ExtendedImageGesturePageView中,向后滚动时手势状态不会改变),记住clearGestureDetailsCache
  • inPageView 是否在ExtendedImageGesturePageView中

使用示例

ExtendedImageGesturePageView.builder(itemBuilder: (BuildContext context, int index) {var item = widget.pics[index].picUrl;Widget image = ExtendedImage.network(item,fit: BoxFit.contain,mode: ExtendedImageMode.gesture,gestureConfig: GestureConfig(inPageView: true, initialScale: 1.0,//you can cache gesture state even though page view page change.//remember call clearGestureDetailsCache() method at the right time.(for example,this page dispose)cacheGesture: false),);image = Container(child: image,padding: EdgeInsets.all(5.0),);if (index == currentIndex) {return Hero(tag: item + index.toString(),child: image,);} else {return image;}},itemCount: widget.pics.length,onPageChanged: (int index) {currentIndex = index;rebuild.add(index);},controller: PageController(initialPage: currentIndex,),scrollDirection: Axis.horizontal,
)

四、使用hero_widget

当点击图片,实现hero_widget实现hero动画来实现图片预览。
使用Flutter的Hero widget创建hero动画。 将hero从一个路由飞到另一个路由。 将hero 的形状从圆形转换为矩形,同时将其从一个路由飞到另一个路由的过程中进行动画处理。

这里使用的hero_widget完整代码如下

import 'package:extended_image/extended_image.dart';
import 'package:flutter/material.dart';/// make hero better when slide out
class HeroWidget extends StatefulWidget {const HeroWidget({required this.child,required this.tag,required this.slidePagekey,this.slideType = SlideType.onlyImage,});final Widget child;final SlideType slideType;final Object tag;final GlobalKey<ExtendedImageSlidePageState> slidePagekey;_HeroWidgetState createState() => _HeroWidgetState();
}class _HeroWidgetState extends State<HeroWidget> {RectTween? _rectTween;Widget build(BuildContext context) {return Hero(tag: widget.tag,createRectTween: (Rect? begin, Rect? end) {_rectTween = RectTween(begin: begin, end: end);return _rectTween!;},// make hero better when slide outflightShuttleBuilder: (BuildContext flightContext,Animation<double> animation,HeroFlightDirection flightDirection,BuildContext fromHeroContext,BuildContext toHeroContext) {// make hero more smoothlyfinal Hero hero = (flightDirection == HeroFlightDirection.pop? fromHeroContext.widget: toHeroContext.widget) as Hero;if (_rectTween == null) {return hero;}if (flightDirection == HeroFlightDirection.pop) {final bool fixTransform = widget.slideType == SlideType.onlyImage &&(widget.slidePagekey.currentState!.offset != Offset.zero ||widget.slidePagekey.currentState!.scale != 1.0);final Widget toHeroWidget = (toHeroContext.widget as Hero).child;return AnimatedBuilder(animation: animation,builder: (BuildContext buildContext, Widget? child) {Widget animatedBuilderChild = hero.child;// make hero more smoothlyanimatedBuilderChild = Stack(clipBehavior: Clip.antiAlias,alignment: Alignment.center,children: <Widget>[Opacity(opacity: 1 - animation.value,child: UnconstrainedBox(child: SizedBox(width: _rectTween!.begin!.width,height: _rectTween!.begin!.height,child: toHeroWidget,),),),Opacity(opacity: animation.value,child: animatedBuilderChild,)],);// fix transform when slide outif (fixTransform) {final Tween<Offset> offsetTween = Tween<Offset>(begin: Offset.zero,end: widget.slidePagekey.currentState!.offset);final Tween<double> scaleTween = Tween<double>(begin: 1.0, end: widget.slidePagekey.currentState!.scale);animatedBuilderChild = Transform.translate(offset: offsetTween.evaluate(animation),child: Transform.scale(scale: scaleTween.evaluate(animation),child: animatedBuilderChild,),);}return animatedBuilderChild;},);}return hero.child;},child: widget.child,);}
}

五、使用Pic_Swiper

在swiper左右切换功能,使用ExtendedImageGesturePageView来实现切换功能,双击图片及手势进行缩放功能。

完整代码如下

typedef DoubleClickAnimationListener = void Function();class PicSwiper extends StatefulWidget {const PicSwiper({super.key,this.index,this.pics,});final int? index;final List<String>? pics;_PicSwiperState createState() => _PicSwiperState();
}class _PicSwiperState extends State<PicSwiper> with TickerProviderStateMixin {final StreamController<int> rebuildIndex = StreamController<int>.broadcast();final StreamController<bool> rebuildSwiper =StreamController<bool>.broadcast();final StreamController<double> rebuildDetail =StreamController<double>.broadcast();late AnimationController _doubleClickAnimationController;late AnimationController _slideEndAnimationController;late Animation<double> _slideEndAnimation;Animation<double>? _doubleClickAnimation;late DoubleClickAnimationListener _doubleClickAnimationListener;List<double> doubleTapScales = <double>[1.0, 2.0];GlobalKey<ExtendedImageSlidePageState> slidePagekey =GlobalKey<ExtendedImageSlidePageState>();int? _currentIndex = 0;bool _showSwiper = true;double _imageDetailY = 0;Rect? imageDRect;Widget build(BuildContext context) {final Size size = MediaQuery.of(context).size;double statusBarHeight = MediaQuery.of(context).padding.top;imageDRect = Offset.zero & size;Widget result = Material(color: Colors.transparent,shadowColor: Colors.transparent,child: Stack(fit: StackFit.expand,children: <Widget>[ExtendedImageGesturePageView.builder(controller: ExtendedPageController(initialPage: widget.index!,pageSpacing: 50,shouldIgnorePointerWhenScrolling: false,),scrollDirection: Axis.horizontal,physics: const BouncingScrollPhysics(),canScrollPage: (GestureDetails? gestureDetails) {return _imageDetailY >= 0;},itemBuilder: (BuildContext context, int index) {final String item = widget.pics![index];Widget image = ExtendedImage.network(item,fit: BoxFit.contain,enableSlideOutPage: true,mode: ExtendedImageMode.gesture,imageCacheName: 'CropImage',//layoutInsets: EdgeInsets.all(20),initGestureConfigHandler: (ExtendedImageState state) {double? initialScale = 1.0;if (state.extendedImageInfo != null) {initialScale = initScale(size: size,initialScale: initialScale,imageSize: Size(state.extendedImageInfo!.image.width.toDouble(),state.extendedImageInfo!.image.height.toDouble()));}return GestureConfig(inPageView: true,initialScale: initialScale!,maxScale: max(initialScale, 5.0),animationMaxScale: max(initialScale, 5.0),initialAlignment: InitialAlignment.center,//you can cache gesture state even though page view page change.//remember call clearGestureDetailsCache() method at the right time.(for example,this page dispose)cacheGesture: false,);},onDoubleTap: (ExtendedImageGestureState state) {///you can use define pointerDownPosition as you can,///default value is double tap pointer down postion.final Offset? pointerDownPosition = state.pointerDownPosition;final double? begin = state.gestureDetails!.totalScale;double end;//remove old_doubleClickAnimation?.removeListener(_doubleClickAnimationListener);//stop pre_doubleClickAnimationController.stop();//reset to use_doubleClickAnimationController.reset();if (begin == doubleTapScales[0]) {end = doubleTapScales[1];} else {end = doubleTapScales[0];}_doubleClickAnimationListener = () {//print(_animation.value);state.handleDoubleTap(scale: _doubleClickAnimation!.value,doubleTapPosition: pointerDownPosition);};_doubleClickAnimation = _doubleClickAnimationController.drive(Tween<double>(begin: begin, end: end));_doubleClickAnimation!.addListener(_doubleClickAnimationListener);_doubleClickAnimationController.forward();},loadStateChanged: (ExtendedImageState state) {if (state.extendedImageLoadState == LoadState.completed) {return StreamBuilder<double>(builder:(BuildContext context, AsyncSnapshot<double> data) {return ExtendedImageGesture(state,imageBuilder: (Widget image) {return Stack(children: <Widget>[Positioned.fill(child: image,),],);},);},initialData: _imageDetailY,stream: rebuildDetail.stream,);}return null;},);image = HeroWidget(tag: item,slideType: SlideType.onlyImage,slidePagekey: slidePagekey,child: image,);image = GestureDetector(child: image,onTap: () {slidePagekey.currentState!.popPage();Navigator.pop(context);},);return image;},itemCount: widget.pics!.length,onPageChanged: (int index) {_currentIndex = index;rebuildIndex.add(index);if (_imageDetailY != 0) {_imageDetailY = 0;rebuildDetail.sink.add(_imageDetailY);}_showSwiper = true;rebuildSwiper.add(_showSwiper);},),StreamBuilder<bool>(builder: (BuildContext c, AsyncSnapshot<bool> d) {if (d.data == null || !d.data!) {return Container();}return Positioned(top: statusBarHeight,left: 0.0,right: 0.0,child: MySwiperPlugin(widget.pics, _currentIndex, rebuildIndex),);},initialData: true,stream: rebuildSwiper.stream,)],),);result = ExtendedImageSlidePage(key: slidePagekey,child: result,slideAxis: SlideAxis.vertical,slideType: SlideType.onlyImage,slideScaleHandler: (Offset offset, {ExtendedImageSlidePageState? state,}) {return null;},slideOffsetHandler: (Offset offset, {ExtendedImageSlidePageState? state,}) {return null;},slideEndHandler: (Offset offset, {ExtendedImageSlidePageState? state,ScaleEndDetails? details,}) {return null;},onSlidingPage: (ExtendedImageSlidePageState state) {///you can change other widgets' state on page as you want///base on offset/isSliding etc//var offset= state.offset;final bool showSwiper = !state.isSliding;if (showSwiper != _showSwiper) {// do not setState directly here, the image state will change,// you should only notify the widgets which are needed to change// setState(() {// _showSwiper = showSwiper;// });_showSwiper = showSwiper;rebuildSwiper.add(_showSwiper);}},);return result;}void dispose() {rebuildIndex.close();rebuildSwiper.close();rebuildDetail.close();_doubleClickAnimationController.dispose();_slideEndAnimationController.dispose();clearGestureDetailsCache();//cancelToken?.cancel();super.dispose();}void initState() {super.initState();_currentIndex = widget.index;_doubleClickAnimationController = AnimationController(duration: const Duration(milliseconds: 150), vsync: this);_slideEndAnimationController = AnimationController(vsync: this,duration: const Duration(milliseconds: 150),);_slideEndAnimationController.addListener(() {_imageDetailY = _slideEndAnimation.value;if (_imageDetailY == 0) {_showSwiper = true;rebuildSwiper.add(_showSwiper);}rebuildDetail.sink.add(_imageDetailY);});}
}class MySwiperPlugin extends StatelessWidget {const MySwiperPlugin(this.pics, this.index, this.reBuild);final List<String>? pics;final int? index;final StreamController<int> reBuild;Widget build(BuildContext context) {return StreamBuilder<int>(builder: (BuildContext context, AsyncSnapshot<int> data) {return DefaultTextStyle(style: const TextStyle(color: Colors.blue),child: Container(height: 50.0,width: double.infinity,// color: Colors.grey.withOpacity(0.2),child: Row(children: <Widget>[Container(width: 10.0,),Text('${data.data! + 1}',),Text(' / ${pics!.length}',),const SizedBox(width: 10.0,),const SizedBox(width: 10.0,),if (!kIsWeb)GestureDetector(child: Container(padding: const EdgeInsets.only(right: 10.0),alignment: Alignment.center,child: const Text('Save',style: TextStyle(fontSize: 16.0, color: Colors.blue),),),onTap: () {// saveNetworkImageToPhoto(pics![index!].picUrl)//     .then((bool done) {//   showToast(done ? 'save succeed' : 'save failed',//       position: const ToastPosition(//           align: Alignment.topCenter));// });},),],),),);},initialData: index,stream: reBuild.stream,);}
}class ImageDetailInfo {ImageDetailInfo({required this.imageDRect,required this.pageSize,required this.imageInfo,});final GlobalKey<State<StatefulWidget>> key = GlobalKey<State>();final Rect imageDRect;final Size pageSize;final ImageInfo imageInfo;double? _maxImageDetailY;double get imageBottom => imageDRect.bottom - 20;double get maxImageDetailY {try {//return _maxImageDetailY ??= max(key.currentContext!.size!.height - (pageSize.height - imageBottom),0.1);} catch (e) {//currentContext is not readyreturn 100.0;}}
}

使用过程中的util

import 'package:extended_image/extended_image.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart';///
///  create by zmtzawqlp on 2020/1/31
///
double? initScale({required Size imageSize,required Size size,double? initialScale,
}) {final double n1 = imageSize.height / imageSize.width;final double n2 = size.height / size.width;if (n1 > n2) {final FittedSizes fittedSizes =applyBoxFit(BoxFit.contain, imageSize, size);//final Size sourceSize = fittedSizes.source;final Size destinationSize = fittedSizes.destination;return size.width / destinationSize.width;} else if (n1 / n2 < 1 / 4) {final FittedSizes fittedSizes =applyBoxFit(BoxFit.contain, imageSize, size);//final Size sourceSize = fittedSizes.source;final Size destinationSize = fittedSizes.destination;return size.height / destinationSize.height;}return initialScale;
}

效果视频

六、小结

flutter开发实战-hero实现图片预览功能extend_image。描述可能不太准确,请见谅。

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

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用时间潜在瓶颈网络进行图像分类

介绍 简单的循环神经网络(RNN)对学习 时间压缩表示表现出强烈的归纳偏差。方程 1显示了递推公式,其中h_t是整个输入序列 的压缩表示(单个向量)x。 方程 1:递推方程。(来源:Aritra 和 Suvaditya)另一方面,Transformers(Vaswani 等人)对于学习时间压缩表示几乎没有归…

深入浅出排序算法之直接插入排序(拓展:折半插入排序)

目录 1. 图示解析 2. 原理解析 3. 代码实现 4. 性能分析 5. 折半插入排序&#xff08;拓展&#xff09; 直接插入排序和选择排序的第一趟就是第一个关键字 &#xff01; 1. 图示解析 2. 原理解析 整个区间被分为&#xff1a;① 有序区间&#xff1b;② 无序区间 每次选…

【2023】通过redis 实现分布式锁由原生到Redisson代码三种实现和介绍

目录 一、简介分布式锁的实现应该具备哪些条件分布式锁的实现方式 二、具体实现1、RedisTemplate的setnx方式实现1.1、基本配置1.1.1、创建spring项目添加依赖1.1.2、添加RedisTemplate配置bean 1.2、编写DistributedLock类1.2、编写Controller层使用分布式锁1.3、可能出现的问…

智慧公厕:细致入微的城市贴心服务与便捷方便的生活配套

在现代城市生活中&#xff0c;公厕作为重要的城市基础设施&#xff0c;一直是城市发展的关键环节之一。然而&#xff0c;传统的公厕常常存在着设施陈旧、管理不善和卫生状况差等问题&#xff0c;给市民的生活品质和城市形象带来了一定的影响。为了提供更好的城市公厕服务&#…

正点原子嵌入式linux驱动开发——Linux PWM驱动

PWM是很常用到功能&#xff0c;可以通过PWM来控制电机速度&#xff0c;也可以使用PWM来控制LCD的背光亮度。本章就来学习一下如何在Linux下进行PWM驱动开发。 PWM驱动解析 不在介绍PWM是什么了&#xff0c;直接进入使用。 给LCD的背光引脚输入一个PWM信号&#xff0c;这样就…

25装饰器2

有一个比较绕的地方&#xff0c;但是我相信我能理解透彻这个里面的逻辑还有原理 def check(func):print(登录验证)def inner():func()return innerdef fss():print(发说说)fss check(fss) fss()这里的fss check(fss)还有后面的fss()什么意思&#xff1f;怎么理解呢&#xff…

【微信小程序开发】小程序微信用户授权登录(用户信息手机号)

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于小程序的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 授权流程讲解 一.用户信息授权登录 1.w…

记一次vue3实现TRSP大华相机拉流的经历

一、背景 业务场景&#xff0c;大华IP相机安装在A城市某建筑场所&#xff0c;工控机是内网通过4G流量卡上网&#xff0c;工控机通过相机采集数据后做故障识别并上传故障信息到地面服务器&#xff0c;地面服务器在B城市。 现需要在地面服务器提供的WEB界面上实现IP相机实时拉流…

CSS基础框盒模型:打造炙手可热的网页布局!

&#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 &#x1f4dd; 个人网站 :《 江城开朗的豌豆&#x1fadb; 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 ⭐ 专栏简介 &#x1f4d8; 文章引言 一、是…

逐鹿千亿市场:一碗中国面的魅力

【潮汐商业评论/原创】 根据世界方便面协会&#xff08;WINA&#xff09;发布的数据&#xff0c;2022年全球方便面总需求量同比增长4.0%至1212亿份&#xff0c;再创历史新高。从小门头商铺到大型商超&#xff0c;从线下到线上&#xff0c;方便面早就走进了千家万户&#xff0c…

使用adobe font style 工具绘制的艺术字,请鉴赏。

Adobe Fireflyhttps://firefly.adobe.com/generate/font-styles

引领位置服务驱动:腾讯地图 WebService 服务端 API 实用指南

&#x1f52d; 嗨&#xff0c;您好 &#x1f44b; 我是 vnjohn&#xff0c;在互联网企业担任 Java 开发&#xff0c;CSDN 优质创作者 &#x1f4d6; 推荐专栏&#xff1a;Spring、MySQL、Nacos、Java&#xff0c;后续其他专栏会持续优化更新迭代 &#x1f332;文章所在专栏&…

马蹄集OJ赛第十三次

目录 小码哥的抽卡之旅 抽奖概率 越狱 square 矩阵乘法 找朋友 赌石 甜甜花的研究 行列式 饿饿&#xff01;饭饭&#xff01; 小码哥的抽卡之旅 难度&#xff1a;黄金 ①时间限制&#xff1a;1秒 巴占用内存&#xff1a;128M 小码哥最近迷上了一款抽卡游戏。单抽出金…

AWS Lambda 操作 RDS 示例

实现目标 创建一个 Lambda 接收调用时传入的数据, 写入 RDS 数据库 Post 表存储文章信息. 表结构如下: idtitlecontentcreate_date1我是标题我是正文内容2023-10-21 15:20:00 AWS 资源准备 RDS 控制台创建 MySQL 实例, 不允许 Public access (后面 Lambda 需要通过 VPC 访问…

基于MIMO+16QAM系统的VBLAST译码算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 ........................................................................ for SNR_dBSNRS…

element-plus 自动按需引入icon unplugin-icons相关配置(有效)

1.安装的组件有这四个2.vite.config.js配置文件修改页面使用附完整vite.config.js配置 相关配置&#xff08;自行根据配置文件中的安装哈&#xff0c;我就不一 一列举了&#xff09; 1.安装的组件有这四个 2.vite.config.js配置文件修改 页面使用 <i-ep-edit />效果 附…

pytorch学习第四篇:从全连接到卷积

传统神经网络 传统神经网络nn,采用这种全连接的方式,可以看出是一列一列数据,包括起始和中间的隐层都是一列数据。 例如我们再对图像用这种方式来计算,需要把图像转为一列数据,例如图像为28x28单通道图像,需要转为28x28=784的列数据再进行神经网络训练。 input layer =…

基于 Android 的文件同步设计方案

1、背景 随着用户对自身数据保护意识的加强&#xff0c;让用户自己维护自己的数据也成了独立开发产品时的一个卖点。若只针对少量的文件进行同步&#xff0c;则实现起来比较简单。当针对一个多层级目录同步时&#xff0c;情况就复杂多了。鉴于相关的文章甚少&#xff0c;本文我…

【从删库到跑路】MySQL数据库 | 存储过程 | 存储函数(使用代码辅助理解)

&#x1f38a;专栏【MySQL】 &#x1f354;喜欢的诗句&#xff1a;更喜岷山千里雪 三军过后尽开颜。 &#x1f386;音乐分享【The Right Path】 &#x1f970;欢迎并且感谢大家指出小吉的问题 文章目录 &#x1f384;存储过程介绍&#x1f384;存储过程特点&#x1f33a;存储过…

找搭子平台小程序开发制作方案

找搭子小程序是一个基于地理位置的社交平台&#xff0c;旨在帮助用户找到附近的人&#xff0c;一起进行各种活动。的目标是打造一个安全、便捷、有趣的社交平台&#xff0c;让用户在享受活动的同时&#xff0c;也能结识新朋友。 找搭子平台小程序的目标用户主要是年轻人&#x…