如何知道窗口小部件在视口中是否可见?

如何知道窗口小部件在视口中是否可见?,第1张

如何知道窗口小部件在视口中是否可见?

有了改写的问题,我对您正在尝试做的事情有了更清晰的了解。您有一个小部件列表,并且要根据当前是否在视口中显示这些小部件来决定是否显示浮动 *** 作按钮。

我写了一个基本的例子来说明这一点。我将在下面描述各种元素,但请注意:

  1. 它使用的GlobalKey往往不会过于有效
  2. 它连续运行,并且在滚动过程中每帧都进行一些非最佳计算。

因此,这可能会导致您的应用速度变慢。我将它留给其他人来优化或编写一个更好的答案,该答案使用对渲染树的更好了解来完成相同的 *** 作。

无论如何,这是代码。首先,我将为您提供一种相对较幼稚的方式-直接在变量上使用setState,因为它更简单:

import 'package:flutter/material.dart';import 'package:flutter/rendering.dart';void main() => runApp(new MyApp());class MyApp extends StatefulWidget {  @override  State<StatefulWidget> createState() => new MyAppState();}class MyAppState extends State<MyApp> {  GlobalKey<State> key = new GlobalKey();  double fabOpacity = 1.0;  @override  Widget build(BuildContext context) {    return new MaterialApp(      home: new Scaffold(        appBar: new AppBar(          title: new Text("Scrolling."),        ),        body: NotificationListener<ScrollNotification>(          child: new ListView( itemExtent: 100.0, children: [   ContainerWithBorder(),   ContainerWithBorder(),   ContainerWithBorder(),   ContainerWithBorder(),   ContainerWithBorder(),   ContainerWithBorder(),   ContainerWithBorder(),   ContainerWithBorder(),   ContainerWithBorder(),   ContainerWithBorder(),   ContainerWithBorder(),   new MyObservableWidget(key: key),   ContainerWithBorder(),   ContainerWithBorder(),   ContainerWithBorder(),   ContainerWithBorder(),   ContainerWithBorder(),   ContainerWithBorder(),   ContainerWithBorder(),   ContainerWithBorder() ],          ),          onNotification: (ScrollNotification scroll) { var currentContext = key.currentContext; if (currentContext == null) return false; var renderObject = currentContext.findRenderObject(); RenderAbstractViewport viewport = RenderAbstractViewport.of(renderObject); var offsetToRevealBottom = viewport.getOffsetToReveal(renderObject, 1.0); var offsetToRevealTop = viewport.getOffsetToReveal(renderObject, 0.0); if (offsetToRevealBottom.offset > scroll.metrics.pixels ||     scroll.metrics.pixels > offsetToRevealTop.offset) {   if (fabOpacity != 0.0) {     setState(() {       fabOpacity = 0.0;     });   } } else {   if (fabOpacity == 0.0) {     setState(() {       fabOpacity = 1.0;     });   } } return false;          },        ),        floatingActionButton: new Opacity(          opacity: fabOpacity,          child: new FloatingActionButton( onPressed: () {   print("YAY"); },          ),        ),      ),    );  }}class MyObservableWidget extends StatefulWidget {  const MyObservableWidget({Key key}) : super(key: key);  @override  State<StatefulWidget> createState() => new MyObservableWidgetState();}class MyObservableWidgetState extends State<MyObservableWidget> {  @override  Widget build(BuildContext context) {    return new Container(height: 100.0, color: Colors.green);  }}class ContainerWithBorder extends StatelessWidget {  @override  Widget build(BuildContext context) {    return new Container(      decoration: new BoxDecoration(border: new Border.all(), color: Colors.grey),    );  }}

这样做有几个容易解决的问题-它不会隐藏按钮,而只是使其透明,它​​每次都会渲染整个窗口小部件,并且每帧都要对窗口小部件的位置进行计算

