flutter开发实战-美颜前后对比图效果实现

2024-05-24 21:12

本文主要是介绍flutter开发实战-美颜前后对比图效果实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

flutter开发实战-美颜前后对比图效果实现
在这里插入图片描述

最近使用代码中遇到了图片前后对比,这里使用的是CustomClipper来实现

一、CustomClipper

我们实现CustomClipper子类来实现美颜后的图片裁剪功能

getClip()是用于获取剪裁区域的接口,由于图片大小是60×60,
我们返回剪裁区域为Rect.fromLTWH(10.0, 15.0, 40.0, 30.0),即图片中部40×30像素的范围。
shouldReclip() 接口决定是否重新剪裁。
如果在应用中,剪裁区域始终不会发生变化时应该返回false,这样就不会触发重新剪裁,避免不必要的性能开销。
如果剪裁区域会发生变化(比如在对剪裁区域执行一个动画),那么变化后应该返回true来重新执行剪裁。

二、使用CustomClipper来实现美颜前后对比图效果

美颜前后对比图,原图展示,美颜后的图片根据手势拖动距离进行裁剪
美颜之后的图裁剪,设置Clip.hardEdge。

ClipRect(clipper: compareCustomClipper,clipBehavior: Clip.hardEdge,child: CachedNetworkImage(imageUrl: "https://qiniu.example.com/64c2fba1-81ff-41dc-b32e-6920b0677f8c0",fit: BoxFit.cover,width: widget.width,height: widget.height,),),

手势拖动,更新compareCustomClipper

void onHorizontalDragDown(DragDownDetails details) {print("onHorizontalDragDown");startOffsetX = details.localPosition.dx;print("onHorizontalDragDown startOffsetX:${startOffsetX}");}void onHorizontalDragStart(DragStartDetails details) {print("onHorizontalDragStart");}void onHorizontalDragUpdate(DragUpdateDetails details) {print("onHorizontalDragUpdate");double curOffsetX = details.localPosition.dx;double distance = curOffsetX - startOffsetX;print("onHorizontalDragUpdate curOffsetX:${curOffsetX}, startOffsetX:${startOffsetX}, distance:${distance}");offsetX = widget.width! + distance;if (offsetX > widget.width!) {offsetX = widget.width!;}if (offsetX < 0) {offsetX = 0;}compareCustomClipper = CompareCustomClipper(Rect.fromLTWH(offsetX, 0.0, (widget.width ?? 0) - offsetX, widget.height ?? 0));setState(() {});}

完整代码如下


import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';class ComparePicPage extends StatefulWidget {const ComparePicPage({super.key});@overrideState<ComparePicPage> createState() => _ComparePicPageState();
}class _ComparePicPageState extends State<ComparePicPage> {@overrideWidget build(BuildContext context) {Size size = MediaQuery.of(context).size;return Scaffold(appBar: AppBar(title: const Text('ComparePicPage'),),body: Center(child: ComparePicWidget(width: 320,height: 480,),),);}
}// 自定义裁剪CustomClipper
class CompareCustomClipper extends CustomClipper<Rect> {CompareCustomClipper(this.rect);Rect rect;// Rect getClip(Size size) => Rect.fromLTWH(0.0, 15.0, 40.0, 30.0);@overrideRect getClip(Size size) => rect;@overridebool shouldReclip(CustomClipper<Rect> oldClipper) => true;
}/// 图片美颜前后对比
class ComparePicWidget extends StatefulWidget {const ComparePicWidget({super.key,this.width,this.height,});final double? width;final double? height;@overrideState<ComparePicWidget> createState() => _ComparePicWidgetState();
}class _ComparePicWidgetState extends State<ComparePicWidget> {// 定义一个裁剪CompareCustomClipper? compareCustomClipper;double offsetX = 0;double startOffsetX = 0;@overridevoid initState() {// TODO: implement initStateoffsetX = widget.width ?? 0;compareCustomClipper = CompareCustomClipper(Rect.fromLTWH(offsetX, 0.0, (widget.width ?? 0) - offsetX, widget.height ?? 0));super.initState();}@overridevoid dispose() {// TODO: implement disposesuper.dispose();}void onHorizontalDragDown(DragDownDetails details) {print("onHorizontalDragDown");startOffsetX = details.localPosition.dx;print("onHorizontalDragDown startOffsetX:${startOffsetX}");}void onHorizontalDragStart(DragStartDetails details) {print("onHorizontalDragStart");}void onHorizontalDragUpdate(DragUpdateDetails details) {print("onHorizontalDragUpdate");double curOffsetX = details.localPosition.dx;double distance = curOffsetX - startOffsetX;print("onHorizontalDragUpdate curOffsetX:${curOffsetX}, startOffsetX:${startOffsetX}, distance:${distance}");offsetX = widget.width! + distance;if (offsetX > widget.width!) {offsetX = widget.width!;}if (offsetX < 0) {offsetX = 0;}compareCustomClipper = CompareCustomClipper(Rect.fromLTWH(offsetX, 0.0, (widget.width ?? 0) - offsetX, widget.height ?? 0));setState(() {});}@overrideWidget build(BuildContext context) {return Container(width: widget.width,height: widget.height,decoration: BoxDecoration(color: Colors.black,borderRadius: const BorderRadius.all(Radius.circular(10),),border: Border.all(color: Colors.transparent,width: 0,style: BorderStyle.solid,),),clipBehavior: Clip.none,child: Stack(alignment: Alignment.center,clipBehavior: Clip.none,children: [// 原图ClipRect(clipBehavior: Clip.hardEdge,child: CachedNetworkImage(imageUrl: "https://qiniu.example.com/Fsgjbe7O8Z5x83_Aff8-Qage9bpc8e.png",fit: BoxFit.cover,width: widget.width,height: widget.height,),),// 美颜之后的图ClipRect(clipper: compareCustomClipper,clipBehavior: Clip.hardEdge,child: CachedNetworkImage(imageUrl: "https://qiniu.example.com/64c2fba1-81ff-41dc-b32e-6920b0677f833c",fit: BoxFit.cover,width: widget.width,height: widget.height,),),// linePositioned(left: offsetX + 26.5 + (-27.5),child: buildLine(context),),Positioned(left: offsetX + (-27.5),child: buildCustomButton(context),),// tipPositioned(left: 20,top: 20,child: buildCompareTip(context, "原图"),),Positioned(right: 20,top: 20,child: buildCompareTip(context, "美颜后"),),],),);}Widget buildLine(BuildContext context) {return Image.asset("assets/images/line.png",width: 2,height: 576,fit: BoxFit.cover,);}Widget buildCustomButton(BuildContext context) {return GestureDetector(onHorizontalDragDown: (DragDownDetails details) {onHorizontalDragDown(details);},onHorizontalDragStart: (DragStartDetails details) {onHorizontalDragStart(details);},onHorizontalDragUpdate: (DragUpdateDetails details) {onHorizontalDragUpdate(details);},child: Image.asset("assets/images/move_button.png",width: 55,height: 55,fit: BoxFit.cover,),);}Widget buildCompareTip(BuildContext context, String title) {return Container(width: 60,height: 30,alignment: Alignment.center,decoration: BoxDecoration(color: Colors.black.withOpacity(0.35),borderRadius: const BorderRadius.all(Radius.circular(20),),),child: Text(title,maxLines: 1,overflow: TextOverflow.ellipsis,textAlign: TextAlign.center,style: const TextStyle(fontSize: 13,fontWeight: FontWeight.w600,fontStyle: FontStyle.normal,color: Colors.white,decoration: TextDecoration.none,),),);}
}

