欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

flutter 實現(xiàn)點擊下拉欄微信右上角彈出窗功能

 更新時間:2021年05月21日 15:26:10   作者:Mannaoz  
這篇文章主要介紹了flutter 實現(xiàn)彈出窗點擊下拉欄微信右上角彈出窗功能,這段代碼使用的是PopupRoute這個路由類進行實現(xiàn) 的,分步驟通過實例代碼講解的非常詳細,需要的朋友可以參考下

先看效果實現(xiàn)

需求分析

這個是使用 PopupRoute這個路由類進行實現(xiàn)

大概原理就是利用PopupRpute這個類進行改造,然后自定義一個頁面,頁面內(nèi)鑲嵌一個動畫類,用來實現(xiàn)縮放動畫

大概分為三部分,PopupRoute改造,彈出頁面設(shè)置,動畫類設(shè)置。

為什么選擇PopupRoute?

可以鑲嵌在flutter本身的路由管理之中

也就是邏輯操作都是正常的頁面管理,可以手動管理,也可以用路由返回直接關(guān)掉,不會影響原有頁面和布局

第一步,改造PopupRoute類

import 'package:flutter/material.dart';

class Popup extends PopupRoute {
  final Duration _duration = Duration(milliseconds: 300);
  Widget child;

  Popup({@required this.child});

  @override
  Color get barrierColor => null;

  @override
  bool get barrierDismissible => true;

  @override
  String get barrierLabel => null;

  @override
  Widget buildPage(BuildContext context, Animation<double> animation,
      Animation<double> secondaryAnimation) {
    return child;
  }

  @override
  Duration get transitionDuration => _duration;
}

第二步,新建一個彈窗頁面

頁面分兩部分

一個是頁面的背景,一個是頁面的內(nèi)容

注意,彈窗動畫的代碼在下方

class Model extends StatefulWidget {
  final double left; //距離左邊位置 彈窗的x軸定位
  final double top; //距離上面位置 彈窗的y軸定位
  final bool otherClose; //點擊背景關(guān)閉頁面
  final Widget child; //傳入彈窗的樣式
  final Function fun; // 把關(guān)閉的函數(shù)返回給父組件 參考vue的$emit
  final Offset offset; // 彈窗動畫的起點

  Model({
    @required this.child,
    this.left = 0,
    this.top = 0,
    this.otherClose = false,
    this.fun,
    this.offset,
  });


  @override
  _ModelState createState() => _ModelState();
}


class _ModelState extends State<Model> {
  AnimationController animateController;


  @override
  Widget build(BuildContext context) {
    return Material(
      color: Colors.transparent,
      child: Stack(
        children: <Widget>[
          Positioned(
            child: GestureDetector(
              child: Container(
                width: MediaQuery.of(context).size.width,
                height: MediaQuery.of(context).size.height,
                color: Colors.transparent,
              ),
              onTap: () async {
                if (widget.otherClose) {
                } else {
                  closeModel();
                }
              },
            ),
          ),
          Positioned(
            /// 這個是彈窗動畫 在下方,我把他分離 防止太長
            child: ZoomInOffset(
              duration: Duration(milliseconds: 180),
              offset: widget.offset,
              controller: (controller) {
                animateController = controller;
                widget.fun(closeModel);
              },
              child: widget.child,
            ),
            left: widget.left,
            top: widget.top,
          ),
        ],
      ),
    );
  }


  ///關(guān)閉頁面動畫
  Future closeModel() async {
    await animateController.reverse();
    Navigator.pop(context);
  }
}

動畫代碼

我是直接復制animate_do:^2.0.0 這個版本的ZoomIn的動畫類

這個插件本身就是依賴flutter 自帶的動畫來完成的,很簡潔,使用很方便,不過默認構(gòu)造的時候沒有動畫的啟動方向,默認是最中心。但是可以添加個參數(shù),我把源碼復制出來自己改造了一下。這個類在構(gòu)造的時候有個controller 參數(shù),類型的函數(shù),帶一個AnimationController的參數(shù)把控制器通過函數(shù)傳遞出去到Model類,可以在Model類里面進行控制動畫開啟和關(guān)閉后續(xù)我在Model類里面把動畫關(guān)閉和返回退出PopupRoute層封裝成一個函數(shù) 傳遞到Model里面的fun參數(shù)里面返回出去可以在最外部進行組件通信,進而控制這些子組件

import 'package:flutter/material.dart';

class ZoomInOffset extends StatefulWidget {
  final Key key;
  final Widget child;
  final Duration duration;
  final Duration delay;


  ///把控制器通過函數(shù)傳遞出去,可以在父組件進行控制
  final Function(AnimationController) controller;
  final bool manualTrigger;
  final bool animate;
  final double from;


  ///這是我自己寫的 起點
  final Offset offset;


