代码之家  ›  专栏  ›  技术社区  ›  woshitom

颤振:更改滚动窗口小部件不透明度和颜色的最佳方法

  •  0
  • woshitom  · 技术社区  · 5 年前

    我的目标是在用户向下滚动时更改appbar的颜色和不透明度。

    我的逻辑是:

    • 滚动偏移=0:appbar为红色,不透明度为1
    • 0<滚动偏移<40:appbar为蓝色,不透明度为0.4
    • 40<=滚动偏移:appbar为蓝色,不透明度与滚动偏移成比例

    我想出了以下代码:

    import 'package:flutter/material.dart';
    import 'package:gradient_app_bar/gradient_app_bar.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: MyHomePage(title: 'Flutter Demo Home Page'),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      MyHomePage({Key key, this.title}) : super(key: key);
    
      final String title;
    
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      var _gradientColor1 = Colors.red[400];
      var _gradientColor2 = Colors.red[800];
      ScrollController _scrollViewController;
    
      void changeColor(){
        if((_scrollViewController.offset == 0) && (_gradientColor1 != Colors.red[400])){
          setState(() {
            _gradientColor1 = Colors.red[400];
            _gradientColor2 = Colors.red[800];
          });
        }else if((_scrollViewController.offset <= 40) && (_gradientColor1 != Color.fromRGBO(66,165,245 ,0.4))){
          setState(() {
            _gradientColor1 = Color.fromRGBO(66,165,245 ,0.4);
            _gradientColor2 = Color.fromRGBO(21,101,192 ,0.4);
          });
        }else if((_scrollViewController.offset <= 100) && (_scrollViewController.offset > 40)){
          var opacity = _scrollViewController.offset/100;
          setState(() {
            _gradientColor1 = Color.fromRGBO(66,165,245 ,opacity);
            _gradientColor2 = Color.fromRGBO(21,101,192 ,opacity);
          });
        }
      }
    
      @override
      void initState() {
        _scrollViewController = ScrollController(initialScrollOffset: 0.0);
        _scrollViewController.addListener(changeColor);
      }
    
      @override
      Widget build(BuildContext context) {
    
        return Scaffold(
          appBar: GradientAppBar(
            backgroundColorStart: _gradientColor1,
            backgroundColorEnd: _gradientColor2,
            elevation: 0,
          ),
          body: SingleChildScrollView(
            controller: _scrollViewController,
            child: Column(
              children: <Widget>[
                Container(color: Colors.red, height: 400,),
                Container(color: Colors.purple, height: 400,),
              ],
            ),
          ),
        );
      }
    }
    

    它可以按预期工作,但对于一个更复杂的用户界面,它会变得滞后。 在我的示例中,我使用GradientAppbar: https://github.com/joostlek/GradientAppBar

    0 回复  |  直到 5 年前
        1
  •  3
  •   Mortada Jafar    5 年前

    我认为最好的方法是 AnimatedBuilder 您将看到主体中的第一个容器不会更改其颜色,因为小部件状态没有更改 结果是:

    enter image description here

    代码:

    import 'dart:math';
    import 'package:flutter/material.dart';
    
    class ProductDetails extends StatefulWidget {
      @override
      _ProductDetailsState createState() => _ProductDetailsState();
    }
    
    class _ProductDetailsState extends State<ProductDetails>
        with TickerProviderStateMixin {
      AnimationController _ColorAnimationController;
      AnimationController _TextAnimationController;
      Animation _colorTween, _iconColorTween;
      Animation<Offset> _transTween;
    
      @override
      void initState() {
        _ColorAnimationController =
            AnimationController(vsync: this, duration: Duration(seconds: 0));
        _colorTween = ColorTween(begin: Colors.transparent, end: Color(0xFFee4c4f))
            .animate(_ColorAnimationController);
        _iconColorTween = ColorTween(begin: Colors.grey, end: Colors.white)
            .animate(_ColorAnimationController);
    
    
        _TextAnimationController =
            AnimationController(vsync: this, duration: Duration(seconds: 0));
    
        _transTween = Tween(begin: Offset(-10, 40), end: Offset(-10, 0))
            .animate(_TextAnimationController);
    
        super.initState();
      }
    
      bool _scrollListener(ScrollNotification scrollInfo) {
        if (scrollInfo.metrics.axis == Axis.vertical) {
          _ColorAnimationController.animateTo(scrollInfo.metrics.pixels / 350);
    
          _TextAnimationController.animateTo(
              (scrollInfo.metrics.pixels - 350) / 50);
          return true;
        }
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          backgroundColor: Color(0xFFEEEEEE),
          body: NotificationListener<ScrollNotification>(
            onNotification: _scrollListener,
            child: Container(
              height: double.infinity,
              child: Stack(
                children: <Widget>[
                  SingleChildScrollView(
                    child: Column(
                      children: <Widget>[
                        Container(
                          height: 150,
                          color:
                              Color((Random().nextDouble() * 0xFFFFFF).toInt() << 0)
                                  .withOpacity(1),
                          width: 250,
                        ),
                        Container(
                          height: 150,
                          color: Colors.pink,
                          width: 250,
                        ),
                        Container(
                          height: 150,
                          color: Colors.deepOrange,
                          width: 250,
                        ),
                        Container(
                          height: 150,
                          color: Colors.red,
                          width: 250,
                        ),
                        Container(
                          height: 150,
                          color: Colors.white70,
                          width: 250,
                        ),
                      ],
                    ),
                  ),
                  Container(
                    height: 80,
                    child: AnimatedBuilder(
                      animation: _ColorAnimationController,
                      builder: (context, child) => AppBar(
                        backgroundColor: _colorTween.value,
                        elevation: 0,
                        titleSpacing: 0.0,
                        title: Transform.translate(
                          offset: _transTween.value,
                          child: Text(
                            "اسم کالا اینجا",
                            style: TextStyle(
                                color: Colors.white,
                                fontWeight: FontWeight.bold,
                                fontSize: 16),
                          ),
                        ),
                        iconTheme: IconThemeData(
                          color: _iconColorTween.value,
                        ),
                        actions: <Widget>[
                          IconButton(
                            icon: Icon(
                              Icons.local_grocery_store,
                            ),
                            onPressed: () {
    //                          Navigator.of(context).push(TutorialOverlay());
                            },
                          ),
                          IconButton(
                            icon: Icon(
                              Icons.more_vert,
                            ),
                            onPressed: () {},
                          ),
                        ],
                      ),
                    ),
                  ),
                ],
              ),
            ),
          ),
        );
      }
    }