import 'package:chat/utils/screen.dart'; import 'package:flutter/material.dart'; import 'package:flutter/foundation.dart'; class GZXDropdownMenuController extends ChangeNotifier { double dropDownHearderHeight; int menuIndex = 0; bool isShow = false; void show(int index) { isShow = true; menuIndex = index; notifyListeners(); } void hide() { isShow = false; notifyListeners(); } } typedef OnItemTap = void Function(T value); class GZXDropDownHeader extends StatefulWidget { final Color color; final double borderWidth; final Color borderColor; final TextStyle style; final TextStyle dropDownStyle; final double iconSize; final Color iconColor; final Color iconDropDownColor; // final List menuStrings; final double height; final double dividerHeight; final Color dividerColor; final GZXDropdownMenuController controller; final OnItemTap onItemTap; final List items; final GlobalKey stackKey; GZXDropDownHeader({ Key key, @required this.items, @required this.controller, @required this.stackKey, this.style = const TextStyle(color: Color(0xFF666666), fontSize: 13), this.dropDownStyle, this.height = 40, this.iconColor = const Color(0xFFafada7), this.iconDropDownColor, this.iconSize = 20, this.borderWidth = 0, this.borderColor = const Color(0xFFeeede6), this.dividerHeight = 20, this.dividerColor = const Color(0xFFeeede6), this.onItemTap, this.color = Colors.white, }) : super(key: key); @override _GZXDropDownHeaderState createState() => _GZXDropDownHeaderState(); } class _GZXDropDownHeaderState extends State with SingleTickerProviderStateMixin { bool _isShowDropDownItemWidget = false; int _menuCount; GlobalKey _keyDropDownHearder = GlobalKey(); @override void initState() { super.initState(); widget.controller.addListener(_onController); } _onController() { // print(widget.controller.menuIndex); } @override Widget build(BuildContext context) { // print('_GZXDropDownHeaderState.build'); _menuCount = widget.items.length; var gridView = GridView.count( physics: new NeverScrollableScrollPhysics(), crossAxisCount: _menuCount, childAspectRatio: (Screen.width / _menuCount) / widget.height, children: widget.items.map((item) { return _menu(item); }).toList(), ); return Container( key: _keyDropDownHearder, height: widget.height, margin: EdgeInsets.zero, padding: EdgeInsets.symmetric(horizontal: 10), decoration: BoxDecoration( border: Border.all(color: widget.borderColor, width: widget.borderWidth), ), child: gridView, ); } dispose() { super.dispose(); } _menu(GZXDropDownHeaderItem item) { int index = widget.items.indexOf(item); int menuIndex = widget.controller.menuIndex; _isShowDropDownItemWidget = index == menuIndex && widget.controller.isShow; return GestureDetector( onTap: () { final RenderBox overlay = widget.stackKey.currentContext.findRenderObject(); final RenderBox dropDownItemRenderBox = _keyDropDownHearder.currentContext.findRenderObject(); var position = dropDownItemRenderBox.localToGlobal(Offset.zero, ancestor: overlay); // print("POSITION : $position "); var size = dropDownItemRenderBox.size; // print("SIZE : $size"); widget.controller.dropDownHearderHeight = size.height + position.dy; if (widget.controller.isShow) { widget.controller.hide(); } else { widget.controller.show(index); } if (widget.onItemTap != null) { widget.onItemTap(index); } setState(() {}); }, child: Container( color: widget.color, width: Screen.width/3-20, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Expanded( child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Flexible( child: Text( item.title, textScaleFactor: 1.0, maxLines: 1, overflow: TextOverflow.ellipsis, style: _isShowDropDownItemWidget ? widget.dropDownStyle ??TextStyle(color: Theme.of(context).primaryColor, fontSize: 13) : widget.style, )), Icon( !_isShowDropDownItemWidget ? item.iconData ?? Icons.arrow_drop_down : item.iconData ?? Icons.arrow_drop_up, color: _isShowDropDownItemWidget ? widget.iconDropDownColor ?? Theme.of(context).primaryColor : widget.iconColor, size: item.iconSize ?? widget.iconSize, ), ], ), ) ], )), ); } } class GZXDropDownHeaderItem { final String title; final IconData iconData; final double iconSize; GZXDropDownHeaderItem( this.title, { this.iconData, this.iconSize, }); } class GZXDropdownMenuBuilder { final Widget dropDownWidget; final double dropDownHeight; final callback; GZXDropdownMenuBuilder( {@required this.dropDownWidget, @required this.dropDownHeight, @required this.callback}); } class GZXDropDownMenu extends StatefulWidget { final GZXDropdownMenuController controller; final List menus; final int animationMilliseconds; const GZXDropDownMenu( {Key key, @required this.controller, @required this.menus, this.animationMilliseconds = 100}) : super(key: key); @override _GZXDropDownMenuState createState() => _GZXDropDownMenuState(); } class _GZXDropDownMenuState extends State with SingleTickerProviderStateMixin { bool _isShowDropDownItemWidget = false; bool _isShowMask = false; bool _isControllerDisposed = false; Animation _animation; AnimationController _controller; @override void initState() { super.initState(); widget.controller.addListener(_onController); _controller = new AnimationController( duration: Duration(milliseconds: widget.animationMilliseconds), vsync: this); } _onController() { // print('_GZXDropDownMenuState._onController ${widget.controller.menuIndex}'); _showDropDownItemWidget(); } @override Widget build(BuildContext context) { // print('_GZXDropDownMenuState.build'); _controller.duration = Duration(milliseconds: widget.animationMilliseconds); return _buildDropDownWidget(); } dispose() { _controller.dispose(); _isControllerDisposed = true; super.dispose(); } _showDropDownItemWidget() { int menuIndex = widget.controller.menuIndex; if (menuIndex >= widget.menus.length || widget.menus[menuIndex] == null) { return; } _isShowDropDownItemWidget = !_isShowDropDownItemWidget; _isShowMask = !_isShowMask; _animation = new Tween(begin: 0.0, end: widget.menus[menuIndex].dropDownHeight) .animate(_controller) ..addListener(() { //这行如果不写,没有动画效果 setState(() {}); }); if (_isControllerDisposed) return; if (_animation.status == AnimationStatus.completed) { _controller.reverse(); } else { _controller.forward(); } } _hideDropDownItemWidget() { _isShowDropDownItemWidget = !_isShowDropDownItemWidget; _isShowMask = !_isShowMask; _controller.reverse(); widget.controller.isShow = false; } Widget _mask(callback) { if (_isShowMask) { return GestureDetector( onTap: () { print('到mask了'); _hideDropDownItemWidget(); if (callback != null) callback(); }, child: Container( width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height * 2, color: Color.fromRGBO(0, 0, 0, 0.1), ), ); } else { return Container( height: 0, ); } } Widget _buildDropDownWidget() { int menuIndex = widget.controller.menuIndex; return Positioned( width: MediaQuery.of(context).size.width, top: widget.controller.dropDownHearderHeight, left: 0, child: Column( children: [ Container( color: Colors.white, width: MediaQuery.of(context).size.width, height: _animation == null ? 0 : _animation.value, child: widget.menus[menuIndex].dropDownWidget, ), _mask(widget.menus[menuIndex].callback) ], )); } }