  ZoomInOffset(
      {this.key,
      this.child,
      this.duration = const Duration(milliseconds: 500),
      this.delay = const Duration(milliseconds: 0),
      this.controller,
      this.manualTrigger = false,
      this.animate = true,
      this.offset,
      this.from = 1.0})
      : super(key: key) {
    if (manualTrigger == true && controller == null) {
      throw FlutterError('If you want to use manualTrigger:true, \n\n'
          'Then you must provide the controller property, that is a callback like:\n\n'
          ' ( controller: AnimationController) => yourController = controller \n\n');
    }
  }


  @override
  _ZoomInState createState() => _ZoomInState();
}


/// State class, where the magic happens
class _ZoomInState extends State<ZoomInOffset>
    with SingleTickerProviderStateMixin {
  AnimationController controller;
  bool disposed = false;
  Animation<double> fade;
  Animation<double> opacity;


  @override
  void dispose() async {
    disposed = true;
    controller.dispose();
    super.dispose();
  }


  @override
  void initState() {
    super.initState();


    controller = AnimationController(duration: widget.duration, vsync: this);
    fade = Tween(begin: 0.0, end: widget.from)
        .animate(CurvedAnimation(curve: Curves.easeOut, parent: controller));


    opacity = Tween<double>(begin: 0.0, end: 1)
        .animate(CurvedAnimation(parent: controller, curve: Interval(0, 0.65)));


    if (!widget.manualTrigger && widget.animate) {
      Future.delayed(widget.delay, () {
        if (!disposed) {
          controller?.forward();
        }
      });
    }


    if (widget.controller is Function) {
      widget.controller(controller);
    }
  }


  @override
  Widget build(BuildContext context) {
    if (widget.animate && widget.delay.inMilliseconds == 0) {
      controller?.forward();
    }


    return AnimatedBuilder(
      animation: fade,
      builder: (BuildContext context, Widget child) {
        ///  這個transform有origin的可選構(gòu)造參數(shù),我們可以手動添加
        return Transform.scale(
          origin: widget.offset,
          scale: fade.value,
          child: Opacity(
            opacity: opacity.value,
            child: widget.child,
          ),
        );
      },
    );
  }
}

最后頁面調(diào)用

我用stack類進行堆疊組件,堆疊出上面箭頭

其實可以抽成一個方向設(shè)置不過太麻煩了我沒寫,畢竟能用就行

import 'package:flutter/material.dart';
import 'package:one/widget/Model.dart';
import 'package:one/widget/Popup.dart';

void main() {
  runApp(MyApp());
}


class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}


class _MyAppState extends State<MyApp> {
  ///給獲取詳細信息的widget設(shè)置一個key
  GlobalKey iconkey = GlobalKey();


  ///獲取位置,給后續(xù)彈窗設(shè)置位置
  Offset iconOffset;


  ///獲取size 后續(xù)計算彈出位置
  Size iconSize;


  ///接受彈窗類構(gòu)造成功傳遞來的關(guān)閉參數(shù)
  Function closeModel;


  @override
  Widget build(BuildContext context) {
    ///等待widget初始化完成
    WidgetsBinding.instance.addPostFrameCallback((duration) {
      ///通過key獲取到widget的位置
      RenderBox box = iconkey.currentContext.findRenderObject();


      ///獲取widget的高寬
      iconSize = box.size;


      ///獲取位置
      iconOffset = box.localToGlobal(Offset.zero);
    });


    return MaterialApp(
      home: Builder(
        builder: (context) => Scaffold(
          appBar: AppBar(
            actions: [
              IconButton(
                key: iconkey,
                icon: Icon(
                  Icons.favorite,
                  color: Colors.red,
                ),
                onPressed: () {
                  showModel(context);
                },
              ),
            ],
          ),
          body: Column(
            children: [],
          ),
        ),
      ),
    );
  }


  ///播放動畫
  void showModel(BuildContext context) {
    /// 設(shè)置傳入彈窗的高寬
    double _width = 130;
    double _height = 230;


    Navigator.push(
      context,
      Popup(
        child: Model(
          left: iconOffset.dx - _width + iconSize.width / 1.2,
          top: iconOffset.dy + iconSize.height / 1.3,
          offset: Offset(_width / 2, -_height / 2),
          child: Container(
            width: _width,
            height: _height,
            child: buildMenu(),
          ),
          fun: (close) {
            closeModel = close;
          },
        ),
      ),
    );
  }


