时钟小部件在拍打颤动时未更新其状态

时间:2020-05-05 14:54:00

标签: flutter

1 [已附加图片网址] 2

int clockHours = 1; int clockMinutes = 1;

void updateHours(){

clockHours = clockHours +1;

}

void updateMinutess(){ clockMinutes = clockMinutes +1;

 }

1 个答案:

答案 0 :(得分:0)

您可以在下面复制粘贴运行完整代码
完整的代码已包含FlutterAnalogClock的更新源代码
FlutterAnalogClock的源代码需要添加didUpdateWidget

class _FlutterAnalogClockState extends State<FlutterAnalogClock> {
...
@override
  void didUpdateWidget(FlutterAnalogClock oldWidget) {
    super.didUpdateWidget(oldWidget);
    if(widget.dateTime != oldWidget.dateTime) {
      _dateTime = widget.dateTime;
    }
  }

使用它的代码段

 ...
FlutterAnalogClock(
              showBorder: true,
              showTicks: true,
              showMinuteHand: true,
              showSecondHand: false,
              showNumber: true,
              borderWidth: 10.0,
              hourNumberScale: 1,
              isLive: false,
              width: 200.0,
              height: 200.0,
              decoration: const BoxDecoration(),
              dateTime: DateTime(2019, 1, 1, clockHours, clockMinutes, 15),
            ),
RaisedButton(
    onPressed: () {
      clockHours = clockHours + 1;
      setState(() {

      });
    },
    child: Text("+ Hour"))

工作演示

enter image description here

完整代码

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter/cupertino.dart';
import 'dart:math';
import 'dart:ui';

class FlutterAnalogClockPainter extends CustomPainter {
  static const List<String> defaultHourNumbers = [
    '1',
    '2',
    '3',
    '4',
    '5',
    '6',
    '7',
    '8',
    '9',
    '10',
    '11',
    '12'
  ];
  final DateTime _datetime;
  final Color dialPlateColor;
  final Color hourHandColor;
  final Color minuteHandColor;
  final Color secondHandColor;
  final Color numberColor;
  final Color borderColor;
  final Color tickColor;
  final Color centerPointColor;
  final bool showBorder;
  final bool showTicks;
  final bool showMinuteHand;
  final bool showSecondHand;
  final bool showNumber;
  final double hourNumberScale;
  final List<String> hourNumbers;
  double _borderWidth;
  final TextPainter _hourTextPainter = TextPainter(
    textAlign: TextAlign.center,
    textDirection: TextDirection.ltr,
  );

  FlutterAnalogClockPainter(
    this._datetime, {
    this.dialPlateColor = Colors.transparent,
    this.hourHandColor = Colors.black,
    this.minuteHandColor = Colors.black,
    this.secondHandColor = Colors.black,
    this.numberColor = Colors.black,
    this.borderColor = Colors.black,
    this.tickColor = Colors.black,
    this.centerPointColor = Colors.black,
    this.showBorder = true,
    this.showTicks = true,
    this.showMinuteHand = true,
    this.showSecondHand = true,
    this.showNumber = true,
    this.hourNumberScale = 1.0,
    this.hourNumbers = defaultHourNumbers,
    double borderWidth,
  })  : assert(hourNumbers == null || hourNumbers.length == 12),
        _borderWidth = borderWidth;

