"Fossies" - the Fresh Open Source Software Archive

Member "flutter-3.7.1/packages/flutter/lib/src/cupertino/activity_indicator.dart" (1 Feb 2023, 5995 Bytes) of package /linux/misc/flutter-3.7.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Dart source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 // Copyright 2014 The Flutter Authors. All rights reserved.
    2 // Use of this source code is governed by a BSD-style license that can be
    3 // found in the LICENSE file.
    4 
    5 import 'dart:math' as math;
    6 
    7 import 'package:flutter/widgets.dart';
    8 
    9 import 'colors.dart';
   10 
   11 const double _kDefaultIndicatorRadius = 10.0;
   12 
   13 // Extracted from iOS 13.2 Beta.
   14 const Color _kActiveTickColor = CupertinoDynamicColor.withBrightness(
   15   color: Color(0xFF3C3C44),
   16   darkColor: Color(0xFFEBEBF5),
   17 );
   18 
   19 /// An iOS-style activity indicator that spins clockwise.
   20 ///
   21 /// {@youtube 560 315 https://www.youtube.com/watch?v=AENVH-ZqKDQ}
   22 ///
   23 /// {@tool dartpad}
   24 /// This example shows how [CupertinoActivityIndicator] can be customized.
   25 ///
   26 /// ** See code in examples/api/lib/cupertino/activity_indicator/cupertino_activity_indicator.0.dart **
   27 /// {@end-tool}
   28 ///
   29 /// See also:
   30 ///
   31 ///  * <https://developer.apple.com/ios/human-interface-guidelines/controls/progress-indicators/#activity-indicators>
   32 class CupertinoActivityIndicator extends StatefulWidget {
   33   /// Creates an iOS-style activity indicator that spins clockwise.
   34   const CupertinoActivityIndicator({
   35     super.key,
   36     this.color,
   37     this.animating = true,
   38     this.radius = _kDefaultIndicatorRadius,
   39   })  : assert(animating != null),
   40         assert(radius != null),
   41         assert(radius > 0.0),
   42         progress = 1.0;
   43 
   44   /// Creates a non-animated iOS-style activity indicator that displays
   45   /// a partial count of ticks based on the value of [progress].
   46   ///
   47   /// When provided, the value of [progress] must be between 0.0 (zero ticks
   48   /// will be shown) and 1.0 (all ticks will be shown) inclusive. Defaults
   49   /// to 1.0.
   50   const CupertinoActivityIndicator.partiallyRevealed({
   51     super.key,
   52     this.color,
   53     this.radius = _kDefaultIndicatorRadius,
   54     this.progress = 1.0,
   55   })  : assert(radius != null),
   56         assert(radius > 0.0),
   57         assert(progress != null),
   58         assert(progress >= 0.0),
   59         assert(progress <= 1.0),
   60         animating = false;
   61 
   62   /// Color of the activity indicator.
   63   ///
   64   /// Defaults to color extracted from native iOS.
   65   final Color? color;
   66 
   67   /// Whether the activity indicator is running its animation.
   68   ///
   69   /// Defaults to true.
   70   final bool animating;
   71 
   72   /// Radius of the spinner widget.
   73   ///
   74   /// Defaults to 10px. Must be positive and cannot be null.
   75   final double radius;
   76 
   77   /// Determines the percentage of spinner ticks that will be shown. Typical usage would
   78   /// display all ticks, however, this allows for more fine-grained control such as
   79   /// during pull-to-refresh when the drag-down action shows one tick at a time as
   80   /// the user continues to drag down.
   81   ///
   82   /// Defaults to 1.0. Must be between 0.0 and 1.0 inclusive, and cannot be null.
   83   final double progress;
   84 
   85   @override
   86   State<CupertinoActivityIndicator> createState() => _CupertinoActivityIndicatorState();
   87 }
   88 
   89 class _CupertinoActivityIndicatorState extends State<CupertinoActivityIndicator>
   90     with SingleTickerProviderStateMixin {
   91   late AnimationController _controller;
   92 
   93   @override
   94   void initState() {
   95     super.initState();
   96     _controller = AnimationController(
   97       duration: const Duration(seconds: 1),
   98       vsync: this,
   99     );
  100 
  101     if (widget.animating) {
  102       _controller.repeat();
  103     }
  104   }
  105 
  106   @override
  107   void didUpdateWidget(CupertinoActivityIndicator oldWidget) {
  108     super.didUpdateWidget(oldWidget);
  109     if (widget.animating != oldWidget.animating) {
  110       if (widget.animating) {
  111         _controller.repeat();
  112       } else {
  113         _controller.stop();
  114       }
  115     }
  116   }
  117 
  118   @override
  119   void dispose() {
  120     _controller.dispose();
  121     super.dispose();
  122   }
  123 
  124   @override
  125   Widget build(BuildContext context) {
  126     return SizedBox(
  127       height: widget.radius * 2,
  128       width: widget.radius * 2,
  129       child: CustomPaint(
  130         painter: _CupertinoActivityIndicatorPainter(
  131           position: _controller,
  132           activeColor: widget.color ?? CupertinoDynamicColor.resolve(_kActiveTickColor, context),
  133           radius: widget.radius,
  134           progress: widget.progress,
  135         ),
  136       ),
  137     );
  138   }
  139 }
  140 
  141 const double _kTwoPI = math.pi * 2.0;
  142 
  143 /// Alpha values extracted from the native component (for both dark and light mode) to
  144 /// draw the spinning ticks.
  145 const List<int> _kAlphaValues = <int>[
  146   47,
  147   47,
  148   47,
  149   47,
  150   72,
  151   97,
  152   122,
  153   147,
  154 ];
  155 
  156 /// The alpha value that is used to draw the partially revealed ticks.
  157 const int _partiallyRevealedAlpha = 147;
  158 
  159 class _CupertinoActivityIndicatorPainter extends CustomPainter {
  160   _CupertinoActivityIndicatorPainter({
  161     required this.position,
  162     required this.activeColor,
  163     required this.radius,
  164     required this.progress,
  165   })  : tickFundamentalRRect = RRect.fromLTRBXY(
  166           -radius / _kDefaultIndicatorRadius,
  167           -radius / 3.0,
  168           radius / _kDefaultIndicatorRadius,
  169           -radius,
  170           radius / _kDefaultIndicatorRadius,
  171           radius / _kDefaultIndicatorRadius,
  172         ),
  173         super(repaint: position);
  174 
  175   final Animation<double> position;
  176   final Color activeColor;
  177   final double radius;
  178   final double progress;
  179 
  180   final RRect tickFundamentalRRect;
  181 
  182   @override
  183   void paint(Canvas canvas, Size size) {
  184     final Paint paint = Paint();
  185     final int tickCount = _kAlphaValues.length;
  186 
  187     canvas.save();
  188     canvas.translate(size.width / 2.0, size.height / 2.0);
  189 
  190     final int activeTick = (tickCount * position.value).floor();
  191 
  192     for (int i = 0; i < tickCount * progress; ++i) {
  193       final int t = (i - activeTick) % tickCount;
  194       paint.color = activeColor
  195           .withAlpha(progress < 1 ? _partiallyRevealedAlpha : _kAlphaValues[t]);
  196       canvas.drawRRect(tickFundamentalRRect, paint);
  197       canvas.rotate(_kTwoPI / tickCount);
  198     }
  199 
  200     canvas.restore();
  201   }
  202 
  203   @override
  204   bool shouldRepaint(_CupertinoActivityIndicatorPainter oldPainter) {
  205     return oldPainter.position != position ||
  206         oldPainter.activeColor != activeColor ||
  207         oldPainter.progress != progress;
  208   }
  209 }