三、小结

flutter开发实战-美颜前后对比图效果实现

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

这篇关于flutter开发实战-美颜前后对比图效果实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

SpringBoot3实现Gzip压缩优化的技术指南

《SpringBoot3实现Gzip压缩优化的技术指南》随着Web应用的用户量和数据量增加,网络带宽和页面加载速度逐渐成为瓶颈,为了减少数据传输量,提高用户体验,我们可以使用Gzip压缩HTTP响应,... 目录1、简述2、配置2.1 添加依赖2.2 配置 Gzip 压缩3、服务端应用4、前端应用4.1 N

SpringBoot实现数据库读写分离的3种方法小结

《SpringBoot实现数据库读写分离的3种方法小结》为了提高系统的读写性能和可用性,读写分离是一种经典的数据库架构模式,在SpringBoot应用中,有多种方式可以实现数据库读写分离,本文将介绍三... 目录一、数据库读写分离概述二、方案一:基于AbstractRoutingDataSource实现动态

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

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

Java枚举类实现Key-Value映射的多种实现方式

《Java枚举类实现Key-Value映射的多种实现方式》在Java开发中,枚举(Enum)是一种特殊的类,本文将详细介绍Java枚举类实现key-value映射的多种方式,有需要的小伙伴可以根据需要... 目录前言一、基础实现方式1.1 为枚举添加属性和构造方法二、http://www.cppcns.co

使用Python实现快速搭建本地HTTP服务器

《使用Python实现快速搭建本地HTTP服务器》:本文主要介绍如何使用Python快速搭建本地HTTP服务器,轻松实现一键HTTP文件共享,同时结合二维码技术,让访问更简单,感兴趣的小伙伴可以了... 目录1. 概述2. 快速搭建 HTTP 文件共享服务2.1 核心思路2.2 代码实现2.3 代码解读3.

MySQL双主搭建+keepalived高可用的实现

《MySQL双主搭建+keepalived高可用的实现》本文主要介绍了MySQL双主搭建+keepalived高可用的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,... 目录一、测试环境准备二、主从搭建1.创建复制用户2.创建复制关系3.开启复制,确认复制是否成功4.同

Java实现文件图片的预览和下载功能

《Java实现文件图片的预览和下载功能》这篇文章主要为大家详细介绍了如何使用Java实现文件图片的预览和下载功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... Java实现文件(图片)的预览和下载 @ApiOperation("访问文件") @GetMapping("

Spring Boot + MyBatis Plus 高效开发实战从入门到进阶优化(推荐)

《SpringBoot+MyBatisPlus高效开发实战从入门到进阶优化(推荐)》本文将详细介绍SpringBoot+MyBatisPlus的完整开发流程,并深入剖析分页查询、批量操作、动... 目录Spring Boot + MyBATis Plus 高效开发实战:从入门到进阶优化1. MyBatis

MyBatis 动态 SQL 优化之标签的实战与技巧(常见用法)

《MyBatis动态SQL优化之标签的实战与技巧(常见用法)》本文通过详细的示例和实际应用场景,介绍了如何有效利用这些标签来优化MyBatis配置,提升开发效率,确保SQL的高效执行和安全性,感... 目录动态SQL详解一、动态SQL的核心概念1.1 什么是动态SQL?1.2 动态SQL的优点1.3 动态S

Python基于wxPython和FFmpeg开发一个视频标签工具

《Python基于wxPython和FFmpeg开发一个视频标签工具》在当今数字媒体时代,视频内容的管理和标记变得越来越重要,无论是研究人员需要对实验视频进行时间点标记,还是个人用户希望对家庭视频进行... 目录引言1. 应用概述2. 技术栈分析2.1 核心库和模块2.2 wxpython作为GUI选择的优