Añadir el icono SVG en el control deslizante personalizado usando el pintor personalizado

votos
3

Estoy implementando el deslizador personalizado, donde he completado la detección de gestos en el deslizador, ahora quiero añadir el icono SVG en el mando para arrastrar, no puedo encontrar ningún recurso. Sólo quiero añadir el SVG a cualquier idea de cómo implementarlo. He puesto mi código y me hacen saber cualquier sugerencia si ustedes tienen.

Archivo principal de ui

import 'package:animations_sample/custom_slider.dart';
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  MyApp({Key key}) : super(key: key);

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

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: Container(
            width: 200,
            height: 200,
            child: LeftSlider(),
          ),
        ),
      ),
    );
  }
}

Archivo Slider personalizado

import 'dart:io';

import 'package:animations_sample/base_painter.dart';
import 'package:animations_sample/customleftPainter.dart';
import 'package:animations_sample/utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'dart:async';
import 'dart:typed_data';
import 'dart:ui' as UI;

import 'package:flutter/services.dart' show rootBundle;
import 'package:path_provider/path_provider.dart';

import 'package:flutter/services.dart';

class LeftSlider extends StatefulWidget {
  LeftSlider({Key key}) : super(key: key);

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

class _LeftSliderState extends State<LeftSlider> {
  //intial Values coming
  int leftEnd = 12;
  String rawLeftSvg =
      '''<svg xmlns=http://www.w3.org/2000/svg height=512px viewBox=0 0 32 32 width=512px><g><path d=m8 0c-4.41113 0-8 3.58887-8 8s3.58887 8 8 8 8-3.58887 8-8-3.58887-8-8-8zm0 15c-3.85986 0-7-3.14014-7-7s3.14014-7 7-7 7 3.14014 7 7-3.14014 7-7 7z data-original=#000000 class=active-path data-old_color=#000000 fill=#2184C4/><path d=m9 3c-1.04364 0-1.9624.536926-2.5 1.34772v-3.84772c0-.276367-.223633-.5-.5-.5-1.6543 0-3 1.3457-3 3 0 1.04364.536926 1.9624 1.34772 2.5h-3.84772c-.276367 0-.5.223633-.5.5 0 1.6543 1.3457 3 3 3 1.04364 0 1.9624-.536926 2.5-1.34772v3.84772c0 .276367.223633.5.5.5 1.6543 0 3-1.3457 3-3 0-1.04364-.536926-1.9624-1.34772-2.5h3.84772c.276367 0 .5-.223633.5-.5 0-1.6543-1.3457-3-3-3zm-6 5c-.930176 0-1.71436-.638184-1.93652-1.5h3.87305c-.222168.861816-1.00635 1.5-1.93652 1.5zm1-5c0-.930176.638184-1.71436 1.5-1.93652v3.87305c-.861816-.222168-1.5-1.00635-1.5-1.93652zm2 3.5c-.276123 0-.5-.223877-.5-.5 0-.276184.223877-.5.5-.5s.5.223816.5.5c0 .276123-.223877.5-.5.5zm2 2.5c0 .930176-.638184 1.71436-1.5 1.93652v-3.87305c.861816.222168 1.5 1.00635 1.5 1.93652zm-.936523-3.5c.222168-.861816 1.00635-1.5 1.93652-1.5.930176 0 1.71436.638184 1.93652 1.5h-3.87305z transform=translate(2 2) data-original=#000000 class=active-path data-old_color=#000000 fill=#2184C4/></g> </svg>''';
  DrawableRoot svgRoot;
  UI.Image image;
  @override
  void initState() {
    super.initState();
    getLeftIcon();
  }
    // this is for the Ui.Image
  Future<UI.Image> loadUiImage(String imageAssetPath) async {
    final ByteData data = await rootBundle.load(imageAssetPath);

    final Completer<UI.Image> completer = Completer();
    UI.decodeImageFromList(Uint8List.view(data.buffer), (UI.Image img) {
      return completer.complete(img);
    });
    return completer.future;
  }
   //Please Ignore
  /* Future<File> getImageFileFromAssets(String path) async {
    final byteData = await rootBundle.load('assets/$path');

    final file = File('${(await getTemporaryDirectory()).path}/$path');
    await file.writeAsBytes(byteData.buffer
        .asUint8List(byteData.offsetInBytes, byteData.lengthInBytes));

    return file;
  } */

