Как определить последнее прокручиваемое пользователем направление - PullRequest
0 голосов
/ 22 апреля 2020

У меня есть код ниже, который изменяет непрозрачность fab при прокрутке пользователя вниз или вверх. но для этого я так много раз вызываю метод setState(). Есть ли способ обнаружить последнее прокручиваемое пользователем направление, чтобы я мог вызвать setState() в этот момент только Один раз ? Или я признателен, если вы можете определить новую расширенную функцию для этого.

@override
void initState() {
super.initState();
_controller = ScrollController()
  ..addListener(() {
    upDirection = _controller.position.userScrollDirection == ScrollDirection.forward;
    upDirection = _controller.position.userScrollDirection == ScrollDirection.reverse;


      if (upDirection)
        setState(() {
          _scrolled = 0.5;
          flag = false;
        });
      else if (!upDirection) {
        setState(() {
          _scrolled = 1.0;
        });
        flag = false;
      }

  });
}

А вот список

    return Scaffold(
    body:
    SingleChildScrollView(
      controller: _controller,
      child: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Container(),
            Container(),
            Container(),
            Container(),
            Container(),
            Container(),
          ],
        ),
      ),
    ),

  floatingActionButton: AnimatedOpacity(
    opacity: _scrolled,
    duration: Duration(milliseconds: 100),
    child: FloatingActionButton(
      onPressed: (){},
      child: Icon(Icons.settings),
          ),
        ),
  floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
);

Ответы [ 2 ]

2 голосов
/ 22 апреля 2020

Проблема в том, что добавленный слушатель будет вызываться каждый раз, когда на контроллере появляется новое событие. Вот почему ваш setState неоднократно вызывается.

Вы можете использовать флаги для предотвращения повторного вызова setState.

Рабочий код :

void initState() {
    ScrollDirection _lastScrollDirection; // <---- Notice the new variable here.
    _controller = ScrollController();

    _controller.addListener(() {
      if (_lastScrollDirection != _controller.position.userScrollDirection) {
        _lastScrollDirection = _controller.position.userScrollDirection;

        setState(() {
          //You can set whatever you want here. 
          //It will only get called once when user changes direction.
        });

        print('Scroll direction changed --> $_lastScrollDirection');
      }
    });
    super.initState();
  }

DEMO:

enter image description here

0 голосов
/ 22 апреля 2020

Благодаря Omer Celik полный код может быть примерно таким, как показано ниже, и вы можете настроить его:

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

void main() => runApp(MaterialApp());

class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MainPage(),
    );
  }
}

class MainPage extends StatefulWidget {

  @override
  _MainPageState createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {

  ScrollController _controller;
  double _scrolled = 1.0;


  @override
  void initState() {
    ScrollDirection _lastScrollDirection;
    _controller = ScrollController();

    _controller.addListener(() {
      if (_lastScrollDirection != _controller.position.userScrollDirection) {
        _lastScrollDirection = _controller.position.userScrollDirection;


          if (_lastScrollDirection == ScrollDirection.forward) {
            setState(() {
            _scrolled = 1.0;
            });
          }
          else if (_lastScrollDirection == ScrollDirection.reverse) {
            setState(() {
              _scrolled = 0.5;
            });
          }
      }
    });
    super.initState();
  }

  @override
  Widget build(BuildContext context) {

    return Scaffold(
        body:

        ListView.builder(
          controller: _controller,
          physics: BouncingScrollPhysics(),
          padding: const EdgeInsets.all(16.0),
          itemCount: 50,
          itemBuilder: _buildItem,
        ),


      floatingActionButton: AnimatedOpacity(
        opacity: _scrolled,
        duration: Duration(milliseconds: 700),
        child: FloatingActionButton(
          onPressed: (){},
          child: Icon(Icons.settings),
        ),
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
    );
  }
  Widget _buildItem(BuildContext context, int index) {
    return Container(
      child: Text(index.toString()),
    );
  }
}
...