Flutility

A collection of useful widgets, material widgets that totally should be included in flutter and other stuff.

See how it works in the examples(##How to use it)

See how to build a material selection effect in the Advanced Example

This package contains

Add the package to your pubspec.yaml file.

flutility: <Newest Version>

And then import it.

import 'package:flutility/flutility.dart';

How to use it

Bool controlled animation

Most of the animated widget in this package are controlled with a bool. This makes simple animation a lot easier because you don't need a animation controller anymore. Don't forget to call setState after changing the value.

bool animate = false;

void animateSomething() {
setState(()) {
animate = !animate;
}}

Scale Item Switch

A widget to switch between two icons with the simple material icon transition. Like the third transition here.

The animation is controlled by the animate value. firstIcon and secondIcon are properties in a IconButton so they should be some sort of icon.

If firstIcon or secondIcon are not set the other icon will just disappear. Icons are in the disabled state if they don't have there VoidCallback set.


ScaleIconSwitch(
  animate: animate,
  firstIcon: Icon(Icons.delete_outline),
  secondIcon: Icon(Icons.share_outlined),
  onFirstPressed: switchIcon,
  onSecondPressed: switchIcon,
)

Simple animated Icon

Just use a bool to control an animated icon. And give it a Duration if you want.


SimpleAnimatedIcon(
        animate: animate,
        icon: AnimatedIcons.play_pause,
);

Delayed Value Builder

This widget updates a value for his child after a delay. Useful if you want to delay values for Foo animations.

Give the DelayedValueBuilder a value. Then you can access the delayed value in the builder. When you call setState the value in the builder will be updated after the delay.

DelayedValueBuilder(
  builder: (context, value) => AnimatedContainer(
    duration: Duration(milliseconds: 200),
    color: value ? Colors.green : Colors.black,
    height: 40,
    width: 40,
  ),
  value: animate,
  delay: Duration(milliseconds: 700),
),

Delayed Value Stagger

A ListView that works like the delayed builder but has multiple widgets which are updated one after one.

DelayedValueStagger(
  value: animate,
  shrinkWrap: true,
  duration: Duration(milliseconds: 200),
  builder: (context, value) => [
    Text('$value'),
    Text('$value'),
    Text('$value'),
    Text('$value'),
 ],
),

Logger

Tired of reading all these gray boring logs? Try Logger! Just create a logger somewhere in your code. You can give it a name if you want.

var logger = Logger(name: 'Logan the logger');

And now you can use it.

logger.log('Hello there');

Example App

Example App that is using most of the features

show/hide
import 'package:flutter/material.dart';
import 'package:flutter_util/flutter_util.dart';

import 'app_bar_page.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  bool animate = false;

  //Using the logger
  void useLogger() {
    Logger logger = Logger(name: 'Dieter the logger');
    logger.log('Hello there!');

    logger.logInfo('This is a info message');

    var list = ['hello', 'there'];
    logger.logRich(list, 'This is a rich message');
  }

//Controlls the animation bool
  void setAnimation() {
    setState(() {
      animate = !animate;
    });
  }

  Widget _simpleAnimatedIcon() => SimpleAnimatedIcon(
        animate: animate,
        icon: AnimatedIcons.play_pause,
      );

  Widget _scaleItemSwitch() => Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          ScaleIconSwitch(
            animate: animate,
            firstIcon: Icon(Icons.share_outlined),
            secondIcon: Icon(Icons.delete_outline),
            // giving the icons a on pressed function so they are not in the disabled state.
            onFirstPressed: () {},
            onSecondPressed: () {},
          ),
          //Just lets the icon disappear
          ScaleIconSwitch(
            animate: animate, duration: Duration(milliseconds: 500),
            firstIcon: Icon(Icons.add_a_photo_outlined),

            // giving the icons a on pressed function so they are not in the disabled state.
            onFirstPressed: () {},
          ),
        ],
      );

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('HomePage')),
      body: Center(
        child: Column(
          children: [
            RaisedButton(
              onPressed: setAnimation,
              child: Text('Animate it'),
            ),
            Text('Simple animated icon'),
            _simpleAnimatedIcon(),
            Text('ScaleIconSwitch'),
            _scaleItemSwitch(),
            RaisedButton(
              onPressed: useLogger,
              child: Text('Hello logger'),
            ),
            RaisedButton(
              onPressed: () => Navigator.of(context).push(MaterialPageRoute(
                  builder: (BuildContext context) => AppBarPage())),
              child: Text('Advanced example'),
            ),
          ],
        ),
      ),
    );
  }
}

Advanced Example

An App that uses the material design select effect

show/hide

import 'package:flutter/material.dart';

import 'package:flutter_util/flutter_util.dart';

class AppBarPage extends StatefulWidget {
  @override
  _AppBarPageState createState() => _AppBarPageState();
}

class _AppBarPageState extends State<AppBarPage> {
  //We are using a logger here
  Logger logger = Logger();
  //If the item is selected animate will be set to true.
  bool animate = false;

  @override
  Widget build(BuildContext context) {
    Widget _appBar() => SliverAppBar(
          pinned: true,

          title: Text(
            animate ? '1 item selected' : 'Advanced example',
            style: TextStyle(color: animate ? Colors.white : Colors.black),
          ),

          backgroundColor: Colors.white,
          leading: Center(
            child: IconButton(
              onPressed: () {
                setState(() {
                  if (animate) {
                    animate = false;
                    logger.log('Selection cancelled');
                  }
                });
              },
              icon: SimpleAnimatedIcon(
                animate: animate,
                color: animate ? Colors.white : Colors.black,
                icon: AnimatedIcons.menu_close,
              ),
            ),
          ),
          actions: [
            ScaleIconSwitch(
              animate: animate,
              secondIcon: Icon(
                Icons.share_outlined,
                color: Colors.white,
              ),
              onSecondPressed: () => logger.log('Share!'),
            ),
            ScaleIconSwitch(
              animate: animate,
              firstIcon: Icon(Icons.info_outline_rounded, color: Colors.black),
              secondIcon: Icon(
                Icons.delete_outline_outlined,
                color: Colors.white,
              ),
              onFirstPressed: () => logger.logInfo('Info!'),
              onSecondPressed: () => logger.log('Delete!'),
            ),
          ],
          //Put the RippleAnimation in the flexibleSpace
          flexibleSpace: Container(
            child: RippleAnimation(
              animate: animate,
              duration: Duration(milliseconds: 260),
              // Offset so it looks like it starts at the bottom
              offsetY: 90,
              offsetX: 40,
              rippleColor: Colors.deepPurpleAccent[400],
              //If backgroundColor is not set it will be set transparent
              height: 56,
            ),
          ),
        );

    return Scaffold(
      backgroundColor: Colors.white,
      body: NestedScrollView(
        headerSliverBuilder: (context, innerBoxIsScrolled) => [_appBar()],
        body: Column(
          children: [
            CheckboxListTile(
              activeColor: Colors.deepPurpleAccent[400],
              value: animate,
              controlAffinity: ListTileControlAffinity.leading,
              title: Text('Something you can select'),
              subtitle: Text('For a cool effect'),
              onChanged: (bool value) {
                setState(
                  () {
                    animate = value;
                  },
                );
              },
            )
          ],
        ),
      ),
    );
  }
}

Libraries

delayed_value_builder
delayed_value_stagger
emphasized_elevation
flutility
logger
ripple_anamation
scale_item_switch
simple_animated_icon