  getLeftIcon() async {
    /*  svgRoot= await svg.fromSvgString(rawLeftSvg, rawLeftSvg); */
    //File file = await getImageFileFromAssets('icon.png');

    image = await loadUiImage('assets/snowflake.png');
    svgRoot = await svg.fromSvgString(rawLeftSvg, rawLeftSvg);
    print('sucess');
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.transparent,
      body: SliderLeftPaint(
        leftsvgIcon: svgRoot,
        leftIcon: image,
        leftInitial: 0,
        leftEnd: leftEnd,
        onSelectionChange: (int left) {
          setState(() {
            leftEnd = left;
          });
        },
        child: Center(
            child: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Padding(
              padding: const EdgeInsets.only(right: 10),
              child: Text(
                '$leftEnd\u00B0',
              ),
            ),
          ],
        )),
      ),
    );
  }
}

class SliderLeftPaint extends StatefulWidget {
  final DrawableRoot leftsvgIcon;
  final UI.Image leftIcon;
  final int leftInitial;
  final int leftEnd;

  final Function onSelectionChange;
  final Widget child;

  const SliderLeftPaint(
      {Key key,
      this.leftsvgIcon,
      @required this.leftIcon,
      @required this.leftInitial,
      @required this.leftEnd,
      @required this.onSelectionChange,
      this.child})
      : super(key: key);

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

class _SliderLeftPaintState extends State<SliderLeftPaint> {
  bool _isInitLeftHandlerSelected = false;

  CustomLeftPainter customLeftPainter;

  /// start angle in radians where we need to locate the initial left handler
  double _leftStartAngle;

  /// end angle in radians where we need to locate the end left  handler
  double _leftEndAngle;

  /// the absolute angle in radians representing the selection
  double _leftSweepAngle;

// we need to update this widget both with gesture detector but
  // also when the parent widget rebuilds itself
  @override
  void didUpdateWidget(SliderLeftPaint oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.leftInitial != widget.leftInitial ||
        oldWidget.leftEnd != widget.leftEnd) {
      _calculatePercentage();
    }
  }

  void _calculatePercentage() {
    if (_isInitLeftHandlerSelected) {
      // This is for left inti and end percentage and the sweep Angle
      // TODO That it should be in a limit of half circle

      double initLeftPercentage = valueToPercentage(widget.leftInitial, 100);
      print('This is initial Left Percentge $initLeftPercentage');
      double endLeftPercentage = valueToPercentage(widget.leftEnd, 100);
      print('This is  End  Left Percentage $endLeftPercentage');

      double sweepLeftAngle =
          getSweepAngle(initLeftPercentage, endLeftPercentage);
      print('This is the sweep angle for the left hand side $sweepLeftAngle');
      _leftStartAngle = percentageToRadians(initLeftPercentage);
      print('This is the Left Start Angle $_leftStartAngle');
      _leftEndAngle = percentageToRadians(endLeftPercentage);
      print('This is the Left End Angle $_leftEndAngle');

      _leftSweepAngle = percentageToRadians(sweepLeftAngle.abs());
      print('This is the Left Sweep Angle $_leftSweepAngle');
    }

    customLeftPainter = CustomLeftPainter(
      leftdrawablesvgIcon: widget.leftsvgIcon,
      leftSvgIcon: widget.leftIcon,
      startLeftAngle: _leftStartAngle,
      endLeftAngle: _leftEndAngle,
      leftSweepAngle: _leftSweepAngle,
      selectionLeftColor: Colors.blueAccent,
    );
  }

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    _calculatePaintData();
  }

  void _calculatePaintData() {
    // This is for the right init and end percentage and the sweepangle

    // This is for left inti and end percentage and the sweep Angle
    double initLeftPercentage = valueToPercentage(widget.leftInitial, 100);
    print('This is initial Left Percentge $initLeftPercentage');
    double endLeftPercentage = valueToPercentage(widget.leftEnd, 100);
    print('This is  End  Left Percentage $endLeftPercentage');

    double sweepLeftAngle =
        getSweepAngle(initLeftPercentage, endLeftPercentage);
    print('This is the sweep angle for the left hand side $sweepLeftAngle');
    _leftStartAngle = percentageToRadians(initLeftPercentage);
    print('This is the Left Start Angle $_leftStartAngle');
    _leftEndAngle = percentageToRadians(endLeftPercentage);
    print('This is the Left End Angle $_leftEndAngle');

    _leftSweepAngle = percentageToRadians(sweepLeftAngle.abs());
    print('This is the Left Sweep Angle $_leftSweepAngle');

    customLeftPainter = CustomLeftPainter(
      leftdrawablesvgIcon: widget.leftsvgIcon,
      leftSvgIcon: widget.leftIcon,
      startLeftAngle: _leftStartAngle,
      endLeftAngle: _leftEndAngle,
      leftSweepAngle: _leftSweepAngle,
      selectionLeftColor: Colors.blue,
    );
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onPanUpdate: _onPanUpdate,
      onPanEnd: _onPanEnd,
      onPanDown: _onPanDown,
      child: CustomPaint(
        painter: BasePainter(
          baseColor: Color(0XFF5E5C5D),
        ),
        foregroundPainter: customLeftPainter,
        child: Padding(
          padding: const EdgeInsets.all(12.0),
          child: widget.child,
        ),
      ),
    );
  }

  _onPanUpdate(DragUpdateDetails details) {
    if (!_isInitLeftHandlerSelected) {
      return;
    }
    if (customLeftPainter.leftcenter == null) {
      return;
    }

    RenderBox renderBox = context.findRenderObject();
    var position = renderBox.globalToLocal(details.globalPosition);
    var leftAngle;

    var leftPercent;

    var newLeftValue;

    if (_leftSweepAngle >= 0) {
      leftAngle = coordinatesToRadians(customLeftPainter.leftcenter, position);
      leftPercent = radianstoPercentageLeft(leftAngle);
      newLeftValue = percentageToValue(leftPercent, 100);
      if (_isInitLeftHandlerSelected) {
        widget.onSelectionChange(newLeftValue);
      }
    }
  }

  _onPanDown(DragDownDetails details) {
    if (customLeftPainter == null) {
      return;
    }
    RenderBox renderBox = context.findRenderObject();
    var position = renderBox.globalToLocal(details.globalPosition);
    if (position != null) {
      _isInitLeftHandlerSelected = isPointInsideCircle(
          position, customLeftPainter.leftInitHandler, 12.0);
    }
  }

  _onPanEnd(_) {
    _isInitLeftHandlerSelected = false;
  }
}

Pintor izquierdo

import 'dart:math';
import 'dart:ui' as UI;

import 'package:animations_sample/utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';

class CustomLeftPainter extends CustomPainter {
  DrawableRoot leftdrawablesvgIcon;
  UI.Image leftSvgIcon;
  double startLeftAngle;
  double endLeftAngle;
  double leftSweepAngle;
  Color selectionLeftColor;
  Size actuallsize = Size(30, 30);

  Offset leftcenter;

  double leftradius;

  Offset leftInitHandler;

  CustomLeftPainter({
    @required this.leftdrawablesvgIcon,
    @required this.leftSvgIcon,
    @required this.startLeftAngle,
    @required this.endLeftAngle,
    @required this.leftSweepAngle,
    @required this.selectionLeftColor,
  });

