如何在 Flutter 中制作前后图像滑块视图

问题描述

我想使用堆叠的两张图片创建一个 Before-After 视图,并在我的 Flutter 应用程序中提供有关前后视图的用户体验。

如何创建像这样的 Before/After 控件https://iosexample.com/fancy-slider-for-before-after-images-with-swift/

图片来源https://iosexample.com

enter image description here

解决方法

这是我自己的问题的答案以传播知识

创建一个 BeforeAfter 类

import 'package:flutter/material.dart';

import 'RectClipper.dart';

class BeforeAfter extends StatefulWidget {
  final Widget beforeImage;
  final Widget afterImage;
  final double imageHeight;
  final double imageWidth;
  final double imageCornerRadius;
  final Color thumbColor;
  final double thumbRadius;
  final Color overlayColor;
  final bool isVertical;

  const BeforeAfter({
    Key key,@required this.beforeImage,@required this.afterImage,this.imageHeight,this.imageWidth,this.imageCornerRadius = 8.0,this.thumbColor = Colors.white,this.thumbRadius = 16.0,this.overlayColor,this.isVertical = false,})  : assert(beforeImage != null),assert(afterImage != null),super(key: key);

  @override
  _BeforeAfterState createState() => _BeforeAfterState();
}

class _BeforeAfterState extends State<BeforeAfter> {
  double _clipFactor = 0.5;

  @override
  Widget build(BuildContext context) {
    return Stack(
      alignment: Alignment.center,children: <Widget>[
        Padding(
          padding: widget.isVertical ? const EdgeInsets.symmetric(vertical: 24.0) : const EdgeInsets.symmetric(horizontal: 24.0),child: SizedImage(
            widget.afterImage,widget.imageHeight,widget.imageWidth,widget.imageCornerRadius,),Padding(
          padding: widget.isVertical ? const EdgeInsets.symmetric(vertical: 24.0) : const EdgeInsets.symmetric(horizontal: 24.0),child: ClipPath(
            clipper: widget.isVertical ? RectClipperVertical(_clipFactor) : RectClipper(_clipFactor),child: SizedImage(
              widget.beforeImage,Positioned.fill(
          child: SliderTheme(
            data: SliderThemeData(
              trackHeight: 0.0,overlayColor: widget.overlayColor,thumbShape: CustomThumbShape(widget.thumbRadius,widget.thumbColor),child: widget.isVertical
                ? RotatedBox(
                    quarterTurns: 1,child: Slider(
                      value: _clipFactor,onChanged: (double factor) => setState(() => this._clipFactor = factor),)
                : Slider(
                    value: _clipFactor,],);
  }
}

class SizedImage extends StatelessWidget {
  final Widget _image;
  final double _height,_width,_imageCornerRadius;

  const SizedImage(this._image,this._height,this._width,this._imageCornerRadius,{Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ClipRRect(
      borderRadius: BorderRadius.circular(_imageCornerRadius),child: SizedBox(
        height: _height,width: _width,child: _image,);
  }
}

class CustomThumbShape extends SliderComponentShape {
  final double _thumbRadius;
  final Color _thumbColor;

  CustomThumbShape(this._thumbRadius,this._thumbColor);

  @override
  Size getPreferredSize(bool isEnabled,bool isDiscrete) {
    return Size.fromRadius(_thumbRadius);
  }

  @override
  void paint(
    PaintingContext context,Offset center,{
    Animation<double> activationAnimation,Animation<double> enableAnimation,bool isDiscrete,TextPainter labelPainter,RenderBox parentBox,SliderThemeData sliderTheme,TextDirection textDirection,double value,double textScaleFactor,Size sizeWithOverflow,}) {
    final Canvas canvas = context.canvas;

    final Paint paint = Paint()
      ..isAntiAlias = true
      ..strokeWidth = 4.0
      ..color = _thumbColor
      ..style = PaintingStyle.fill;

    final Paint paintStroke = Paint()
      ..isAntiAlias = true
      ..strokeWidth = 4.0
      ..color = _thumbColor
      ..style = PaintingStyle.stroke;

    canvas.drawCircle(
      center,_thumbRadius,paintStroke,);

    canvas.drawCircle(
      center,_thumbRadius - 6,paint,);

    canvas.drawRect(Rect.fromCenter(center: center,width: 4.0,height: parentBox.size.height),paint);
  }
}

然后创建一个 RectClipper 类

import 'package:flutter/material.dart';

class RectClipper extends CustomClipper<Path> {
  final double clipFactor;

  RectClipper(this.clipFactor);

  @override
  Path getClip(Size size) {
    Path path = Path();
    path.lineTo(size.width * clipFactor,0.0);
    path.lineTo(size.width * clipFactor,size.height);
    path.lineTo(0.0,size.height);
    path.close();
    return path;
  }

  @override
  bool shouldReclip(CustomClipper<Path> oldClipper) => true;
}

class RectClipperVertical extends CustomClipper<Path> {
  final double clipFactor;

  RectClipperVertical(this.clipFactor);

  @override
  Path getClip(Size size) {
    Path path = Path();
    path.lineTo(0.0,size.height * clipFactor);
    path.lineTo(size.width,0.0);
    path.close();
    return path;
  }

  @override
  bool shouldReclip(CustomClipper<Path> oldClipper) => true;
}

最后在屏幕上使用这些类

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

class BeforeAfterImageScreen extends StatefulWidget {
  static String tag = '/BeforeAfterImageScreen';

  @override
  BeforeAfterImageScreenState createState() => BeforeAfterImageScreenState();
}

class BeforeAfterImageScreenState extends State<BeforeAfterImageScreen> {
  @override
  Widget build(BuildContext context) {
    changeStatusColor(appColorPrimary);
    return Scaffold(
      appBar: appBar(context,"Before After Image"),body: Center(
        child: BeforeAfter(
          beforeImage: Image.asset('images/integrations/img/after.jpg'),afterImage: Image.asset('images/integrations/img/before.jpg'),);
  }
}

enter image description here

,

这是答案,一个很酷的图书馆 唯一的问题是不支持像remini一样放大图像

https://pub.dev/packages/before_after

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...