2017-08-16 326 views
1

我試圖在CustomPainter中創建一個動畫,其中動畫從底部開始向上,但是從頂部開始。Flutter - 在CustomPainter中從下到上的動畫

當點擊FloatActionButton矩形應該上升到屏幕的最大高度,並且當再次敲擊回到最小大小。

我可以得到屏幕的大小,但我無法從底部向上插入此動畫。你可以幫我嗎?

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; 
    } 
} 

回答

2

您可以使用AnimatedBuilder做到這一點。另外,請確保您提供了shouldRepaint的工作實施。您的upDown成員變量應該是State的成員,而不是build函數的一部分。

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; 
    } 
} 
+0

感謝您的幫助,爲GIF藍色動畫從上往下開始,如何開始從下往上藍色的動畫? – rafaelcb21

+0

我已經改變了你的代碼並重寫了這個問題,因爲我試圖在代碼的多個部分中播放,並且我無法在底部啓動動畫 – rafaelcb21

+1

我編輯了我的答案,您只需要將您的'drawRect'調用改爲'new Rect.fromLTRB(0.0,size.height - _rectHeight,this._width,size.height)' –