rafaelcb21 rafaelcb21 - 1 month ago 8
Dart Question

Flutter - Animation from bottom to top in CustomPainter

I'm trying to create an animation in a

CustomPainter
in which the animation starts from the bottom to up, but it's starting at the top.

When clicking on the
FloatActionButton
the rectangle should rise to the maximum height of the screen, and when tap again go back to the minimum size.

I can get the size of the screen but I'm not able to insert this animation from the bottom to up. can you help me?

enter image description here

import 'package:flutter/material.dart';
import 'dart:ui' as ui;

void main() {
runApp(new MaterialApp(home: new HomePage()));
}

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

class HomePageState extends State<HomePage> with TickerProviderStateMixin {
AnimationController _controller;
Animation<double> _animation;
bool upDown = true;

@override
void initState() {
_controller = new AnimationController(
vsync: this,
duration: const Duration(milliseconds: 180),
);

_animation = new CurvedAnimation(
parent: _controller,
curve: new Interval(0.0, 1.0, curve: Curves.linear),
);
}

@override
Widget build(BuildContext context) {
final ui.Size logicalSize = MediaQuery.of(context).size;
final double _width = logicalSize.width;
final double _height = logicalSize.height;

void _up(){
setState((){
if(upDown) {
upDown = false;
_controller.forward(from: 0.0);
} else {
upDown = true;
_controller.reverse(from: 1.0);
}
});
}

return new Scaffold(
body: new Stack(
children: <Widget>[
new Positioned(
bottom: 0.0,
child: new AnimatedBuilder(
animation: _animation,
builder: (BuildContext context, Widget child) {
return new Container(
height: _height,
child: new CustomPaint(
painter: new Sky(_width, _height * _animation.value),
//child: new Text('$_height '+ _animation.value.toString()),
),
);
},
),
),
new Positioned(
bottom: 16.0,
right: 16.0,
child: new FloatingActionButton(
backgroundColor: new Color(0xFFE57373),
child: new Icon(Icons.add),
onPressed: (){
_up();
},
)
)
]
)
);
}
}

class Sky extends CustomPainter {
final double _width;
double _rectHeight;

Sky(this._width, this._rectHeight);

@override
void paint(Canvas canvas, Size size) {
canvas.drawRect(
new Rect.fromLTRB(
0.0, 0.0, this._width, _rectHeight
),
new Paint()..color = new Color(0xFF0099FF),
);
}

@override
bool shouldRepaint(Sky oldDelegate) {
return _width != oldDelegate._width || _rectHeight != oldDelegate._rectHeight;
}
}

Answer Source

You can use an AnimatedBuilder to do this. Also, make sure that you provide a working implementation of shouldRepaint. Your upDown member variable should be a member of the State rather than part of the build function.

screenshot

import 'package:flutter/material.dart';
import 'dart:ui' as ui;

void main() {
  runApp(new MaterialApp(home: new HomePage()));
}

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

class HomePageState extends State<HomePage> with TickerProviderStateMixin {
  AnimationController _controller;
  Animation<double> _animation;
  bool upDown = true;

  @override
  void initState() {
    _controller = new AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 180),
    );

    _animation = new CurvedAnimation(
      parent: _controller,
      curve: new Interval(0.0, 1.0, curve: Curves.linear),
    );
  }

  @override
  Widget build(BuildContext context) {
    final ui.Size logicalSize = MediaQuery.of(context).size;
    final double _width = logicalSize.width;
    final double _height = logicalSize.height;

    void _up(){
      setState((){
        if(upDown) {
          upDown = false;
          _controller.forward(from: 0.0);
        } else {
          upDown = true;
          _controller.reverse(from: 1.0);
        }
      });
    }

    return new Scaffold(
        body: new Stack(
            children: <Widget>[
              new Positioned(
                  bottom: 0.0,
                  child: new AnimatedBuilder(
                    animation: _animation,
                    builder: (BuildContext context, Widget child) {
                    return new Container(
                      height: _height,
                      child: new CustomPaint(
                        painter: new Sky(_width, _height * _animation.value),
                      ),
                    );
                  },
                ),
              ),
              new Positioned(
                bottom: 16.0,
                right: 16.0,
                child: new FloatingActionButton(
                  backgroundColor: new Color(0xFFE57373),
                  child: new Icon(Icons.add),
                  onPressed: (){
                    _up();
                  },
                )
              )
            ]
        )
    );
  }
}

class Sky extends CustomPainter {
  final double _width;
  double _rectHeight;

  Sky(this._width, this._rectHeight);

  @override
  void paint(Canvas canvas, Size size) {
    canvas.drawRect(
      new Rect.fromLTRB(
          0.0, size.height - _rectHeight, this._width, size.height
      ),
      new Paint()..color = new Color(0xFF0099FF),
    );
  }

  @override
  bool shouldRepaint(Sky oldDelegate) {
    return _width != oldDelegate._width || _rectHeight != oldDelegate._rectHeight;
  }
}