updatable_vertical_ticker 1.1.4 copy "updatable_vertical_ticker: ^1.1.4" to clipboard
updatable_vertical_ticker: ^1.1.4 copied to clipboard

A flutter widget for a smooth scrolling vertical text ticker which integrates text updates cleanly so that scrolling is glitch-free and uninterrupted.

example/lib/main.dart

import 'dart:async';
import 'dart:math';

import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:ipsum/ipsum.dart';
import 'package:updatable_vertical_ticker/updatable_vertical_ticker.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Updatable Vertical Ticker Example',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final Duration oneSec = Duration(milliseconds: 500);
  final double minDesktopWidth = 768;
  final double linePadding = 20;
  final double borderSpace = 64;
  final int fontMinSize = 12;
  final int fontMaxSize = 80;
  final int ledDotMinSize = 1;
  final int ledDotMaxSize = 10;
  final int maxLines = 8;

  final int modules = 21;
  final double ledGap = 0.2;
  final Color ledOnColor = Colors.red.shade500;
  final Color ledOffColor = const Color(0xFF000000);

  Orientation orientation = Orientation.portrait;
  DateTime lastUpdate = DateTime.now();
  List<String> updatableText = [];
  double width = 1024;
  double height = 768;
  double fontSize = 24.0;
  double ledSize = 5.0;
  int maxWidth = 0;
  int scrollDuration = 400;
  int linePause = 1;
  int cyclePause = 2;
  int rng = -1;
  int seconds = 0;
  bool initialized = false;
  bool showLedVariant = false;

  @override
  void initState() {
    super.initState();

    start();
  }

  Future<void> start() async {
    await randomUpdates();

    Timer.periodic(
      oneSec,
      (Timer t) => setState(() {
        final int value =
            rng - DateTime.now().difference(lastUpdate).inSeconds - 1;
        seconds = value > 0 ? value : 0;
      }),
    );

    initialized = true;
  }

  int random(int min, int max) {
    return min + Random().nextInt(max - min);
  }

  List<String> textGenerator({required bool showLedVariant}) {
    final List<String> newTexts = ['-- Start --'];
    final int lines = random(3, 6);

    for (int i = 1; i < lines; i++) {
      final int rng = random(5, 10);
      String line = Ipsum().words(rng);
      if (showLedVariant == true && line.length > modules) {
        line = line.substring(0, modules);
      }
      newTexts.add(line);
    }
    newTexts.add('-- End --');

    return newTexts;
  }

  Future<void> randomUpdates() {
    rng = rng == -1 ? 2 : random(4, 60);

    return Future.delayed(Duration(seconds: rng), () {
      SchedulerBinding.instance.addPostFrameCallback((_) async {
        if (mounted) {
          setState(() {
            lastUpdate = DateTime.now();
            updatableText = textGenerator(showLedVariant: showLedVariant);
          });
        }
      });

      randomUpdates();
    });
  }

  List<Widget> sliders1() => [
        Row(
          children: [
            SizedBox(width: 100.0, child: Text('scrollDuration: ')),
            SizedBox(
              width: 170,
              child: Slider(
                value: scrollDuration.toDouble(),
                min: 100,
                max: 1000,
                divisions: 100,
                thumbColor: Colors.red.shade700,
                activeColor: Colors.green.shade200,
                inactiveColor: Colors.grey.shade700,
                onChanged: (double value) {
                  setState(() {
                    scrollDuration = value.floor();
                  });
                },
              ),
            ),
            Text('$scrollDuration ms'),
          ],
        ),
        if (width > minDesktopWidth) Expanded(child: SizedBox()),
        Row(
          children: [
            SizedBox(
                width: 100.0,
                child: Text(showLedVariant ? 'Dotsize' : 'FontSize: ')),
            SizedBox(
              width: 170,
              child: Slider(
                value: showLedVariant ? ledSize : fontSize,
                min: showLedVariant
                    ? ledDotMinSize.toDouble()
                    : fontMinSize.toDouble(),
                max: showLedVariant
                    ? ledDotMaxSize.toDouble()
                    : fontMaxSize.toDouble(),
                divisions: showLedVariant
                    ? ledDotMaxSize - ledDotMinSize
                    : fontMaxSize - fontMinSize,
                thumbColor: Colors.red.shade700,
                activeColor: Colors.green.shade200,
                inactiveColor: Colors.grey.shade700,
                onChanged: (double value) {
                  setState(() {
                    if (showLedVariant) {
                      ledSize = value;
                    } else {
                      fontSize = value;
                    }
                  });
                },
              ),
            ),
            SizedBox(
              width: 80.0,
              child: Text(showLedVariant ? '$ledSize px' : '$fontSize px'),
            ),
          ],
        ),
      ];

  List<Widget> sliders2() => [
        Row(
          children: [
            SizedBox(width: 100.0, child: Text('linePause: ')),
            SizedBox(
              width: 170,
              child: Slider(
                value: linePause.toDouble(),
                min: 0,
                max: 5,
                divisions: 5,
                thumbColor: Colors.red.shade700,
                activeColor: Colors.green.shade200,
                inactiveColor: Colors.grey.shade700,
                onChanged: (double value) {
                  setState(() {
                    linePause = value.floor();
                  });
                },
              ),
            ),
            Text('$linePause s'),
          ],
        ),
        if (width > minDesktopWidth) Expanded(child: SizedBox()),
        Row(
          children: [
            SizedBox(width: 100.0, child: Text('cyclePause: ')),
            SizedBox(
              width: 170,
              child: Slider(
                value: cyclePause.toDouble(),
                min: 0,
                max: 5,
                divisions: 5,
                thumbColor: Colors.red.shade700,
                activeColor: Colors.green.shade200,
                inactiveColor: Colors.grey.shade700,
                onChanged: (double value) {
                  setState(() {
                    cyclePause = value.floor();
                  });
                },
              ),
            ),
            SizedBox(width: 80.0, child: Text('$cyclePause s')),
          ],
        ),
      ];

  @override
  Widget build(BuildContext context) {
    width = MediaQuery.of(context).size.width;
    height = MediaQuery.of(context).size.height;

    return MaterialApp(
      title: 'Updatable Vertical Ticker',
      themeMode: ThemeMode.system,
      home: Material(
        child: SafeArea(
          child: Center(
            child: SizedBox(
              width: MediaQuery.of(context).size.width - 64,
              child: OrientationBuilder(
                  builder: (BuildContext context, Orientation o) {
                orientation = o;

                return NotificationListener<SizeChangedLayoutNotification>(
                  onNotification: (notification) {
                    width = MediaQuery.of(context).size.width;
                    height = MediaQuery.of(context).size.height;
                    build(context);
                    return false;
                  },
                  child: SizeChangedLayoutNotifier(
                    child: Container(
                      padding: EdgeInsets.only(top: 16.0),
                      key: ValueKey(
                        'UpdatableVerticalTickerWrapper-${orientation == Orientation.portrait ? 'portrait' : 'landscape'}-$width',
                      ),
                      width: width - 16,
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Wrap(
                            children: [
                              SizedBox(
                                  width: 142,
                                  height: 32.0,
                                  child: Row(
                                    children: [
                                      Text(
                                        'Options: ',
                                        style: TextStyle(
                                            fontWeight: FontWeight.bold),
                                      ),
                                    ],
                                  )),
                              SizedBox(
                                width: 250.0,
                                child: Row(
                                  mainAxisSize: MainAxisSize.min,
                                  children: [
                                    Checkbox(
                                      value: showLedVariant,
                                      onChanged: (bool? mode) {
                                        setState(() {
                                          updatableText = textGenerator(
                                              showLedVariant: !showLedVariant);
                                          showLedVariant = !showLedVariant;
                                        });
                                      },
                                    ),
                                    Text('display LED variant'),
                                  ],
                                ),
                              ),
                            ],
                          ),
                          SizedBox(height: 16.0),
                          Wrap(
                            crossAxisAlignment: WrapCrossAlignment.center,
                            children: [
                              SizedBox(
                                width: 150.0,
                                child: Row(
                                  children: [
                                    Text(
                                      'width: ',
                                      style: TextStyle(
                                          fontWeight: FontWeight.bold),
                                    ),
                                    Text('${width - 16}'),
                                  ],
                                ),
                              ),
                              SizedBox(
                                width: 150.0,
                                child: Row(
                                  children: [
                                    Text(
                                      'maxWidth: ',
                                      style: TextStyle(
                                          fontWeight: FontWeight.bold),
                                    ),
                                    Text('$maxWidth'),
                                  ],
                                ),
                              ),
                              SizedBox(
                                width: 220.0,
                                child: Row(
                                  mainAxisSize: MainAxisSize.min,
                                  children: [
                                    Text(
                                      'orientation: ',
                                      style: TextStyle(
                                          fontWeight: FontWeight.bold),
                                    ),
                                    Text(orientation.name),
                                  ],
                                ),
                              ),
                            ],
                          ),
                          Padding(
                            padding: EdgeInsets.only(top: linePadding),
                            child: SizedBox(
                              height: maxLines * 20,
                              child: Row(
                                crossAxisAlignment: CrossAxisAlignment.start,
                                children: [
                                  Text(
                                    'new text lines: ',
                                    style:
                                        TextStyle(fontWeight: FontWeight.bold),
                                  ),
                                  Flexible(
                                    child: Text(
                                      updatableText.join('\n'),
                                      maxLines: maxLines,
                                      overflow: TextOverflow.ellipsis,
                                    ),
                                  ),
                                ],
                              ),
                            ),
                          ),
                          Padding(
                            padding: EdgeInsets.only(top: linePadding),
                            child: Row(
                              children: [
                                Text(
                                  'next update: ',
                                  style: TextStyle(fontWeight: FontWeight.bold),
                                ),
                                Text('in $seconds seconds'),
                              ],
                            ),
                          ),
                          Padding(
                            padding: EdgeInsets.only(top: linePadding),
                            child: width > minDesktopWidth
                                ? Row(
                                    children: sliders1(),
                                  )
                                : SizedBox(
                                    height: 100.0,
                                    child: SizedBox(
                                      height: 100.0,
                                      child: Column(
                                        crossAxisAlignment:
                                            CrossAxisAlignment.start,
                                        children: sliders1(),
                                      ),
                                    ),
                                  ),
                          ),
                          Padding(
                            padding: EdgeInsets.only(top: linePadding),
                            child: width > minDesktopWidth
                                ? Row(
                                    children: sliders2(),
                                  )
                                : SizedBox(
                                    height: 100.0,
                                    child: SizedBox(
                                      height: 100.0,
                                      child: Column(
                                        crossAxisAlignment:
                                            CrossAxisAlignment.start,
                                        children: sliders2(),
                                      ),
                                    ),
                                  ),
                          ),
                          if (width > minDesktopWidth)
                            Expanded(
                              child: SizedBox(),
                            ),
                          Padding(
                            padding: const EdgeInsets.only(bottom: 8.0),
                            child: Stack(
                              children: [
                                SizedBox(
                                  height: (fontMaxSize * 1.2).toDouble(),
                                  child: Center(
                                    child: Container(
                                      color: Colors.lightBlueAccent,
                                      child: initialized == true &&
                                              updatableText.isNotEmpty
                                          ? showLedVariant
                                              ? UpdatableVerticalLedTicker(
                                                  key: ValueKey(
                                                    'UpdatableVerticalTickerExamplePage-${orientation == Orientation.portrait ? 'portrait' : 'landscape'}-$width-${showLedVariant ? ledSize : fontSize}',
                                                  ),
                                                  texts: updatableText,
                                                  modules: modules,
                                                  useProportionalFont: true,
                                                  center: true,
                                                  ledSize: ledSize,
                                                  ledGap: ledGap,
                                                  onColor: ledOnColor,
                                                  offColor: ledOffColor,
                                                  scrollDuration: Duration(
                                                      milliseconds:
                                                          scrollDuration),
                                                  linePause: Duration(
                                                      seconds: linePause),
                                                  cyclePause: Duration(
                                                      seconds: cyclePause),
                                                  // getMaxWidth: (int width) {
                                                  //   SchedulerBinding.instance
                                                  //       .addPostFrameCallback(
                                                  //           (_) async {
                                                  //     if (mounted) {
                                                  //       setState(() {
                                                  //         maxWidth = width;
                                                  //       });
                                                  //     }
                                                  //   });
                                                  // },
                                                )
                                              : UpdatableVerticalTicker(
                                                  key: ValueKey(
                                                    'UpdatableVerticalTickerExamplePage-${orientation == Orientation.portrait ? 'portrait' : 'landscape'}-$width-$fontSize',
                                                  ),
                                                  texts: updatableText,
                                                  scrollDuration: Duration(
                                                      milliseconds:
                                                          scrollDuration),
                                                  linePause: Duration(
                                                      seconds: linePause),
                                                  cyclePause: Duration(
                                                      seconds: cyclePause),
                                                  textStyle: TextStyle(
                                                    fontFamily:
                                                        'whiteCupertino subtitle',
                                                    fontSize: fontSize,
                                                    color: Colors.black,
                                                  ),
                                                  getMaxWidth: (int width) {
                                                    SchedulerBinding.instance
                                                        .addPostFrameCallback(
                                                            (_) async {
                                                      if (mounted) {
                                                        setState(() {
                                                          maxWidth = width;
                                                        });
                                                      }
                                                    });
                                                  },
                                                )
                                          : SizedBox(),
                                    ),
                                  ),
                                ),
                              ],
                            ),
                          ),
                        ],
                      ),
                    ),
                  ),
                );
              }),
            ),
          ),
        ),
      ),
    );
  }
}
0
likes
160
points
20
downloads

Documentation

API reference

Publisher

verified publisherwilhelm-devblog.de

Weekly Downloads

A flutter widget for a smooth scrolling vertical text ticker which integrates text updates cleanly so that scrolling is glitch-free and uninterrupted.

Repository (GitHub)
View/report issues

Topics

#animation #text #ticker #ui

License

MIT (license)

Dependencies

flutter

More

Packages that depend on updatable_vertical_ticker