Adicionando o ícone SVG no controle deslizante personalizado usando o pintor personalizado

votos
3

Estou implementando o deslizador personalizado, onde completei a detecção de gestos no deslizador , agora quero adicionar o ícone SVG no botão para arrastar, não consigo encontrar nenhum recurso. Só quero adicionar o SVG a qualquer ideia de como implementá-lo. Coloquei o meu código e avisem-me de qualquer sugestão que vocês tenham.

Arquivo ui principal

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(),
          ),
        ),
      ),
    );
  }
}

Arquivo deslizante 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 esquerdo

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 para conversões.

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

Gostaria de adicionar este pequeno ícone svg no botão

<?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 25/05/2020 em 13:31
fonte usuário
Em outras línguas...                            


1 respostas

votos
0

Use o pacote flutter_svg, ele tem um exemplo de como desenhar um SVG para uma tela, que é basicamente o que você quer alcançar:

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

Você também pode carregar o SVG como um ativo a partir de seus arquivos. Tenha em mente que um exemplo mais simples na sua pergunta pode levar a melhores respostas.

Respondeu 31/05/2020 em 05:31
fonte usuário

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