  ///構(gòu)造傳入的widget
  Widget buildMenu() {
    ///構(gòu)造List
    List _list = [1, 2, 3, 4, 5];


    return Container(
      height: 160,
      width: 230,
      child: Stack(
        children: [
          Positioned(
            right: 4,
            top: 17,
            child: Container(
              width: 20,
              height: 20,
              transform: Matrix4.rotationZ(45 * 3.14 / 180),
              decoration: BoxDecoration(
                color: Color.fromRGBO(46, 53, 61, 1),
                borderRadius: BorderRadius.circular(5),
              ),
            ),
          ),


          ///菜單內(nèi)容
          Positioned(
            bottom: 0,
            child: Container(
              padding: EdgeInsets.only(
                top: 20,
                bottom: 20,
                left: 10,
                right: 10,
              ),
              width: 130,
              height: 200,
              decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(10),
                color: Color.fromRGBO(46, 53, 61, 1),
              ),
              child: Column(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: _list
                    .map<Widget>((e) => InkWell(
                          child: Container(
                            width: double.infinity,
                            alignment: Alignment.center,
                            child: Text(
                              '這應該是選項${e.toString()}',
                              style: TextStyle(
                                color: Colors.white70,
                                fontSize: 14,
                              ),
                            ),
                          ),
                          onTap: () async {
                            print('這是點擊了選項${e.toString()}');
                            await Future.delayed(Duration(milliseconds: 500))
                                .then((value) => print('開始'));
                            await closeModel();
                            print('結(jié)束');
                          },
                        ))
                    .toList(),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

然后就能實現(xiàn)我們的彈窗動畫了,如果想要其他效果的動畫,可以手動替換動畫類,或者自己手寫個新的最后我自己的項目修飾效果,還有demo的代碼代碼 倉庫地址:https://github.com/mannaoz/one

到此這篇關(guān)于flutter 實現(xiàn)點擊下拉欄微信右上角彈出窗功能的文章就介紹到這了,更多相關(guān)flutter彈出窗內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Android開發(fā)實現(xiàn)讀取assets目錄下db文件的方法示例

    Android開發(fā)實現(xiàn)讀取assets目錄下db文件的方法示例

    這篇文章主要介紹了Android開發(fā)實現(xiàn)讀取assets目錄下db文件的方法,結(jié)合實例形式分析了Android針對assets目錄下SQLite數(shù)據(jù)庫文件的相關(guān)操作技巧,需要的朋友可以參考下
    2017-10-10
  • Android常用命令集錦(圖文并茂適應于初學者)

    Android常用命令集錦(圖文并茂適應于初學者)

    大家好,今天我們要講的是android開發(fā)中,比較常用的名令集錦, 在我們開發(fā)中難免用到Android命令,有些確實命令確實很有用處,這也是我為什么總結(jié)這篇文章的原因了,希望對大家有所幫助
    2013-01-01
  • android 彈出提示框的使用(圖文實例)

    android 彈出提示框的使用(圖文實例)

    android 彈出提示框的使用(圖文實例),需要的朋友可以參考一下
    2013-06-06
  • Android入門之計時器Chronometer的使用教程

    Android入門之計時器Chronometer的使用教程

    Chronometer是一個簡單的定時器,你可以給它一個開始時間,并以此定時。本文將利用個簡單的示例為大家講解一下它的使用,感興趣的小伙伴可以嘗試一下
    2022-11-11
  • Kotlin中Object關(guān)鍵字的使用示例介紹

    Kotlin中Object關(guān)鍵字的使用示例介紹

    在Kotlin中object是一個特殊的關(guān)鍵字。主要用于聲明一個類的同時創(chuàng)建這個類的對象(例如單例)。在Kotlin中它有三個方面的應用:對象表達式,對象聲明和伴生對象
    2022-09-09
  • 使用Thumbnails實現(xiàn)圖片指定大小壓縮

    使用Thumbnails實現(xiàn)圖片指定大小壓縮

    這篇文章主要為大家詳細介紹了使用Thumbnails實現(xiàn)圖片指定大小壓縮,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • Android 讀取sdcard上的圖片實例(必看)

    Android 讀取sdcard上的圖片實例(必看)

    下面小編就為大家?guī)硪黄狝ndroid 讀取sdcard上的圖片實例(必看)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-03-03
  • textView 添加超鏈接(兩種實現(xiàn)方式)

    textView 添加超鏈接(兩種實現(xiàn)方式)

    在textView添加超鏈接,有兩種方式,第一種通過HTML格式化你的網(wǎng)址,一種是設(shè)置autolink,讓系統(tǒng)自動識別超鏈接,下面為大家介紹下這兩種方法的實現(xiàn)
    2013-06-06
  • Mac 下 Android Studio 不打印日志的解決辦法

    Mac 下 Android Studio 不打印日志的解決辦法

    這篇文章主要介紹了Mac 下 Android Studio 不打印日志的解決辦法的相關(guān)資料,希望通過本文能幫助到大家,需要的朋友可以參考下
    2017-10-10
  • Android實現(xiàn)表情功能

    Android實現(xiàn)表情功能

    這篇文章主要為大家詳細介紹了Android實現(xiàn)表情功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-04-04

最新評論