写了一个经常在针对图片处理 显示处理前和处理后的对比Widget
import 'package:flutter/material.dart';
class ImageCompareSlider extends StatefulWidget {
final Widget beforeImage;
final Widget afterImage;
final Color? dividerColor;
final Color? handleColor;
final double handleSize;
final double dividerWidth;
final IconData? handleIcon;
const ImageCompareSlider({
super.key,
required this.beforeImage,
required this.afterImage,
this.dividerColor = const Color(0x88FFFFFF),
this.handleColor = const Color(0x88FFFFFF),
this.handleSize = 50,
this.dividerWidth = 2,
this.handleIcon = Icons.compare_arrows,
});
@override
State<ImageCompareSlider> createState() => _ImageCompareSliderState();
}
class _ImageCompareSliderState extends State<ImageCompareSlider> {
double _sliderPosition = 0.5;
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
final width = constraints.maxWidth;
final height = constraints.maxHeight;
return Stack(
children: [
// 左边的图片
Positioned.fill(
child: widget.beforeImage,
),
// 右边的图片
Positioned.fill(
child: ClipPath(
clipper: SlideClipper(_sliderPosition),
child: widget.afterImage,
),
),
// 拖动条
Positioned.fill(
child: GestureDetector(
onHorizontalDragUpdate: (details) {
setState(() {
_sliderPosition = (details.globalPosition.dx / width)
.clamp(0.0, 1.0);
});
},
child: Stack(
children: [
// 分割线
Positioned(
left: width * _sliderPosition - widget.dividerWidth / 2,
top: 0,
height: height,
child: Container(
width: widget.dividerWidth,
color: widget.dividerColor,
),
),
// 拖动手柄
Positioned(
left: width * _sliderPosition - widget.handleSize / 2,
top: (height - widget.handleSize) / 2,
child: Container(
width: widget.handleSize,
height: widget.handleSize,
decoration: BoxDecoration(
color: widget.handleColor,
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.3),
blurRadius: 4,
offset: const Offset(0, 2),
),
],
),
child: Icon(
widget.handleIcon,
color: Colors.white,
size: widget.handleSize * 0.6,
),
),
),
// 增加拖动热区
Positioned(
left: width * _sliderPosition - widget.handleSize / 2,
top: 0,
height: height,
child: Container(
width: widget.handleSize,
color: Colors.transparent,
),
),
],
),
),
),
],
);
},
);
}
}
class SlideClipper extends CustomClipper<Path> {
final double position;
SlideClipper(this.position);
@override
Path getClip(Size size) {
return Path()
..addRect(Rect.fromLTWH(
size.width * position,
0,
size.width - (size.width * position),
size.height,
));
}
@override
bool shouldReclip(CustomClipper<Path> oldClipper) => true;
}
如何使用
SizedBox(
width: double.infinity,
height: 350,
child: ImageCompareSlider(
beforeImage: Image.asset(
'assets/before.jpg',
fit: BoxFit.cover,
),
afterImage: Image.asset(
'assets/after.jpg',
fit: BoxFit.cover,
),
// 可选的自定义参数
// dividerColor: Colors.blue,
// handleColor: Colors.purple,
handleSize: 50,
dividerWidth: 2,
handleIcon: Icons.compare_arrows,
),
)