  @override
  void paint(Canvas canvas, Size size) {
    //clock radius
    final radius = min(size.width, size.height) / 2;
    //clock circumference
    final double borderWidth =
        showBorder ? (_borderWidth ?? radius / 20.0) : 0.0;
    final double circumference = 2 * (radius - borderWidth) * pi;

    canvas.translate(size.width / 2, size.height / 2);

    canvas.drawCircle(
        Offset(0, 0),
        radius,
        Paint()
          ..style = PaintingStyle.fill
          ..color = dialPlateColor);

    // border style
    if (showBorder && borderWidth > 0) {
      Paint borderPaint = Paint()
        ..color = this.borderColor
        ..style = PaintingStyle.stroke
        ..strokeWidth = borderWidth
        ..isAntiAlias = true;
      canvas.drawCircle(Offset(0, 0), radius - borderWidth / 2, borderPaint);
    }

    // setup tick
    final double tickWidth = circumference / 200;
    final double bigTickWidth = circumference / 120;
    final double tickRadius = (radius - borderWidth - bigTickWidth);
    if (showTicks) _paintTicks(canvas, tickRadius, tickWidth, bigTickWidth);

    // setup numbers
    final double numberRadius = tickRadius - bigTickWidth * 3;
    double hourTextHeight = (radius - borderWidth) / 40 * 8 * hourNumberScale;

    if (showNumber) {
      hourTextHeight = _paintHourText(canvas, numberRadius, hourTextHeight);
    }

    _paintHourHand(
        canvas, numberRadius - hourTextHeight, (radius - borderWidth) / 20);

    if (showMinuteHand) {
      _paintMinuteHand(canvas, numberRadius, (radius - borderWidth) / 40);
    }
    if (showSecondHand) {
      _paintSecondHand(canvas, numberRadius + hourTextHeight / 2,
          (radius - borderWidth) / 80);
    }

    //draw center point
    Paint centerPointPaint = Paint()
      ..strokeWidth = ((radius - borderWidth) / 10)
      ..strokeCap = StrokeCap.round
      ..color = this.centerPointColor;
    canvas.drawPoints(PointMode.points, [Offset(0, 0)], centerPointPaint);
  }

  /// draw ticks
  void _paintTicks(
      Canvas canvas, double radius, double tickWidth, double bigTickWidth) {
    List<Offset> ticks = [];
    List<Offset> bigTicks = [];
    for (var i = 0; i < 60; i++) {
      double _angle = i * 6.0;
      if (i % 5 != 0) {
        double x = cos(getRadians(_angle)) * radius;
        double y = sin(getRadians(_angle)) * radius;
        ticks.add(Offset(x, y));
      } else {
        double x = cos(getRadians(_angle)) * radius;
        double y = sin(getRadians(_angle)) * radius;
        bigTicks.add(Offset(x, y));
      }
    }
    Paint tickPaint = Paint()
      ..color = this.tickColor
      ..strokeWidth = tickWidth
      ..strokeCap = StrokeCap.round;
    canvas.drawPoints(PointMode.points, ticks, tickPaint);

    Paint bigTickPaint = Paint()
      ..color = this.tickColor
      ..strokeWidth = bigTickWidth
      ..strokeCap = StrokeCap.round;
    canvas.drawPoints(PointMode.points, bigTicks, bigTickPaint);
  }

  /// draw number(1 - 12)
  double _paintHourText(Canvas canvas, double radius, double fontSize) {
    double maxTextHeight = 0;
    for (var i = 0; i < 12; i++) {
      double _angle = i * 30.0;
      canvas.save();
      double hourNumberX = cos(getRadians(_angle)) * radius;
      double hourNumberY = sin(getRadians(_angle)) * radius;
      canvas.translate(hourNumberX, hourNumberY);
      int intHour = i + 3;
      if (intHour > 12) intHour = intHour - 12;

      String hourText = hourNumbers[intHour - 1];
      _hourTextPainter.text = TextSpan(
        text: hourText,
        style: TextStyle(fontSize: fontSize, color: this.numberColor),
      );
      _hourTextPainter.layout();
      if (_hourTextPainter.height > maxTextHeight)
        maxTextHeight = _hourTextPainter.height;
      _hourTextPainter.paint(canvas,
          Offset(-_hourTextPainter.width / 2, -_hourTextPainter.height / 2));
      canvas.restore();
    }
    return maxTextHeight;
  }

  /// draw hour hand
  void _paintHourHand(Canvas canvas, double radius, double strokeWidth) {
    double angle = _datetime.hour % 12 + _datetime.minute / 60.0 - 3;
    Offset handOffset = Offset(cos(getRadians(angle * 30)) * radius,
        sin(getRadians(angle * 30)) * radius);
    final hourHandPaint = Paint()
      ..color = this.hourHandColor
      ..strokeWidth = strokeWidth;
    canvas.drawLine(Offset(0, 0), handOffset, hourHandPaint);
  }

