universal_widget 1.2.5

The Mighty UniversalWidget #

I'm just so excited to introduce to you my superhero widget: UniversalWidget

You can find the package at: https://pub.dartlang.org/packages/universal_widget

Why? #

With UniversalWidget, you will have full control with it in the widget tree.

alt text

I made this login animation with UniversalWidget in only 8 lines of code. If you want to know how to do it with Flutter, see this cool tutorial: https://blog.geekyants.com/flutter-login-animation-ab3e6ed4bd19

Write less, do more. #

For example, instead of:

Positioned(
  top: 10,
  left: 20,
  child: Container(
    height: 50,
    padding: EdgeInsets.all(20),
    decoration: BoxDecoration(
      color: Colors.blueAccent,
      borderRadius: BorderRadius.circular(10)
    ),
    transform: Matrix4()..identity()
      ..translate(20, 40)
      ..rotation(45 * math.pi),
    child: Text("Hello World")
  )
)

You can write:

UniversalWidget(
  x: 20,
  y: 40,
  rotation: 45, // degrees
  top: 10,
  left: 20,
  height: 50,
  padding: EdgeInsets.all(20)
  color: Colors.blueAccent,
  borderRadius: BorderRadius.circular(10),
  child: Text("Hello World")
)

Much shorter, right? Not stop from that, it's more helpful than you think. Please continue reading the next paragraph.

Flexibility #

Let's say I have a widget in red:

UniversalWidget myWidget = UniversalWidget(
  color: Colors.red
);

What if I want to change its color into BLUE when I pressed a button? Easy as pie:

RaisedButton(
  child: Text("Change Me!"),
  onPressed: (){
    myWidget.update(
      color: Colors.blue
    )
  }
);

Think about how you will do this with StatefulWidget, I bet it would cost you at least 20 lines of code. Now looks back...

There are a lot more features that can unlock the true power of UniversalWidget. Such as:

To manage the UniversalWidget's visibility:

myWidget.update(visible: false);
// turns its visibility on by: myWidget.update(visible: true);

You can even change the child widget of UniversalWidget:

myWidget.update(
  child: Text("Holy Shiettttt!")
);

Masking (clipping) the child widget of UniversalWidget by setting mask flag:

myWidget.update(
  mask: true,
  child: Text("Holy Shiettttt!")
);

Animation #

I admit that AnimatedContainer does a good job. But UniversalWidget can do animation much better:

UniversalWidget myWidget = UniversalWidget(
  color: Colors.red,
  height: 50
);
// let animate it:
myWidget.update(
  duration: 0.5 // seconds
  color: Colors.blue
);

It's just simple like that!

Advanced Animation #

Apply easing type to the animation, listen to the widget to see when the animation is finished, see the progress of the animation, or make the animation repeated. Here you go:

myWidget.update(
  duration: 0.5, // in seconds
  delay: 2, // in seconds - wait 2 seconds then play the animation
  height: 100,
  ease: Curve.elasticEaseOut, // or your can use Ease.elasticEaseOut, it's the same
  onComplete: (widget){
    print("I finished changing my height!");
  },
  onUpdate: (progress){
    print("Animation progress is $progress");
  }
);

If you want to repeat the animation 5 times:

myWidget.update(
  ...
  repeat: 5,
  ...
);

If you want the animation to play in reverse after it's finish: (like the way playing Yoyo in real life)

myWidget.update(
  ...
  yoyo: true,
  ...
);

If you want to repeat the animation forever:

myWidget.update(
  ...
  repeat: -1,
  ...
);

Combining "repeat" and "yoyo", you will have the animation go forward & backward forever:

myWidget.update(
  ...
  repeat: -1,
  yoyo: true,
  ...
);

To stop the widget from animation:

myWidget.killAllTweens();

Additional Animation Easing Types #

