首页 > 解决方案 > 当小部件到达屏幕的某个位置时如何触发事件?

问题描述

我希望在小部件位于屏幕的某个位置时触发一个事件。例如,假设我们有一个Container仍然不可见的 Widget。它位于可滚动的某个位置,Scaffold其主体的高度足以必须滚动。我们开始滚动,当小部件可见并且到达屏幕中间时,这会触发事件。换句话说,只有当 Widget 处于某个位置时才应该触发事件。也许类似的东西可以用 a 来实现,ScrollController但我想知道是否有其他方法可以做到这一点。

标签: flutter

解决方案


所以我开始了一点研究,我发现我想要的可以用 RenderBox 对象来实现。通过使用它们,您可以获得(类型)的大小Size或位置(类型Offset)。一旦拥有它们,就很容易触发事件。在这种情况下,我做了一个简单的示例,仅当 Container 的位置超过 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,
            ),
          ],
        ),
      ),
    );
  }
}

推荐阅读