代码展示:
menu.dart文件:
import 'package:flutter/material.dart';import 'arrow_list.dart';import 'fade_popup.dart';import 'mask.dart';class FCArrowMenuScreen extends StatefulWidget { static const routeName = '/arrow_menu'; @override _FCArrowMenuScreenState createState() => _FCArrowMenuScreenState();}class _FCArrowMenuScreenState extends State<FCArrowMenuScreen> { GlobalKey<_FCArrowMenuScreenState> _globalKey = GlobalKey(); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Top Arrow Menu') ), body: Stack( children: [ Positioned( // Positioned只能配合 Stack 使用 left: 150, top: 150, child: IconButton( key: _globalKey, icon: Icon(Icons.add_circle, size: 35, color: Colors.yellow[800]), onPressed: () { // 获取 IconButton 在屏幕上的坐标 // 1.先获取此组件, 利用组件绑定的key // 2.组件自身的左上角 转屏幕坐标(零点) RenderBox box = _globalKey.currentContext.findRenderObject(); Offset boxZeroOffset = box.localToGlobal(Offset.zero); Size boxSize = box.size; double menuX = boxZeroOffset.dx - FCArrowMenu.menuWidth * 0.5 + box.size.width * 0.5; double menuY = boxZeroOffset.dy + boxSize.height; Navigator.of(context).push( /** 自定义动效路由*/ FCFadePopupRoute(child: FCMask(child: FCArrowMenu(), left: menuX, top: menuY)) /** 可使用 PageRouteBuilder路由: 系统自带动效路由; PageRouteBuilder继承PopupRoute*/ // PageRouteBuilder( // opaque: false, // barrierDismissible: true, // maintainState: true, // transitionDuration: Duration(milliseconds: 250), // pageBuilder: (context, animation, secondaryAnimation) { // return FadeTransition( // opacity: Tween(begin: 0.0, end: 1.0).animate(CurvedAnimation(parent: animation, curve: Curves.fastOutSlowIn)), // child: FCMask(child: FCArrowMenu(), left: menuX, top: menuY), // ); // }) ); } ), ) ] ), ); }}
fade_popup.dart文件:自定义动效
import 'package:flutter/material.dart';class FCFadePopupRoute extends PopupRoute { final Widget child; FCFadePopupRoute({@required this.child}); @override Color get barrierColor => null; @override String get barrierLabel => null; @override bool get barrierDismissible => true; @override bool get maintainState => true; @override Duration get transitionDuration => Duration(milliseconds: 250); @override Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) { return FadeTransition( opacity: Tween(begin: 0.0, end: 1.0).animate(CurvedAnimation(parent: animation, curve: Curves.easeIn)), child: child, ); }}
mask.dart文件:
import 'package:flutter/material.dart';class FCMask extends StatelessWidget { final Widget child; final double left; final double top; FCMask({ @required this.child, this.left, this.top }); @override Widget build(BuildContext context) { return Scaffold( // 这里也可以使用 Material(color: Colors.transparent, child: xxx) backgroundColor: Colors.transparent, body: GestureDetector( onTap: ()=>Navigator.of(context).pop(), child: Stack( children: [ Container( // 底部全屏黑色透明背景 width: double.infinity, height: double.infinity, color: Colors.black.withOpacity(0.55) ), Positioned( top: top, left: left, child: child ) ], ) ), ); }}
arrow_list.dart文件:
import 'package:flutter/material.dart';import 'dart:ui' as ui;// cell显示内容数据模型class MenuItem { final Widget leading; final String title; MenuItem({ this.leading, this.title });}// items数据源List<MenuItem> items = [ MenuItem(leading: Icon(Icons.warning_amber_rounded, color: Colors.white, size: 28), title: "异常提示"), MenuItem(leading: Icon(Icons.update_rounded, color: Colors.white, size: 28), title: "更新信息"), MenuItem(leading: Icon(Icons.message_rounded, color: Colors.white, size: 28), title: "回复信息")];class FCArrowMenu extends StatelessWidget { static double menuWidth = MediaQueryData.fromWindow(ui.window).size.width *0.35; @override Widget build(BuildContext context) { return Container( width: menuWidth, child: Column( children: [ // Image.asset('assets/images/img_up_arrow.png', width: 25.0, height: 13.4), FCTrigon(), // 自定义绘制箭头 Container( constraints: BoxConstraints(maxHeight: 45.0*5), // 设置最大容器高度 padding: EdgeInsets.only(left: 8, right: 8), decoration: BoxDecoration( color: Colors.black.withOpacity(0.55), borderRadius: BorderRadius.circular(5) ), child: ListView.builder( shrinkWrap: true, padding: EdgeInsets.zero, itemCount: items.length, itemBuilder: (context, index) { Widget leading = items[index].leading; String title = items[index].title; return GestureDetector( child: Container( padding: EdgeInsets.only(top: 8, bottom: 8), child: Row( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.center, children: [ leading, SizedBox(width: 8), Expanded( child: Text(title, style: TextStyle( fontSize: 17, color: Colors.white, fontWeight: FontWeight.bold )), ) ], ), ), onTap: () { print("$title"); }, ); }, ), ) ], ), ); }}/* 绘制三角形 */ class FCTrigon extends StatelessWidget { @override Widget build(BuildContext context) { return ClipPath( clipper: FCTrigonPath(), child: Container( width: 25.0, height: 13.4, color: Colors.black.withOpacity(0.55), ), ); }}class FCTrigonPath extends CustomClipper<Path> { @override Path getClip(Size size) { Path path = Path(); path.moveTo(0, size.height); path.lineTo(size.width * 0.5, 0); path.lineTo(size.width, size.height); path.close(); return path; } @override bool shouldReclip(covariant CustomClipper<Path> oldClipper) { return true; }}
版权声明:内容来源于互联网和用户投稿 如有侵权请联系删除