Yes, UniversalWidget has more easing type than Flutter framework, it supports:

  • Ease.backIn
  • Ease.backOut
  • Ease.backInOut
  • Ease.slowMo
  • Ease.sineIn
  • Ease.sineOut
  • Ease.sineInOut

Let play with it yourself! ;)

Accessibility #

Let's take full control of your UniversalWidget, you can access to it everywhere, EVERYWHERE. (as long as it's still on your screen)

By give it a name:

UniversalWidget(
  name: "TheMightyWidgetEver",
  width: 100.0, height: 50.0
);

Now what if you want this widget to animate the height to zero when pressing on the button?

RaisedButton(
  child: Text("Collapse Me!"),
  onPressed: (){
    UniversalWidget.find("TheMightyWidgetEver").update(
      duration: 0.8,
      height: 0.0
    )
  }
);

Or just want to check for its properties:

UniversalWidget widget = UniversalWidget.find("TheMightyWidgetEver");
print(widget.get().width); // 100.0

Notes that the given name should be unique, if you have many UniversalWidget with the same name, only the latest one in the widget tree can be accessible by a name, the others won't. So please name it wisely.

Wait, there's more. If you want to check for the size of the widget, do this:

UniversalWidget(
  child: Text("Hello World!"),
  // because the widget size can only be calculated after the widget are build, you need to listen on this event:
  onWidgetBuilt: (context){
    print("My size is ${context.size}");
  }
);

Check whether the widget located on the screen:

UniversalWidget widget = UniversalWidget.find("TheMightyWidgetEver");
//...
print(widget.globalPosition);

Summary #

Phewwww... that's it for now. Now you guys might understand why I called it "The Mighty Widget", not too brag, eh? Hopefully it will save you a bunch of time, as it's saving me right now.

If you have any feedback, or meet any troubles while using this widget, please feel free to reach me via this Github repo.

Happy Coding with Flutter guys! I'll be back.

[1.2.4] - Fixed bug

  • Fixed bug of not tweening the rotation attribute.

[1.2.4] - Fixed bug

  • Fixed error: A UniversalWidgetController was used after being disposed..

[1.2.0] - Big performance improvement, added UniversalChannel & a lot new features

  • Performance improved much better.
  • Added widget.reset() to reset the UniversalWidget to the very first time it's created.
  • Added widget.onEnterFrame(callback, {int fps}) and widget.stopEnterFrame() (OMG, this one is so much fun!).
  • Added widget.toByte({pixelRatio}), widget.toImage({pixelRatio}), widget.toBase64({pixelRatio}) to capture the widget and convert it to image/base64/byte.
  • Added UniversalChannel to communicate between UniversalWidgets (Full documentation & Examples will come later).
  • Fixed some minor bugs.

