Флаттер: лучший способ изменить прозрачность и цвет виджета при прокрутке - PullRequest
0 голосов
/ 17 февраля 2019

Моя цель - изменить цвет и непрозрачность панели приложения при прокрутке пользователя вниз.

Моя логика:

  • scroll offset = 0: панель приложения красного цвета с непрозрачностью= 1
  • 0 <смещение прокрутки <40: панель приложения синего цвета с непрозрачностью = 0,4 </li>
  • 40 <= смещение прокрутки: панель приложения синего цвета с непрозрачностью, пропорциональной смещению прокрутки </li>

Я придумал следующий код:

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

1 Ответ

0 голосов
/ 21 июля 2019

я думаю, что лучший подход будет использовать 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: () {},
                      ),
                    ],
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
...