flutter悬浮按钮案例


能滑动隐藏的悬浮按钮

https://www.jianshu.com/p/18f6f6a532ec

 

Flutter 可随意拖动按钮

https://www.jianshu.com/p/167ddc5660dc

 

flutter 滚动隐藏悬浮按钮

 
Untitled.gif
  • 实现思路,当开始滚动的时候,执行动画让中间的悬浮按钮向右移动。当滚动结束的时候复位动画

监听滚动的方法有两种

第一种 NotificationListener 在widget树中,子widget滚动时会向上发送notification,通过NotificationListener可以监控到该notification。NotificationListener也是一个widget,可以将被监控的widget放入其child内。
NotificationListener
const NotificationListener({ Key key, @required this.child, 被监控的子widget树 this.onNotification, 监控到notification后的回调方法。 }) 

onNotification(ScrollNotification notification) , 此方法需要一个返回值,表示是否拦截住notification,如果是true,那么notifcation到此为止;如果是false,那么notification会继续向更外层widget传递。参数ScrollNotification包含了监听到的信息。
ScrollNotification

ScrollNotification({ @required this.metrics, 所有信息都在这里存储 ScrollMetrics @required this.context, }); 
第二种是通过ScrollController来监听

ScrollController 常用方法

  • addListener 滑动监听方法,在initState中监听
  • _scrollController.position.pixels 滑动距离
  • _scrollController.offset 滚动的偏移量
  • _scrollController.position.maxScrollExtent 最大可滑动距离,滑动组件内容长度
  • -_scrollController.position.minScrollExtent 最小可滑动距离,0
  • _scrollController.position.viewportDimension 滑动视图所占长度
  • _scrollController.dispose() 销毁监听,在dispose方法中调用
  • _scrollController.jumpTo 控制滑动组件的滑动距离,无动画
  • _scrollController.animateTo(10); 控制滑动组件的滑动距离,有动画
  • _scrollController.position.jumpTo 同上
  • _scrollController.position.animateTo 同上
  controller.addListener((){
      print(controller......)
   });

下面我们开始实现我们的效果

第一步

我们使用Scaffold floatingActionButton 来添加我们widget ,配合 floatingActionButtonLocation 设置下位置,

Scaffold( appBar: PreferredSize( child: _getAppBar(), preferredSize: Size(double.infinity,44), ), backgroundColor: Colors.white, floatingActionButton: AnimationWidget(), floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, body: ..., ); 

创建悬浮按钮 AnimationWidget

import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; //状态管理 class NotifierAnimation extends ChangeNotifier{ //回调方法 ValueChanged stopValueChanged; void animationStartAndEnd(isStop){ stopValueChanged(isStop); notifyListeners(); } } class AnimationWidget extends StatefulWidget { @override _AnimationWidgetState createState() => _AnimationWidgetState(); } class _AnimationWidgetState extends State<AnimationWidget> with SingleTickerProviderStateMixin{ AnimationController _animationController; Animation<Offset> _animation; @override void initState() { super.initState(); //实例化动画 _animationController = new AnimationController(vsync: this,duration: new Duration(milliseconds: 240)); _animation = Tween(begin: Offset(0,0), end: Offset(0.8, 0)).animate(_animationController); } @override void didChangeDependencies() { //Provider 状态管理 得到回调如果true 那就是开始动画 final counter = Provider.of<NotifierAnimation>(context); if (counter !=null) { Provider.of<NotifierAnimation>(context,listen: false).stopValueChanged=((v){ if(v){ //开始动画 _animationController.forward(); }else{ //复位动画 _animationController.reverse(); } }); } } @override Widget build(BuildContext context) { return Align( alignment: Alignment.centerRight, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ SizedBox(height: 100), SlideTransition( child: Container( width: 50, height: 50, decoration: BoxDecoration( color: Colors.red ), ),position: _animation,), ], ) ); } } 

这么这里使用到的是NotificationListener,因为ScrollController不能得到什么时候开始滚动什么时候结束滚动,
第二步 创建 NotificationListener child就是你的滚动视图 可以是 ListView CustomScrollView,也可以包裹 三方插件 SmartRefresher

NotificationListener<ScrollNotification>( onNotification: (notification){ if( notification.depth == 0){ switch (notification.runtimeType){ case ScrollStartNotification:{ //开始滚动 执行动画 Provider.of<NotifierAnimation>(context,listen: false).animationStartAndEnd(true); } break; case ScrollUpdateNotification: print("正在滚动") ; break; case ScrollEndNotification:{ print("滚动停止"); //滚动停止 结束动画 复位 Provider.of<NotifierAnimation>(context,listen: false).animationStartAndEnd(false); } break; case OverscrollNotification: print("滚动到边界"); break; } } return; }, child: ListView() ); 
我们这里通过三方插件Provider状态共享来执行动画 ,当然了你也可以使用其他方法,无非就是一个回调,调用我们封装好的widget 来执行动画

Main

//Provider void main() { NotifierAnimation notifierAnimation = NotifierAnimation(); runApp(MultiProvider( providers: [ ChangeNotifierProvider.value(value: notifierAnimation), ], child: MyApp(), )); }


作者:Faith_K
链接:https://www.jianshu.com/p/18f6f6a532ec
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 

Flutter 可随意拖动按钮

停心阁
0.0752020.03.31 13:38:55字数 36阅读 186

实现这个功能主要用到了Stack、Positioned、Draggable等几个组件
直接上代码:

1.main.dart文件

import 'package:flutter/material.dart'; import 'FloatBtn.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: FloatBtn(), ); } } 
  1. FloatBtn.dart 文件
import 'package:flutter/material.dart'; class FloatBtn extends StatefulWidget { FloatBtn({Key key}) : super(key: key); @override _FloatBtnState createState() => _FloatBtnState(); } class _FloatBtnState extends State<FloatBtn> { Offset offsetA = Offset(20, kToolbarHeight + 100);//按钮的初始位置 @override Widget build(BuildContext context) { final size = MediaQuery.of(context).size; final width = size.width; final height = size.height; return Scaffold( body: Stack( children:<Widget>[ Positioned( left: offsetA.dx, top: offsetA.dy, child: Draggable( //创建可以被拖动的Widget child: FloatingActionButton( tooltip: 'Increment', child: Icon(Icons.add), onPressed: () {}, ), //拖动过程中的Widget feedback: FloatingActionButton( tooltip: 'Increment', child: Icon(Icons.add), onPressed: () {}, ), //拖动过程中,在原来位置停留的Widget,设定这个可以保留原本位置的残影,如果不需要可以直接设置为Container() childWhenDragging: Container(), // FloatingActionButton( // tooltip: 'Increment', // child: Icon(Icons.add), onPressed: () {}, // ), //拖动结束后的Widget onDraggableCanceled: (Velocity velocity, Offset offset) { // 计算组件可移动范围 更新位置信息 setState(() { var x = offset.dx; var y = offset.dy; if(offset.dx<0){ x = 20; } if(offset.dx>375){ x = 335; } if(offset.dy<kBottomNavigationBarHeight){ y = kBottomNavigationBarHeight; } if(offset.dy>height-100){ y = height - 100; } offsetA = Offset(x, y); }); } ) ) ] ), ); } }

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM