Flutter - Скрытие FloatingActionButton

Есть ли встроенный способ во Flutter, чтобы скрыть FloatingActionButton в ListView прокручивая вниз, а затем показывая его при прокрутке вверх?

Ответ 1

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

void main() {
  runApp(new MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(

        primarySwatch: Colors.blue,
      ),
      home: new MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
 }
class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => new _MyHomePageState();
 }

 class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;
  ScrollController _hideButtonController;
  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }
  var _isVisible;
  @override
  initState(){
    super.initState();
    _isVisible = true;
    _hideButtonController = new ScrollController();
    _hideButtonController.addListener((){
      if(_hideButtonController.position.userScrollDirection == ScrollDirection.reverse){
        if(_isVisible == true) {
            /* only set when the previous state is false
             * Less widget rebuilds 
             */
            print("**** ${_isVisible} up"); //Move IO away from setState
            setState((){
              _isVisible = false;
            });
        }
      } else {
        if(_hideButtonController.position.userScrollDirection == ScrollDirection.forward){
          if(_isVisible == false) {
              /* only set when the previous state is false
               * Less widget rebuilds 
               */
               print("**** ${_isVisible} down"); //Move IO away from setState
               setState((){
                 _isVisible = true;
               });
           }
        }
    }});
  }
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: new Center(
        child: new CustomScrollView(
          controller: _hideButtonController,
          shrinkWrap: true,
          slivers: <Widget>[
            new SliverPadding(
              padding: const EdgeInsets.all(20.0),
              sliver: new SliverList(
                delegate: new SliverChildListDelegate(
                  <Widget>[
                    const Text('I\'m dedicating every day to you'),
                    const Text('Domestic life was never quite my style'),
                    const Text('When you smile, you knock me out, I fall apart'),
                    const Text('And I thought I was so smart'),
                    const Text('And I thought I was so smart'),
                    const Text('And I thought I was so smart'),
                    const Text('And I thought I was so smart'),
                    const Text('And I thought I was so smart'),
                    const Text('And I thought I was so smart'),
                    const Text('And I thought I was so smart'),
                    const Text('And I thought I was so smart'),
                    const Text('And I thought I was so smart'),
                    const Text('And I thought I was so smart'),
                    const Text('And I thought I was so smart'),
                    const Text('And I thought I was so smart'),
                    const Text('And I thought I was so smart'),
                    const Text('And I thought I was so smart'),
                    const Text('And I thought I was so smart'),
                    const Text('And I thought I was so smart'),
                    const Text('And I thought I was so smart'),
                    const Text('And I thought I was so smart'),
                    const Text('And I thought I was so smart'),
                    const Text('And I thought I was so smart'),
                    const Text('And I thought I was so smart'),
                    const Text('And I thought I was so smart'),
                    const Text('And I thought I was so smart'),
                    const Text('And I thought I was so smart'),
                    const Text('And I thought I was so smart'),
                    const Text('And I thought I was so smart'),
                    const Text('And I thought I was so smart'),
                    const Text('And I thought I was so smart'),
                    const Text('And I thought I was so smart'),
                    const Text('And I thought I was so smart'),
                    const Text('And I thought I was so smart'),
                    const Text('And I thought I was so smart'),
                    const Text('And I thought I was so smart'),
                    const Text('And I thought I was so smart'),
                    const Text('And I thought I was so smart'),
                    const Text('I realize I am crazy'),   
                  ],
                ),
              ),
            ),
          ],
        )
      ),
      floatingActionButton: new Visibility( 
        visible: _isVisible,
        child: new FloatingActionButton(
          onPressed: _incrementCounter,
          tooltip: 'Increment',
          child: new Icon(Icons.add),
        ),     
      ),
    );
  }
}

Я извиняюсь, если не использовал просмотр списка, так как не знаю, как прокрутить просмотр списка. Я отвечу на другие части вашего вопроса.

Сначала вам нужно создать scrollcontroller, который будет прослушивать scrollPostion события

Если scrollcontroller удается найти направление прокрутки вперед или назад. Вы добавляете состояние, которое устанавливает состояние видимым.

Когда вы рисуете кнопку, вы оборачиваете ее в класс видимости. Вы устанавливаете видимый флаг, и виджет должен игнорировать входные команды.

Изменение: я не могу добавить ссылки на ScrollController, ScrollerPosition, ScrollDirection и Opacity. Я думаю, что вы можете искать его самостоятельно или кто-то еще редактировать в ссылках

Edit2: используйте CopsonRoad или используйте виджет видимости, если вы не хотите неокрашенный виджет в дереве макета

Edit3: в свете новичков, использующих код как есть, я бы обновил код, чтобы поощрять лучшие практики. Используйте видимость вместо непрозрачности. Удалить io из setState. протестировано на Flutter 1.5.4-hotfix.2

Ответ 2

Есть много способов передать это. Позвольте мне перечислить несколько здесь.

  1. Вы можете использовать Visibility, чтобы скрыть/показать FAB.

    floatingActionButton: Visibility(
      child: FloatingActionButton(...),
      visible: false, // set it to false
    )
    
  2. В Dart 2.2 вы можете использовать условие if, например:

    floatingActionButton: Column(
      children: <Widget>[
        if (shouldShow) FloatingActionButton(...), // visible if showShould is true
      ],
    )
    
  3. Вы можете использовать виджет Opacity.

    floatingActionButton: Opacity(
      opacity: shouldShow ? 1 : 0, // visible if showShould is true
      child: FloatingActionButton(...),
    )
    

Ответ 3

Вы можете использовать виджет Visibility для обработки видимости дочернего виджета

образец:

  floatingActionButton:
            Visibility(visible: _visibilityFlag , child: _buildFAB(context)),

Ответ 4

Что мы должны делать, если listview находится внутри FutureBuilder.

Ответ 5

Другой очень хороший способ - AnimatedOpacity

AnimatedOpacity(
          opacity: isEnabled ? 0.0 : 1.0,
          duration: Duration(milliseconds: 1000),
          child: FloatingActionButton(
             onPressed: your_method,
             tooltip: 'Increment',
             child: new Icon(Icons.add),
          ),
        )