null

Flutter Package: count_number

Beim Arbeiten an einem kleinen Hobby-Projekt wollte ich einen animierten Zählvorgang implementieren. Dieser sollte je näher er dem Zielwert kommt immer langsamer hoch- bzw. runterzählen. Aus dem Code entstand dann dieses Package.

Features

  • Zählt animiert eine Zahl auf oder ab
  • Unterstützt Integer- und Double-Werte
  • Ruft die Callbacks nur dann auf, wenn sie wirklich nötig sind
  • Kann als dynamisch initialisiert werden
    • Das Setzen des Eigenschaftswertes löst einen neuen Zählvorgang aus

Erste Schritte

Füge die Abhängigkeit hinzu:

flutter pub add count_number

Importiere das Package:

import 'package:count_number/count_number.dart';

Verwendung

Initialisieren eines CountNumber-Objekts:

class _HomeState extends State<Home> {
  int _number = 0;
  late CountNumber _countNumber;

  @override
  void initState() {
    _countNumber = CountNumber(
      endValue: 50,
      onUpdate: (value) => setState(() => _number = value as int),
    );
    super.initState();
  }

  @override
  void dispose() {
    _countNumber.stop();
    super.dispose();
  }
}

Ausführen der Methode start():

@override
  Widget build(BuildContext context) {
    _countNumber.start();

    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Expanded(
        child: Center(
            child: Text(
            _number.toString(),
            style: Theme.of(context).textTheme.headline1,
          ),
        )
      ),
    );
  }

Beispiel

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

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Count Numbers',
      home: const Home('Count Numbers'),
      theme: Theme.of(context).copyWith(
        useMaterial3: true,
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.teal),
      ),
      color: Colors.lightGreen,
    );
  }
}

class Home extends StatefulWidget {
  final String title;

  const Home(this.title, {super.key});

  @override
  State<Home> createState() => _HomeState();
}

class _HomeState extends State<Home> {
  num _number = 0;
  bool _isNumActive = true;
  late CountNumber _countNumber;
  late TextEditingController _txtController;

  void _onPressed() {
    if (_isNumActive) {
      num? newVal = num.tryParse(_txtController.text);
      if (newVal != null) {
        _isNumActive = false;
        _countNumber.value = newVal;
      }
    }
  }

  void onCountUpdate(num value) {
    setState(() => _number = value);
  }

  void onCountDone() {
    setState(() => _isNumActive = true);
  }

  @override
  void initState() {
    _txtController = TextEditingController(text: '0');
    _countNumber = CountNumber(
      endValue: _number,
      onUpdate: onCountUpdate,
      onDone: onCountDone,
      isDynamic: true,
    );
    super.initState();
  }

  @override
  void dispose() {
    _countNumber.stop();
    _txtController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Column(
        children: [
          Expanded(
              child: Center(
                child: Text(
                  CountNumber.isInteger(_number)
                      ? _number.toString()
                      : _number.toStringAsFixed(2),
                  style: Theme.of(context).textTheme.headline1,
                ),
              )),
          Card(
            elevation: 12,
            margin: const EdgeInsets.symmetric(
              vertical: 30,
              horizontal: 20,
            ),
            child: Row(
              children: [
                const SizedBox(
                  width: 15,
                ),
                Expanded(
                  flex: 2,
                  child: Padding(
                    padding: const EdgeInsets.symmetric(
                      vertical: 5,
                      horizontal: 20,
                    ),
                    child: TextField(
                      controller: _txtController,
                      enabled: _isNumActive,
                      keyboardType: TextInputType.number,
                      textAlign: TextAlign.center,
                      onSubmitted: (_) => _onPressed(),
                      style: Theme.of(context).textTheme.headline4?.copyWith(
                        fontWeight: FontWeight.w200,
                      ),
                      decoration: const InputDecoration(
                        fillColor: Colors.white70,
                        filled: true,
                        contentPadding: EdgeInsets.all(10),
                        border: OutlineInputBorder(
                            borderRadius: BorderRadius.all(Radius.circular(10)),
                            borderSide: BorderSide(
                              color: Colors.cyan,
                            )),
                      ),
                    ),
                  ),
                ),
                const Spacer(),
                TextButton(
                  onPressed: _onPressed,
                  child: const Text('Count!'),
                ),
                const SizedBox(
                  width: 15,
                ),
              ],
            ),
          )
        ],
      ),
    );
  }
}

count_number | Flutter Package
count_number - Counts up or down a value based on a spring animation.

Package

GitHub - jibbex/count_number: Counts up or down a value based on a spring animation.
Counts up or down a value based on a spring animation. - GitHub - jibbex/count_number: Counts up or down a value based on a spring animation.

Repository