nateshmbhat / touchable

The only flutter library to add gestures and animations to custom shapes you draw on your canvas.
https://pub.dev/packages/touchable
Mozilla Public License 2.0
233 stars 80 forks source link

How can I force a repaint on click; Change color on click event #8

Closed S-Man42 closed 4 years ago

S-Man42 commented 4 years ago

Hi,

I am trying to use this library to create this behaviour:

I have a filled Path. When I tap on the path it should turn into red. So using this, I can catch the onTapDownevent:

myCanvas.drawPath(path, paint, onTapDown: (tapDetail) {
  print('Tapped');
});

What do I have to do to force the repaint with a new color?

Thanks in advance!

issue-label-bot[bot] commented 4 years ago

Issue-Label Bot is automatically applying the label question to this issue, with a confidence of 0.87. Please mark this comment with :thumbsup: or :thumbsdown: to give our bot feedback!

Links: app homepage, dashboard and code for this bot.

nateshmbhat commented 4 years ago

you just need to do some simple state management here using either :

Here's a small example : 

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

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

class Screen3 extends StatefulWidget {
  @override
  _Screen3State createState() => _Screen3State();
}

class _Screen3State extends State<Screen3> with SingleTickerProviderStateMixin {
  Color color = Colors.orange;

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Column(
        mainAxisSize: MainAxisSize.max,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: <Widget>[
          Flexible(
            child: AnimatedContainer(
                duration: Duration(seconds: 1),
                color: color,
                width: 400,
                height: 900,
                child: CanvasTouchDetector(
                  builder: (context) {
                    return CustomPaint(
                      painter: MyPainter(context, (String circleColor) {
                        setState(() {
                          switch (circleColor) {
                            case 'orange':
                              color = Colors.orange;
                              break;
                            case 'pink':
                              color = Colors.pinkAccent;
                              break;
                            case 'green':
                              color = Colors.green;
                              break;
                            case 'black':
                              color = Colors.black;
                              break;
                            case 'purple':
                              color = Colors.purple;
                              break;
                            case 'grey':
                              color = Colors.grey;
                              break;
                            default:
                              color = Colors.blue;
                          }
                        });
                      }),
                    );
                  },
                )),
          ),
        ],
      ),
    );
  }
}

class MyPainter extends CustomPainter {
  Function(String) setState;
  final BuildContext context;

  MyPainter(this.context, this.setState);

  @override
  void paint(Canvas _canvas, Size size) {
    TouchyCanvas canvas = TouchyCanvas(context, _canvas);

    canvas.drawRect(Rect.fromLTWH(0, 0, 100, 300),Paint()..color=Colors.blue,onTapDown: (_){
      setState('blue');
    });

  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return false;
  }
}
S-Man42 commented 4 years ago

Thank you for your response. However, either I don't understand the example completely or I need something different:

Your example keeps a global color variable which defines the container background. Well, in my use case I have several paths which should be toggles on/off separately. So when I tap onto path A1, it should toggle from red to grey. Toggle twice back to red again. Same for path A2. So I have a map which keeps the toggles states as bool:

var segments = {'a1: false, 'a2': true}

How can I force the Canvas to be repaint using the current map values like:

var paintA1 = Paint();
paint.color = segments['a1'] ? Colors.red : Colors.grey;

Heres the entire code:

class SegmentDisplay extends StatefulWidget {
  @override
  SegmentDisplayState createState() => SegmentDisplayState();
}

class SegmentDisplayState extends State<SegmentDisplay> {
  Color color = Colors.black54;

  var _segments = <String, bool>{'a1': false, 'a2': false};

  @override
  Widget build(BuildContext context) {
    return Column(
        children: <Widget>[
          Container(
            constraints: BoxConstraints(maxHeight: 200),
            width: double.infinity,
            height: double.infinity,
            child: AnimatedContainer(
                duration: Duration(seconds: 0),
                color: color,
                child: CanvasTouchDetector(
                  builder: (context) {
                    return CustomPaint(
                      painter: SegmentPainter(context, _segments, (key, value) {
                        setState(() {
                          _segments[key] = value;
                        });
                      })
                    );
                  },
                )),
          ),
        ],
    );
  }
}

class SegmentPainter extends CustomPainter {
  final Function(String, bool) setSegmentState;
  final Map<String, bool> segments;
  final BuildContext context;

  SegmentPainter(this.context, this.segments, this.setSegmentState); // context from CanvasTouchDetector

  @override
  void paint(Canvas canvas, Size size) {
   var _touchCanvas = TouchyCanvas(context, canvas);

    var paint = Paint();
    paint.color = segments['a1'] ? Colors.red : Colors.grey;  // Color first Path
    paint.strokeWidth = 0;
    paint.style = PaintingStyle.fill;

    var pathA1 = Path();
    pathA1.moveTo(size.width / 99 * 1, 0);
    pathA1.lineTo(size.width / 99 * 48, 0);
    pathA1.lineTo(size.width / 99 * 48, size.height / 99 * 4);
    pathA1.lineTo(size.width / 99 * 44, size.height / 99 * 8);
    pathA1.lineTo(size.width / 99 * 9, size.height / 99 * 8);
    pathA1.close();

    _touchCanvas.drawPath(pathA1, paint, onTapDown: (tapDetail) {
      setSegmentState('a1', !segments['a1']);
    });

    paint.color = segments['a2'] ? Colors.red : Colors.grey; // Color second Path

    var pathA2 = Path();
    pathA2.moveTo(size.width / 99 * 50, 0);
    pathA2.lineTo(size.width / 99 * 97, 0);
    pathA2.lineTo(size.width / 99 * 89, size.height / 99 * 8);
    pathA2.lineTo(size.width / 99 * 54, size.height / 99 * 8);
    pathA2.lineTo(size.width / 99 * 50, size.height / 99 * 4);
    pathA2.close();

    _touchCanvas.drawPath(pathA2, paint, onTapDown: (tapDetail) {
      setSegmentState('a2', !segments['a2']);
    });
 }

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