  @override
  void paint(Canvas canvas, Size size) {
    //This was the problem when all the both left and right angles are 0 then it will return with no points
    /* if (startLeftAngle == 0.0 &&
        endLeftAngle == 0.0 &&
        startRightAngle == 0.0 &&
        endRightAngle == 0.0) return;
 */

    Paint leftprogress = _getPaint(color: selectionLeftColor, width: 20);

    leftcenter = Offset(size.width / 2, size.height / 2);

    leftradius = min(size.width / 2, size.height / 2);

    canvas.drawArc(Rect.fromCircle(center: leftcenter, radius: leftradius),
        pi / 2 + startLeftAngle, leftSweepAngle, false, leftprogress);

    Paint lefthandler =
        _getPaint(color: Colors.white, style: PaintingStyle.fill);
    Paint lefthandlerOutter = _getPaint(color: selectionLeftColor);

    leftInitHandler =
        radiansToCoordinates(leftcenter, pi / 2 + endLeftAngle, leftradius);
    canvas.drawCircle(leftInitHandler, 8.0, lefthandler);
    canvas.drawCircle(leftInitHandler, 12.0, lefthandlerOutter);



    // To draw image but problem is it has scalling problem

    /* canvas.drawImage(
        leftSvgIcon,
        Offset(leftInitHandler.dx - 12, leftInitHandler.dy - 12),
        lefthandlerOutter); */
    //


    leftdrawablesvgIcon.scaleCanvasToViewBox(canvas, size);

    leftdrawablesvgIcon.clipCanvasToViewBox(canvas);

       //This is the add part for the edit
    Rect myRect = Offset(leftInitHandler.dx,leftInitHandler.dy) & const Size(50.0, 50.0);

    leftdrawablesvgIcon.draw(
        canvas,myRect);
  }

  Paint _getPaint({@required Color color, double width, PaintingStyle style}) =>
      Paint()
        ..color = color
        ..strokeCap = StrokeCap.square
        ..style = style ?? PaintingStyle.stroke
        ..strokeWidth = width ?? 8.0;

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
  }
}


utils archivan las conversiones.

import 'dart:math';
import 'dart:ui';

double percentageToRadians(double percentage) => ((pi * percentage) / 100);

double radiansToPercentage(double radians) {
  var normalized = radians < 0 ? -radians : pi - radians;
  var percentage = ((100 * normalized) / (pi));
  // TODO we have an inconsistency of pi/2 in terms of percentage and radians
  return (percentage + 50) % 100;
}

double radianstoPercentageLeft(double radians) {
  var normalized = radians < 0 ? -radians : pi - radians;
  print('************This is left normalized $normalized');
  var percentage = ((100 * normalized) / (pi));
  return (percentage - 50) % 100;
}

double coordinatesToRadians(Offset center, Offset coords) {
  var a = coords.dx - center.dx;
  var b = center.dy - coords.dy;
  return atan2(b, a);
}

Offset radiansToCoordinates(Offset center, double radians, double radius) {
  var dx = center.dx + radius * cos(radians);
  var dy = center.dy + radius * sin(radians);
  return Offset(dx, dy);
}

double valueToPercentage(int time, int intervals) => (time / intervals) * 100;

int percentageToValue(double percentage, int intervals) =>
    ((percentage * intervals) / 100).round();

bool isPointInsideCircle(Offset point, Offset center, double rradius) {
  if(center ==Offset(0,0))
  {
    return false;
  }
  var radius = rradius * 1.2;
  return point.dx < (center.dx + radius) &&
      point.dx > (center.dx - radius) &&
      point.dy < (center.dy + radius) &&
      point.dy > (center.dy - radius);
}

bool isPointAlongCircle(Offset point, Offset center, double radius) {
  // distance is root(sqr(x2 - x1) + sqr(y2 - y1))
  // i.e., (7,8) and (3,2) -> 7.21
  var d1 = pow(point.dx - center.dx, 2);
  var d2 = pow(point.dy - center.dy, 2);
  var distance = sqrt(d1 + d2);
  return (distance - radius).abs() < 10;
}

double getSweepAngle(double init, double end) {
  if (end > init) {
    return end - init;
  }
  if(end == init)
  {
    return 0;
  }
  return (100 - init + end).abs();
}

List<Offset> getSectionsCoordinatesInCircle(
    Offset center, double radius, int sections) {
  var intervalAngle = (pi * 2) / sections;
  return List<int>.generate(sections, (int index) => index).map((i) {
    var radians = (pi / 2) + (intervalAngle * i);
    return radiansToCoordinates(center, radians, radius);
  }).toList();
}

