我试图从一个figma屏幕复制一个UI。但是我被这个小部件卡住了,我想知道材料(或任何外部)包是否有任何类似的东西,这可能会帮助我,或者我需要手工创建这个?它就像一个浮动的菜单卡,它的中心蓝色按钮调用,给予用户能够在所有屏幕之间导航。
ru9i0ody1#
检查此软件包https://github.com/chinabrant/popup_menu
import 'package:flutter/material.dart'; import 'package:popup_menu/popup_menu.dart'; import 'package:popup_menu_example/gesture_demo.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', home: MyHomePage(title: 'Popup Menu Example'), ); } } class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { PopupMenu menu; GlobalKey btnKey = GlobalKey(); GlobalKey btnKey2 = GlobalKey(); @override void initState() { super.initState(); menu = PopupMenu(items: [ // MenuItem(title: 'Copy', image: Image.asset('assets/copy.png')), // MenuItem(title: 'Home', image: Icon(Icons.home, color: Colors.white,)), MenuItem( title: 'Mail', image: Icon( Icons.mail, color: Colors.white, )), MenuItem( title: 'Power', image: Icon( Icons.power, color: Colors.white, )), MenuItem( title: 'Setting', image: Icon( Icons.settings, color: Colors.white, )), MenuItem( title: 'PopupMenu', image: Icon( Icons.menu, color: Colors.white, )) ], onClickMenu: onClickMenu, onDismiss: onDismiss, maxColumn: 1); } void stateChanged(bool isShow) { print('menu is ${isShow ? 'showing' : 'closed'}'); } void onClickMenu(MenuItemProvider item) { print('Click menu -> ${item.menuTitle}'); } void onDismiss() { print('Menu is dismiss'); } @override Widget build(BuildContext context) { PopupMenu.context = context; return Scaffold( appBar: AppBar( title: Text(widget.title), actions: <Widget>[ // action button IconButton( key: btnKey, icon: Icon(Icons.access_time), onPressed: () { maxColumn(); }, ), IconButton( key: btnKey2, icon: Icon(Icons.memory), onPressed: () { maxColumn(); }, ) ], ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.spaceAround, children: <Widget>[ Container( child: GestureDetector( onLongPress: () { //maxColumn(); }, child: MaterialButton( height: 45.0, //key: btnKey, child: Text('Show Menu'), ), ), ), ], ), ), ); } void onGesturesDemo() { Navigator.push( context, MaterialPageRoute(builder: (context) => GestureDemo()), ); } void checkState(BuildContext context) { final snackBar = new SnackBar(content: new Text('这是一个SnackBar!')); Scaffold.of(context).showSnackBar(snackBar); } void maxColumn() { PopupMenu menu = PopupMenu( // backgroundColor: Colors.teal, // lineColor: Colors.tealAccent, maxColumn: 3, items: [ MenuItem(title: 'Copy', image: Image.asset('assets/copy.png')), // MenuItem( // title: 'Home', // // textStyle: TextStyle(fontSize: 10.0, color: Colors.tealAccent), // image: Icon( // Icons.home, // color: Colors.white, // )), // MenuItem( // title: 'Mail', // image: Icon( // Icons.mail, // color: Colors.white, // )), MenuItem( title: 'Power', image: Icon( Icons.power, color: Colors.white, )), MenuItem( title: 'Setting', image: Icon( Icons.settings, color: Colors.white, )), MenuItem( title: 'PopupMenu', image: Icon( Icons.menu, color: Colors.white, )) ], onClickMenu: onClickMenu, stateChanged: stateChanged, onDismiss: onDismiss); menu.show(widgetKey: btnKey); } // void customBackground() { PopupMenu menu = PopupMenu( // backgroundColor: Colors.teal, // lineColor: Colors.tealAccent, // maxColumn: 2, items: [ MenuItem(title: 'Copy', image: Image.asset('assets/copy.png')), MenuItem( title: 'Home', // textStyle: TextStyle(fontSize: 10.0, color: Colors.tealAccent), image: Icon( Icons.home, color: Colors.white, )), MenuItem( title: 'Mail', image: Icon( Icons.mail, color: Colors.white, )), MenuItem( title: 'Power', image: Icon( Icons.power, color: Colors.white, )), MenuItem( title: 'Setting', image: Icon( Icons.settings, color: Colors.white, )), MenuItem( title: 'PopupMenu', image: Icon( Icons.menu, color: Colors.white, )) ], onClickMenu: onClickMenu, stateChanged: stateChanged, onDismiss: onDismiss); menu.show(widgetKey: btnKey2); } }
ogsagwnx2#
好的,从UI来看,你应该有一个底部的导航栏,有三个屏幕,中间的屏幕包含一个容器/卡片,里面有不同的按钮。我已经为此目的创建了类似的东西,我希望它有帮助。底部导航栏:
class BottomNavBar extends StatefulWidget { const BottomNavBar({Key? key}) : super(key: key); @override State<BottomNavBar> createState() => _BottomNavBarState(); } class _BottomNavBarState extends State<BottomNavBar> { int currentIndex = 0; final screens = [ const FirstScreen(), const SecondScreen(), const ThirdScreen() ]; @override Widget build(BuildContext context) { return Scaffold( body: IndexedStack( index: currentIndex, children: screens, ), bottomNavigationBar: BottomNavigationBar( selectedItemColor: const Color.fromRGBO(50, 201, 209, 1), type: BottomNavigationBarType.fixed, currentIndex: currentIndex, onTap: (index) => setState(() => currentIndex = index), backgroundColor: Colors.transparent, elevation: 0, iconSize: 30, items: const [ BottomNavigationBarItem( icon: Icon( Icons.home_outlined, ), label: 'Home', ), BottomNavigationBarItem( icon: Icon( Icons.shopping_cart_outlined, ), label: 'Orders', ), BottomNavigationBarItem( icon: Icon( Icons.production_quantity_limits_rounded, ), label: 'Products', ), ], ), ); } }
卡片/容器小部件:
class ArrowClipper extends CustomClipper<Path> { @override Path getClip(Size size) { final path = Path(); path.moveTo(0, 0); path.lineTo(size.width, 0); path.lineTo(size.width, size.height - 30); path.lineTo(size.width / 2 + 10, size.height - 30); path.lineTo(size.width / 2, size.height); path.lineTo(size.width / 2 - 10, size.height - 30); path.lineTo(0, size.height - 30); path.close(); return path; } @override bool shouldReclip(ArrowClipper oldClipper) => false; }
屏幕:
class ThirdScreen extends StatelessWidget { const ThirdScreen({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Container(); } } class SecondScreen extends StatelessWidget { const SecondScreen({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.grey[100], body: Column( mainAxisAlignment: MainAxisAlignment.end, children: [ ClipPath( clipper: ArrowClipper(), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 20), child: Container( height: 300, width: double.infinity, decoration: BoxDecoration( color: Colors.white, boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(0.5), spreadRadius: 2, blurRadius: 5, offset: const Offset(0, 3), // changes position of shadow ), ], ), child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: const [ CircleAvatar( backgroundColor: Colors.red, ), CircleAvatar( backgroundColor: Colors.yellow, ), CircleAvatar( backgroundColor: Colors.green, ) ], ), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: const [ CircleAvatar( backgroundColor: Colors.red, ), CircleAvatar( backgroundColor: Colors.yellow, ), CircleAvatar( backgroundColor: Colors.green, ) ], ), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: const [ CircleAvatar( backgroundColor: Colors.red, ), CircleAvatar( backgroundColor: Colors.yellow, ), CircleAvatar( backgroundColor: Colors.green, ) ], ) ], )), ), ), ) ], ), ); } } class FirstScreen extends StatelessWidget { const FirstScreen({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Container(); } }
2条答案
按热度按时间ru9i0ody1#
检查此软件包https://github.com/chinabrant/popup_menu
ogsagwnx2#
好的,从UI来看,你应该有一个底部的导航栏,有三个屏幕,中间的屏幕包含一个容器/卡片,里面有不同的按钮。
我已经为此目的创建了类似的东西,我希望它有帮助。
底部导航栏:
卡片/容器小部件:
屏幕: