Büşra Yamaner
Büşra Yamaner

Reputation: 11

Flutter add Image Inside Canvas Circle

I put animated widgets that move from right to left on the home screen of my application. Here I drew circles using Canvas. I want to place images related to imageUrl inside these circles. Here, when I tried to place it with drawImage, the photos were not positioned exactly on top of the circles. Can you help me with this?

                          SizedBox(
                            height: Get.height / 2 + 20,
                            width: MediaQuery.of(context).size.width,
                            child: const WidgetSlider(children: [
                              Circle(
                                  center: {"x": 40, "y": 100},
                                  radius: 70,
                                  color: Colors.green),
                              Circle(
                                  center: {"x": -90, "y": 280},
                                  radius: 65,
                                  color: Colors.grey),
                              Circle(
                                  center: {"x": 3, "y": 55},
                                  radius: 55,
                                  color: Colors.lime),
                              Circle(
                                  center: {"x": -85, "y": 220},
                                  radius: 80,
                                  color: Colors.white),
                              Circle(
                                  center: {"x": 0, "y": 130},
                                  radius: 75,
                                  color: Colors.black),
                              Circle(
                                  center: {"x": 10, "y": 260},
                                  radius: 75,
                                  color: Colors.pink),
                              Circle(
                                  center: {"x": -5, "y": 55},
                                  radius: 55,
                                  color: Colors.amber),
                              Circle(
                                  center: {"x": -25, "y": 180},
                                  radius: 55,
                                  color: Colors.red),
                            ]),
                          ),

This is the animation I gave my widgets to slide from right to left.

    import 'dart:async';
    import 'package:flutter/material.dart';
    
    class WidgetSlider extends StatefulWidget {
      /// To pass children to this widget.
      final List<Widget> children;
    
      /// Spacing between each child.
      /// Default spacing is 10.0
      final double? spacing;
    
      /// Sliding speed applied to widget every 100ms, for smooth transition lower values are recommended.
      /// Default offset x = 10.0
      final double? slidingSpeed;
    
      /// Sliding direction.
      /// Default is Axis.horizontal
      final Axis? slideAxis;
    
      /// Sliding child count
      /// Default is 100m
      final int? slideCount;
    
      const WidgetSlider({
        Key? key,
        required this.children,
        this.spacing,
        this.slidingSpeed,
        this.slideAxis,
        this.slideCount,
      }) : super(key: key);
    
      @override
      State<WidgetSlider> createState() => _WidgetSliderState();
    }
    
    class _WidgetSliderState extends State<WidgetSlider> {
      late ScrollController _sliderController;
      late Timer _sliderTimer;
      final Duration _updateDuration = const Duration(milliseconds: 100);
      final int _defaultSlideCount = 1000000000;
    
      @override
      void initState() {
        assert(widget.children.length > 1);
        _sliderController = ScrollController(initialScrollOffset: 0);
        _sliderTimer = _assignTimer();
        super.initState();
      }
    
      @override
      void dispose() {
        _sliderController.dispose();
        _sliderTimer.cancel();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return AbsorbPointer(
          absorbing: true,
          child: ListView.separated(
            controller: _sliderController,
            shrinkWrap: true,
            physics: null,
            itemCount: widget.slideCount ?? _defaultSlideCount,
            cacheExtent: MediaQuery.of(context).size.width,
            scrollDirection: widget.slideAxis ?? Axis.horizontal,
            itemBuilder: (context, index) {
              return widget.children[index % widget.children.length];
            },
            separatorBuilder: (context, index) {
              if (widget.slideAxis == null) {
                return SizedBox(width: widget.spacing ?? 10);
              }
              return widget.slideAxis == Axis.horizontal
                  ? SizedBox(width: widget.spacing ?? 10)
                  : SizedBox(height: widget.spacing ?? 10);
            },
          ),
        );
      }
    
      Timer _assignTimer() {
        return Timer.periodic(
          _updateDuration,
          (_) {
            _sliderController.animateTo(
              _sliderController.offset + (widget.slidingSpeed ?? 10),
              duration: _updateDuration,
              curve: Curves.linear,
            );
          },
        );
      }
    }

This is my Circle Class.

 class Circle extends StatefulWidget {
          final Map<String, double> center;
          final double radius;
          final Color color;
        
          const Circle(
              {Key? key,
              required this.center,
              required this.radius,
              required this.color})
              : super(key: key);
          @override
          _CircleState createState() => _CircleState();
        }
        
        class _CircleState extends State<Circle> with SingleTickerProviderStateMixin {
          late AnimationController _controller;
        
          @override
          void initState() {
            super.initState();
            _controller = AnimationController(vsync: this);
          }
        
          @override
          void dispose() {
            super.dispose();
            _controller.dispose();
          }
        
          @override
          Widget build(BuildContext context) {
            return CustomPaint(
                size: Size(MediaQuery.of(context).size.width / 5,
                    MediaQuery.of(context).size.height),
                painter: DrawCircle(
                  center: widget.center,
                  radius: widget.radius,
                  color: Colors.white,
                ));
          }
        }

My CustomPainter class is as follows.

class DrawCircle extends CustomPainter {
  Map<String, double> center;
  double radius;
  Color color;
  DrawCircle({
    Key? key,
    required this.center,
    required this.radius,
    required this.color,
  });

  @override
  void paint(Canvas canvas, Size size) {
    Paint brush = Paint()
      ..color = color
      ..strokeCap = StrokeCap.round
      ..style = PaintingStyle.fill
      ..strokeWidth = 30;
    canvas.drawCircle(Offset(center["x"]!, center["y"]!), radius, brush);
  }

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

This is the shape I want to see as output.

This is the result I got. I couldn't add the images

Upvotes: 1

Views: 562

Answers (1)

Hichem Benali
Hichem Benali

Reputation: 411

I would recommend using CircleAvatar instead of CustomPaint.

      @override
      Widget build(BuildContext context) {
        return CircleAvatar(
            radius: Size(MediaQuery.of(context).size.width / 5,
                MediaQuery.of(context).size.height),
            backgroundColor: white,
            foregroundImage: NetworkImage(imageUrl)
            );
      }

This should solve your issue.

Upvotes: 0

Related Questions