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