这是一个更优化的版本,不需要时不进行计算。如果您的列表发生更改,则可能需要向其添加更多逻辑(或者您可以每次都进行计算,并且如果性能足够好,则不必担心)。注意它如何使用animationController和AnimatedBuilder来确保每次仅构建相关部分。您还可以通过直接设置animationController

value
并自己进行不透明度计算来摆脱淡入/淡出(即,您可能希望它在开始滚动到视图时变得不透明,这必须考虑到高度)您的对象):

import 'package:flutter/material.dart';import 'package:flutter/rendering.dart';void main() => runApp(new MyApp());class MyApp extends StatefulWidget {  @override  State<StatefulWidget> createState() => new MyAppState();}class MyAppState extends State<MyApp> with TickerProviderStateMixin<MyApp> {  GlobalKey<State> key = new GlobalKey();  bool fabShowing = false;  // non-state-managed variables  AnimationController _controller;  RenderObject _prevRenderObject;  double _offsetToRevealBottom = double.infinity;  double _offsetToRevealTop = double.negativeInfinity;  @override  void initState() {    super.initState();    _controller = new AnimationController(vsync: this, duration: Duration(milliseconds: 300));    _controller.addStatusListener((val) {      if (val == AnimationStatus.dismissed) {        setState(() => fabShowing = false);      }    });  }  @override  Widget build(BuildContext context) {    return new MaterialApp(      home: new Scaffold(        appBar: new AppBar(          title: new Text("Scrolling."),        ),        body: NotificationListener<ScrollNotification>(          child: new ListView( itemExtent: 100.0, children: [   ContainerWithBorder(),   ContainerWithBorder(),   ContainerWithBorder(),   ContainerWithBorder(),   ContainerWithBorder(),   ContainerWithBorder(),   ContainerWithBorder(),   ContainerWithBorder(),   ContainerWithBorder(),   ContainerWithBorder(),   ContainerWithBorder(),   new MyObservableWidget(key: key),   ContainerWithBorder(),   ContainerWithBorder(),   ContainerWithBorder(),   ContainerWithBorder(),   ContainerWithBorder(),   ContainerWithBorder(),   ContainerWithBorder(),   ContainerWithBorder() ],          ),          onNotification: (ScrollNotification scroll) { var currentContext = key.currentContext; if (currentContext == null) return false; var renderObject = currentContext.findRenderObject(); if (renderObject != _prevRenderObject) {   RenderAbstractViewport viewport = RenderAbstractViewport.of(renderObject);   _offsetToRevealBottom = viewport.getOffsetToReveal(renderObject, 1.0).offset;   _offsetToRevealTop = viewport.getOffsetToReveal(renderObject, 0.0).offset; } final offset = scroll.metrics.pixels; if (_offsetToRevealBottom < offset && offset < _offsetToRevealTop) {   if (!fabShowing) setState(() => fabShowing = true);   if (_controller.status != AnimationStatus.forward) {     _controller.forward();   } } else {   if (_controller.status != AnimationStatus.reverse) {     _controller.reverse();   } } return false;          },        ),        floatingActionButton: fabShowing ? new AnimatedBuilder(     child: new FloatingActionButton(       onPressed: () {         print("YAY");       },     ),     builder: (BuildContext context, Widget child) => Opacity(opacity: _controller.value, child: child),     animation: this._controller,   ) : null,      ),    );  }}class MyObservableWidget extends StatefulWidget {  const MyObservableWidget({Key key}) : super(key: key);  @override  State<StatefulWidget> createState() => new MyObservableWidgetState();}class MyObservableWidgetState extends State<MyObservableWidget> {  @override  Widget build(BuildContext context) {    return new Container(height: 100.0, color: Colors.green);  }}class ContainerWithBorder extends StatelessWidget {  @override  Widget build(BuildContext context) {    return new Container(      decoration: new BoxDecoration(border: new Border.all(), color: Colors.grey),    );  }}


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5013562.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-11-14
下一篇 2022-11-14

发表评论

登录后才能评论

评论列表(0条)

保存