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
- SimpleAnimatedIcon
- Scale Item Switch
- Delayed Value Builder
- Delayed Value Stagger
- Logger
- Ripple Animation
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;
},
);
},
)
],
),
),
);
}
}