  /// draw minute hand
  void _paintMinuteHand(Canvas canvas, double radius, double strokeWidth) {
    double angle = _datetime.minute - 15.0;
    Offset handOffset = Offset(cos(getRadians(angle * 6.0)) * radius,
        sin(getRadians(angle * 6.0)) * radius);
    final hourHandPaint = Paint()
      ..color = this.minuteHandColor
      ..strokeWidth = strokeWidth;
    canvas.drawLine(Offset(0, 0), handOffset, hourHandPaint);
  }

  /// draw second hand
  void _paintSecondHand(Canvas canvas, double radius, double strokeWidth) {
    double angle = _datetime.second - 15.0;
    Offset handOffset = Offset(cos(getRadians(angle * 6.0)) * radius,
        sin(getRadians(angle * 6.0)) * radius);
    final hourHandPaint = Paint()
      ..color = this.secondHandColor
      ..strokeWidth = strokeWidth;
    canvas.drawLine(Offset(0, 0), handOffset, hourHandPaint);
  }

  @override
  bool shouldRepaint(FlutterAnalogClockPainter oldDelegate) {
    return _datetime != oldDelegate._datetime ||
        dialPlateColor != oldDelegate.dialPlateColor ||
        hourHandColor != oldDelegate.hourHandColor ||
        minuteHandColor != oldDelegate.minuteHandColor ||
        secondHandColor != oldDelegate.secondHandColor ||
        tickColor != oldDelegate.tickColor ||
        numberColor != oldDelegate.numberColor ||
        borderColor != oldDelegate.borderColor ||
        centerPointColor != oldDelegate.centerPointColor ||
        showBorder != oldDelegate.showBorder ||
        showTicks != oldDelegate.showTicks ||
        showMinuteHand != oldDelegate.showMinuteHand ||
        showSecondHand != oldDelegate.showSecondHand ||
        showNumber != oldDelegate.showNumber ||
        hourNumbers != oldDelegate.hourNumbers ||
        _borderWidth != oldDelegate._borderWidth ||
        hourNumberScale != oldDelegate.hourNumberScale;
  }

  static double getRadians(double angle) {
    return angle * pi / 180;
  }
}

/// A analog clock.
class FlutterAnalogClock extends StatefulWidget {
  final DateTime dateTime;
  final Color dialPlateColor;
  final Color hourHandColor;
  final Color minuteHandColor;
  final Color secondHandColor;
  final Color numberColor;
  final Color borderColor;
  final Color tickColor;
  final Color centerPointColor;
  final bool showBorder;
  final bool showTicks;
  final bool showMinuteHand;
  final bool showSecondHand;
  final bool showNumber;
  final double borderWidth;
  final double hourNumberScale;
  final List<String> hourNumbers;
  final bool isLive;
  final double width;
  final double height;
  final BoxDecoration decoration;
  final Widget child;

  const FlutterAnalogClock(
      {this.dateTime,
      this.dialPlateColor = Colors.white,
      this.hourHandColor = Colors.black,
      this.minuteHandColor = Colors.black,
      this.secondHandColor = Colors.black,
      this.numberColor = Colors.black,
      this.borderColor = Colors.black,
      this.tickColor = Colors.black,
      this.centerPointColor = Colors.black,
      this.showBorder = true,
      this.showTicks = true,
      this.showMinuteHand = true,
      this.showSecondHand = true,
      this.showNumber = true,
      this.borderWidth,
      this.hourNumberScale = 1.0,
      this.hourNumbers = FlutterAnalogClockPainter.defaultHourNumbers,
      this.isLive = true,
      this.width = double.infinity,
      this.height = double.infinity,
      this.decoration = const BoxDecoration(),
      this.child,
      Key key})
      : super(key: key);
  const FlutterAnalogClock.dark(
      {this.dateTime,
      this.dialPlateColor = Colors.black,
      this.hourHandColor = Colors.grey,
      this.minuteHandColor = Colors.grey,
      this.secondHandColor = Colors.grey,
      this.numberColor = Colors.grey,
      this.borderColor = Colors.black,
      this.tickColor = Colors.grey,
      this.centerPointColor = Colors.grey,
      this.showBorder = true,
      this.showTicks = true,
      this.showMinuteHand = true,
      this.showSecondHand = true,
      this.showNumber = true,
      this.borderWidth,
      this.hourNumberScale = 1.0,
      this.hourNumbers = FlutterAnalogClockPainter.defaultHourNumbers,
      this.isLive = true,
      this.width = double.infinity,
      this.height = double.infinity,
      this.decoration = const BoxDecoration(),
      this.child,
      Key key})
      : super(key: key);