bool isAngleInsideRadiansSelection(double angle, double start, double sweep) {
  var normalized = angle > pi / 2 ? 5 * pi / 2 - angle : pi / 2 - angle;
  var end = (start + sweep) % (2 * pi);
  return end > start
      ? normalized > start && normalized < end
      : normalized > start || normalized < end;
}

// this is not 100% accurate but it works
// we just want to see if a value changed drastically its value
bool radiansWasModuloed(double current, double previous) {
  return (previous - current).abs() > (3 * pi / 2);
}

enter

Me gustaría añadir este pequeño icono de svg en la perilla

<?xml version=1.0?>
<svg xmlns=http://www.w3.org/2000/svg height=512px viewBox=0 0 16 16 width=512px><g><path d=m8 0c-4.41113 0-8 3.58887-8 8s3.58887 8 8 8 8-3.58887 8-8-3.58887-8-8-8zm0 15c-3.85986 0-7-3.14014-7-7s3.14014-7 7-7 7 3.14014 7 7-3.14014 7-7 7z data-original=#000000 class=active-path data-old_color=#000000 fill=#2184C4/><path d=m9 3c-1.04364 0-1.9624.536926-2.5 1.34772v-3.84772c0-.276367-.223633-.5-.5-.5-1.6543 0-3 1.3457-3 3 0 1.04364.536926 1.9624 1.34772 2.5h-3.84772c-.276367 0-.5.223633-.5.5 0 1.6543 1.3457 3 3 3 1.04364 0 1.9624-.536926 2.5-1.34772v3.84772c0 .276367.223633.5.5.5 1.6543 0 3-1.3457 3-3 0-1.04364-.536926-1.9624-1.34772-2.5h3.84772c.276367 0 .5-.223633.5-.5 0-1.6543-1.3457-3-3-3zm-6 5c-.930176 0-1.71436-.638184-1.93652-1.5h3.87305c-.222168.861816-1.00635 1.5-1.93652 1.5zm1-5c0-.930176.638184-1.71436 1.5-1.93652v3.87305c-.861816-.222168-1.5-1.00635-1.5-1.93652zm2 3.5c-.276123 0-.5-.223877-.5-.5 0-.276184.223877-.5.5-.5s.5.223816.5.5c0 .276123-.223877.5-.5.5zm2 2.5c0 .930176-.638184 1.71436-1.5 1.93652v-3.87305c.861816.222168 1.5 1.00635 1.5 1.93652zm-.936523-3.5c.222168-.861816 1.00635-1.5 1.93652-1.5.930176 0 1.71436.638184 1.93652 1.5h-3.87305z transform=translate(2 2) data-original=#000000 class=active-path data-old_color=#000000 fill=#2184C4/></g> </svg>

Publicado el 25/05/2020 a las 13:31
fuente por usuario
En otros idiomas...                            


1 respuestas

votos
0

Utiliza el paquete flutter_svg, que tiene un ejemplo de cómo dibujar un SVG en un lienzo, que es básicamente lo que quieres conseguir:

import 'package:flutter_svg/flutter_svg.dart';
final String rawSvg = '''<svg viewBox="...">...</svg>''';
final DrawableRoot svgRoot = await svg.fromSvgString(rawSvg, rawSvg);

// If you only want the final Picture output, just use
final Picture picture = svgRoot.toPicture();

// Otherwise, if you want to draw it to a canvas:
// Optional, but probably normally desirable: scale the canvas dimensions to
// the SVG's viewbox
svgRoot.scaleCanvasToViewBox(canvas);

// Optional, but probably normally desireable: ensure the SVG isn't rendered
// outside of the viewbox bounds
svgRoot.clipCanvasToViewBox(canvas);
svgRoot.draw(canvas, size); // <---------- I think this is the one that you actually want

También puede cargar el SVG como un activo de sus archivos. Tenga en cuenta que un ejemplo más simple en su pregunta podría llevar a mejores respuestas.

Respondida el 31/05/2020 a las 05:31
fuente por usuario

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more