[1.1.2] - More features & fixed bugs.

  • Changed onWidgetBuilt(BuildContext) to onWidgetBuild(UniversalWitget).
  • Added onWidgetUpdated(UniversalWidget).
  • Added override (bool) to update() method, default value is true, so you can do multiple update() animation at the sametime.
  • Added stopAnimation() method in case you want to stop all animations of the widget.
  • Added interaction properties to enable/disable interactivity of the widget.
  • Fixed losing state issue (when update widget while state hasn't been created).
  • Fixed some minor bugs.

[1.1.1] - Fixed some minor bugs.

  • Update documentation.
  • Added example.

[1.1.0] - Added more features & Fixed some minor bugs.

  • Updated the documentation.
  • Added button mode with onPressed.
  • Added mask (clip) feature.
  • Added update(child) feature.
  • Fixed some minor bugs.
  • TODO: Performance improvement.

[1.0.0] - Publish the widget.

  • TODO: Wait for the bugs?
  • TODO: Performance improvement.

example/main.dart

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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.

  @override
  Widget build(BuildContext context) {
    return HomeScreen();
  }
}

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {

    Widget example = Container(
      padding: EdgeInsets.only(top: 50),
      child: Column(
        children: <Widget>[
          Padding(
            padding: EdgeInsets.only(bottom: 8),
            child: Wrap(
              spacing: 8,
              runSpacing: 8,
              children: <Widget>[
                RaisedButton(
                  child: Text("Start"),
                  onPressed: (){
                    UniversalWidget.find("testWidget").update(
                      duration: 0.5,
                      height: 600,
                      onComplete: (){
                        print("Start -> Done");
                      }
                    );
                  },
                ),
                RaisedButton(
                  child: Text("Reverse"),
                  onPressed: (){
                    UniversalWidget.find("testWidget").update(
                      duration: 0.5,
                      height: 300,
                      onComplete: (){
                        print("Reverse -> Done");
                      }
                    );
                  },
                ),
                RaisedButton(
                  child: Text("Reset"),
                  onPressed: (){
                    UniversalWidget.find("testWidget").update(height: 300, color: Colors.redAccent);
                  },
                ),
                RaisedButton(
                  child: Text("Yoyo"),
                  onPressed: (){
                    UniversalWidget.find("testWidget").update(height: 300);
                    UniversalWidget.find("testWidget").update(
                      duration: 0.5,
                      height: 600,
                      yoyo: true,
                    );
                  },
                ),
                RaisedButton(
                  child: Text("Loop"),
                  onPressed: (){
                    UniversalWidget.find("testWidget").update(height: 300);
                    UniversalWidget.find("testWidget").update(
                      duration: 0.5,
                      height: 600,
                      yoyo: true,
                      repeat: -1
                    );
                  },
                ),
                RaisedButton(
                  child: Text("Stop"),
                  onPressed: (){
                    UniversalWidget.find("testWidget").killAllTweens();
                  },
                ),
                RaisedButton(
                  child: Text("Change Color"),
                  onPressed: (){
                    UniversalWidget.find("testWidget").update(
                      duration: 0.5,
                      color: Colors.blueAccent,
                    );
                  },
                ),
                RaisedButton(
                  child: Text("Scale"),
                  onPressed: (){
                    UniversalWidget.find("testWidget").update(
                      duration: 0.8,
                      transformOrigin: Offset(0.5, 0.5),
                      scale: Offset(0.5, 0.5),
                      color: Colors.blueAccent,
                    );
                  },
                ),
                
              ],
            )
          ),

          UniversalWidget(
            name: "testWidget",
            height: 300,
            color: Colors.redAccent,
            onWidgetBuilt: (context){
              print(context.size);
            },
            onWidgetDisposed: (widget){
              print("=> Good bye ${widget.name}!");
            },
            child: Center(child: Text("Hello World")),
          ),
        ],
      ),
    );

    return Scaffold(
      body: example
    );
  }
}

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  universal_widget: ^1.2.5

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:universal_widget/universal_widget.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
76
Health:
Code health derived from static analysis. [more]
99
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
100
Overall:
Weighted score of the above. [more]
88
Learn more about scoring.

We analyzed this package on Aug 21, 2019, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.4.0
  • pana: 0.12.19
  • Flutter: 1.7.8+hotfix.4

Platforms

Detected platforms: Flutter

References Flutter, and has no conflicting libraries.

Health suggestions

Fix lib/tweener.dart. (-0.50 points)

Analysis of lib/tweener.dart reported 1 hint:

line 235 col 9: The class 'Future' was not exported from 'dart:core' until version 2.1, but this code is required to be able to run on earlier versions.

Fix lib/universal_widget.dart. (-0.50 points)

Analysis of lib/universal_widget.dart reported 1 hint:

line 590 col 3: The method '_trace' isn't used.

Format lib/universal_channel.dart.

Run flutter format to format lib/universal_channel.dart.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.0.0-dev.68.0 <3.0.0
flutter 0.0.0
Transitive dependencies
collection 1.14.11 1.14.12
meta 1.1.6 1.1.7
sky_engine 0.0.99
typed_data 1.1.6
vector_math 2.0.8
Dev dependencies
flutter_test