  @override
  _FlutterAnalogClockState createState() =>
      _FlutterAnalogClockState(this.dateTime);
}

class _FlutterAnalogClockState extends State<FlutterAnalogClock> {
  Timer _timer;
  DateTime _dateTime;
  _FlutterAnalogClockState(this._dateTime);

  @override
  void initState() {
    super.initState();
    if (!widget.isLive && this._dateTime == null)
      this._dateTime = DateTime.now();
    _timer = widget.isLive
        ? Timer.periodic(Duration(seconds: 1), (Timer timer) {
            _dateTime = _dateTime?.add(Duration(seconds: 1));
            if (mounted) {
              setState(() {});
            }
          })
        : null;
  }

  @override
  void didUpdateWidget(FlutterAnalogClock oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (widget.dateTime != oldWidget.dateTime) {
      _dateTime = widget.dateTime;
    }
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      width: widget.width,
      height: widget.height,
      decoration: widget.decoration,
      child: CustomPaint(
        child: widget.child,
        painter: FlutterAnalogClockPainter(
          _dateTime ?? DateTime.now(),
          dialPlateColor: widget.dialPlateColor,
          hourHandColor: widget.hourHandColor,
          minuteHandColor: widget.minuteHandColor,
          secondHandColor: widget.secondHandColor,
          numberColor: widget.numberColor,
          borderColor: widget.borderColor,
          tickColor: widget.tickColor,
          centerPointColor: widget.centerPointColor,
          showBorder: widget.showBorder,
          showTicks: widget.showTicks,
          showMinuteHand: widget.showMinuteHand,
          showSecondHand: widget.showSecondHand,
          showNumber: widget.showNumber,
          borderWidth: widget.borderWidth,
          hourNumberScale: widget.hourNumberScale,
          hourNumbers: widget.hourNumbers,
        ),
      ),
    );
  }

  @override
  void dispose() {
    _timer?.cancel();
    super.dispose();
  }
}

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: TimePicker(),
    );
  }
}

class TimePicker extends StatefulWidget {
  @override
  _TimePickerState createState() => _TimePickerState();
}

class _TimePickerState extends State<TimePicker> {
  @override
  void initState() {
    //********************************************************************
    generateRandomTime();
    super.initState();
  }

  // local variables
  var buttonTime;
  var buttonHours;
  var buttonMinutes;
  int clockHours = 1;
  int clockMinutes = 1;

  DateTime _dateTime = DateTime(2019, 1, 1, 1, 1, 15);
  void incrementHours() {
    setState(() {
      _dateTime = _dateTime.add(Duration(hours: 1));
    });
    print(_dateTime.toString());
  }

  void incrementMinutes() {
    setState(() {
      _dateTime = _dateTime.add(Duration(minutes: 1));
    });
    print(_dateTime.toString());
  }

  void decrementHours() {
    setState(() {
      _dateTime = _dateTime.subtract(Duration(hours: 1));
    });
    print(_dateTime.toString());
  }

  void decrementMinutes() {
    setState(() {
      _dateTime = _dateTime.subtract(Duration(minutes: 1));
    });
    print(_dateTime.toString());
  }

  List<Color> clockColorArray = [
    Color(0xff787878),
  ];

  void generateRandomTime()
  //********************************************************************
  {
    buttonHours = Random().nextInt(11) + 1;
    buttonMinutes = Random().nextInt(58) + 1;
    var hoursZero = buttonHours < 10 ? "0" : "";
    var minutesZero = buttonMinutes < 10 ? "0" : "";

    buttonTime = hoursZero +
        buttonHours.toString() +
        " " +
        ':' +
        " " +
        minutesZero +
        buttonMinutes.toString() +
        " Uhr";
  }

