有了改写的问题,我对您正在尝试做的事情有了更清晰的了解。您有一个小部件列表,并且要根据当前是否在视口中显示这些小部件来决定是否显示浮动 *** 作按钮。
我写了一个基本的例子来说明这一点。我将在下面描述各种元素,但请注意:
- 它使用的GlobalKey往往不会过于有效
- 它连续运行,并且在滚动过程中每帧都进行一些非最佳计算。
因此,这可能会导致您的应用速度变慢。我将它留给其他人来优化或编写一个更好的答案,该答案使用对渲染树的更好了解来完成相同的 *** 作。
无论如何,这是代码。首先,我将为您提供一种相对较幼稚的方式-直接在变量上使用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), ); }}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)