Flutter: Best way to change a widget opacity and color on scroll Flutter: Best way to change a widget opacity and color on scroll flutter flutter

Flutter: Best way to change a widget opacity and color on scroll


i think the best approach Will be using AnimatedBuilder and you will see that first container in body will not changed its color because widget state have not changedand the result :

enter image description here

code:

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: () {},                      ),                    ],                  ),                ),              ),            ],          ),        ),      ),    );  }}


In this little example I do the following: I change the opacity of my AnimatedOpacity depending on some conditions, namely if its offset is either greater or less than 100 pixels from the top to the bottom of the screen. The mentioned offset I obtain it with the help of RenderBox and GlobalKey. This validations and events happen within the function passed to my scrollListener. That means that they get triggered every time I scroll. Here is the full code.

import 'package:flutter/material.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> {  ScrollController _scrollController;  GlobalKey widgetKey = GlobalKey();  Offset widgetOffset;  double _currentPosition;  double opacity = 1;  @override  void initState() {    _scrollController = ScrollController();    _scrollController.addListener(_scrollListener);    super.initState();  }  _scrollListener() {    print('scrolling');    RenderBox textFieldRenderBox = widgetKey.currentContext.findRenderObject();    widgetOffset = textFieldRenderBox.localToGlobal(Offset.zero);    _currentPosition = widgetOffset.dy;    print(        "widget position: $_currentPosition against: 100");    if (100 > _currentPosition && _currentPosition > 1) {      setState(() {        opacity = _currentPosition / 100;      });    } else if (_currentPosition > 100 && opacity != 1) {      opacity = 1;    }    else if (_currentPosition < 0 && opacity != 0) {      opacity = 0;    }    print("opacity is: $opacity");  }  @override  Widget build(BuildContext context) {    return Scaffold(      body: SingleChildScrollView(          controller: _scrollController,          child: Column(            crossAxisAlignment: CrossAxisAlignment.stretch,            children: [              Container(                margin: EdgeInsets.only(bottom: 50),                height: 100,                width: 100,                color: Colors.red,              ),              Container(                margin: EdgeInsets.only(bottom: 50),                height: 100,                width: 100,                color: Colors.red,              ),              AnimatedOpacity(                key: widgetKey,                duration: Duration(milliseconds: 1),                opacity: opacity,                child: Center(                  child: Container(                    margin: EdgeInsets.only(bottom: 50),                    height: 100,                    width: 100,                    color: Colors.purpleAccent,                  ),                ),              ),              Container(                margin: EdgeInsets.only(bottom: 50),                height: 100,                width: 100,                color: Colors.red,              ),              Container(                margin: EdgeInsets.only(bottom: 50),                height: 100,                width: 100,                color: Colors.red,              ),              Container(                margin: EdgeInsets.only(bottom: 50),                height: 100,                width: 100,                color: Colors.red,              ),              Container(                margin: EdgeInsets.only(bottom: 50),                height: 100,                width: 100,                color: Colors.teal,              ),              Container(                margin: EdgeInsets.only(bottom: 50),                height: 100,                width: 100,                color: Colors.teal,              ),              Container(                margin: EdgeInsets.only(bottom: 50),                height: 100,                width: 100,                color: Colors.teal,              ),            ],          )),    );  }}

Scroll and animation behavior