  void checkTime() {}

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      body: Center(
          child: Column(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: <Widget>[
          SizedBox(
            height: 10,
          ),
          Container(
            width: 300,
            height: 70,
            alignment: Alignment.center,
            decoration: BoxDecoration(
              color: Color(0xff69a7b6),
              borderRadius: BorderRadius.circular(10),
            ),
            child: Text(
              buttonTime,
              style: TextStyle(
                color: Colors.white,
                fontSize: 40.0,
                fontWeight: FontWeight.bold,
                fontFamily: 'TickingTimebombBB',
              ),
            ),
          ),
          FlutterAnalogClock(
            showBorder: true,
            showTicks: true,
            hourNumbers: [
              '1',
              '2',
              '3',
              '4',
              '5',
              '6',
              '7',
              '8',
              '9',
              '10',
              '11',
              '12'
            ],
            showMinuteHand: true,
            showSecondHand: false,
            showNumber: true,
            borderWidth: 10.0,
            hourNumberScale: 1,
            isLive: false,
            width: 200.0,
            height: 200.0,
            decoration: const BoxDecoration(),
            dateTime: _dateTime,
          ),
          Column(
            children: <Widget>[
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  MaterialButton(
                    minWidth: 100.0,
                    height: 70.0,
                    textColor: Colors.white,
                    shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.all(Radius.circular(10.0))),
                    color: Color(0xff69a7b6),
                    onPressed: () {
                      incrementHours();
                    },
                    child: Text(
                      '+ Hour',
                      style: TextStyle(
                        fontSize: 25.0,
                      ),
                    ),
                  ),
                  SizedBox(
                    width: 10,
                  ),
                  MaterialButton(
                    minWidth: 100.0,
                    height: 70.0,
                    textColor: Colors.white,
                    shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.all(Radius.circular(10.0))),
                    color: Color(0xff69a7b6),
                    onPressed: () {
                      incrementMinutes();
                    },
                    child: Text(
                      '+ Min',
                      style: TextStyle(
                        fontSize: 25.0,
                      ),
                    ),
                  ),
                ],
              ),
              SizedBox(
                height: 10,
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  MaterialButton(
                    minWidth: 100.0,
                    height: 70.0,
                    textColor: Colors.white,
                    shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.all(Radius.circular(10.0))),
                    color: Color(0xff69a7b6),
                    onPressed: () {
                      decrementHours();
                    },
                    child: Text(
                      '- Hour',
                      style: TextStyle(
                        fontSize: 25.0,
                      ),
                    ),
                  ),
                  SizedBox(
                    width: 10,
                  ),
                  MaterialButton(
                    minWidth: 100.0,
                    height: 70.0,
                    textColor: Colors.white,
                    shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.all(Radius.circular(10.0))),
                    color: Color(0xff69a7b6),
                    onPressed: () {
                      decrementMinutes();
                    },
                    child: Text(
                      '- Min',
                      style: TextStyle(
                        fontSize: 25.0,
                      ),
                    ),
                  ),
                ],
              ),
            ],
          ),
          GestureDetector(
            onTap: () {
              setState(() {
                //checkTime();
              });
            },
            child: Container(
              width: 180,
              height: 70,
              decoration: BoxDecoration(
                color: Color(0xffE0E0E0),
                borderRadius: BorderRadius.circular(10),
              ),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.center,
                crossAxisAlignment: CrossAxisAlignment.center,
                children: <Widget>[
                  Text(
                    ('Check'),
                    style: TextStyle(color: Colors.black, fontSize: 25.0),
                  ),
                  SizedBox(
                    width: 25,
                  ),
                  Icon(
                    Icons.check,
                    color: Colors.blueAccent,
                    size: 30.0,
                  )
                ],
              ),
            ),
          )
        ],
      )),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;
  int clockHours = 1;
  int clockMinutes = 1;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            FlutterAnalogClock(
              showBorder: true,
              showTicks: true,
              showMinuteHand: true,
              showSecondHand: false,
              showNumber: true,
              borderWidth: 10.0,
              hourNumberScale: 1,
              isLive: false,
              width: 200.0,
              height: 200.0,
              decoration: const BoxDecoration(),
              dateTime: DateTime(2019, 1, 1, clockHours, clockMinutes, 15),
            ),
            RaisedButton(
                onPressed: () {
                  clockHours = clockHours + 1;
                  setState(() {});
                },
                child: Text("+ Hour")),
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}