Как вызвать событие, когда виджет достигает определенного положения экрана?

#flutter

#трепетание

Вопрос:

Я хочу, чтобы событие запускалось, когда виджет находится в определенном положении экрана. Предположим, например, что у нас есть Container виджет, который все еще не виден. Он находится в определенном положении прокручиваемого Scaffold объекта, высота тела которого достаточна для прокрутки. Мы начинаем прокручивать, и когда виджет становится видимым и, скажем, достигает середины экрана, это запускает событие. Другими словами, событие должно запускаться только в том случае, если виджет находится в определенном положении. Возможно, чего-то подобного можно было бы достичь с помощью a ScrollController , но мне интересно, могут ли быть другие подходы к этому.

Комментарии:

1. Вы имеете в виду, что хотите запустить функцию, когда виджет виден в списке?

2. Я думаю, что да. Просто чтобы быть уверенным, что вы имеете в виду под «списком»?

3. Но не только видимый, но и «в определенной позиции на экране»

4. для определенного положения не уверен, но для видимости вы можете использовать виджет детектора видимости

5. Отлично. Это уже хорошая информация. Проверяю это.

Ответ №1:

Итак, я начал небольшое исследование и обнаружил, что то, чего я хотел, может быть достигнуто с помощью объектов RenderBox. Используя их, вы можете получить размер (типа Size ) или положение (типа Offset ). Как только они у вас появятся, вызвать событие будет очень легко. В этом случае я привел простой пример, в котором я печатаю инструкцию только в том случае, если положение контейнера превышает заданное смещение по оси y (скажем, определенный процент от высоты экрана, который вы можете получить с MediaQuery.of(context).size.height помощью). Я установил свой лимит на 75% высоты экрана. Событие вызывается при нажатии кнопки FloatingActionButton . Если вы хотите протестировать его, прокрутите немного, а затем нажмите кнопку. Прокрутите еще раз, проверьте его еще раз и так далее. Вы увидите, что событие срабатывает при превышении предела.

Я добился этого с помощью следующей статьи: https://medium.com/@diegoveloper/flutter-widget-size-and-position-b0a9ffed9407

Вот мой пример:

 import 'package:flutter/material.dart';

class Example extends StatefulWidget {
  @override
  _ExampleState createState() => _ExampleState();
}

class _ExampleState extends State<Example> {
  GlobalKey _keyRed = GlobalKey();
  GlobalKey _keyPurple = GlobalKey();
  GlobalKey _keyGreen = GlobalKey();
  Offset positionGreen;

  _getSizes(){
    RenderBox renderBoxRed = _keyRed.currentContext.findRenderObject();
    Size sizeRed = renderBoxRed.size;
    print("red size is: $sizeRed");

    RenderBox renderBoxPurple = _keyRed.currentContext.findRenderObject();
    Size sizePurple = renderBoxPurple.size;
    print("purple size is: $sizePurple");


    RenderBox renderBoxGreen = _keyGreen.currentContext.findRenderObject();
    Size sizeGreen = renderBoxGreen.size;
    print("green size is: $sizeGreen");
  }

  _getPositions(){
    final RenderBox renderBoxRed = _keyRed.currentContext.findRenderObject();
    final positionRed = renderBoxRed.localToGlobal(Offset.zero);
    print("red position is: $positionRed");

    final RenderBox renderBoxPurple = _keyPurple.currentContext.findRenderObject();
    final positionPurple = renderBoxPurple.localToGlobal(Offset.zero);
    print("purple position is: $positionPurple");

    final RenderBox renderBoxGreen = _keyGreen.currentContext.findRenderObject();
    positionGreen = renderBoxGreen.localToGlobal(Offset.zero);
    print("green position is: $positionGreen");
  }


  @override
  Widget build(BuildContext context) {
    double limit = MediaQuery.of(context).size.height*.75;

    return Scaffold(
      floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
      floatingActionButton: FloatingActionButton(
        backgroundColor: Colors.orange,
        onPressed: (){
          _getSizes();
          _getPositions();

          print("npositionGreen in dy is ${positionGreen.dy} and limit is $limit");

          if(positionGreen.dy > limit){
            print("screen resizes");
          } else {
            print("screen doesn't resize");
          }

        },
      ),
      body: SingleChildScrollView(
        child: Column(
          children: [
            Container(
              height: 400,
              key: _keyRed,
            color: Colors.red,
            ),
            Container(
              height: 600,
              key: _keyPurple,
              color: Colors.purple,
            ),
            Container(
              height: 800,
              key: _keyGreen,
              color: Colors.green,
            ),
          ],
        ),
      ),
    );
  }
}