Есть несколько проблем с тем, что вы делаете.Но быстрый FYI - если вы очистите свой код и создадите инкапсулированную проблему, люди с большей вероятностью помогут вам.Это повлечет за собой удаление любых ваших классов, которые не включены, и, в идеале, размещение решения, которое можно вставить в один файл и запустить как есть.
При этом я реализовал то, что думаюты пытался сделать.Я удалил несколько вещей, которые у вас были там, чтобы он действительно собирался, поэтому вам нужно будет добавить их обратно.
Основные проблемы, с которыми вы столкнулись, следующие:
SetState в слушателе
..addListener(() {
setState(() {});
});
Это не идеально, потому что заставит весь виджет перестраивать каждый тик анимации.Это вызовет серьезные проблемы с производительностью для виджета, который не является базовым.Вместо этого используйте AnimatedBuilder
.Или, если вы ищете, когда анимация заканчивается, используйте ..addStateListener
Углы в радианах в трепетании.Я не удосужился импортировать Math для константы Pi, но вам, вероятно, следует.
У вас есть касание, которое на самом деле не вызывало openMenu
или closeMenu
, так чтоопределенно ничего не сделает = D.
Вы бы настроили контроллер анимации на повторение.Это означает, что это будет продолжаться вечно.
Вы не передавали ничего в animationControllerOpenClose.forward
вызовы.Это означает, что он будет анимирован до состояния 1.0, где бы он ни находился в данный момент, даже если он уже был 1.0.Я только что передал 0, но вы можете захотеть что-то сделать с открытием / закрытием (если пользователь нажимает во время анимации или что-то в этом роде).
(тангенциальная проблема) ВыКажется, что добавление новой кнопки меню Открыть / Закрыть после каждого виджета меню.Это может быть то, что вы хотите сделать, но я думаю, вы просто хотите добавить один.
В любом случае, вот пример, который работает.Каждый раз, когда вы нажимаете, он меняет значки, а затем поворачивается.
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "Spinnig Menu",
theme: ThemeData(
primaryColor: Colors.red,
),
home: new Scaffold(
body: new SafeArea(
child: new Column(
children: <Widget>[new CustomThemedRadialMenu()],
),
),
),
);
}
}
class CustomThemedRadialMenu extends StatefulWidget {
@override
_CustomThemedRadialMenuState createState() => _CustomThemedRadialMenuState();
}
class _CustomThemedRadialMenuState extends State<CustomThemedRadialMenu> with SingleTickerProviderStateMixin {
Animation animationOpenClose;
AnimationController animationControllerOpenClose;
bool isOpen;
@override
void initState() {
isOpen = false;
animationControllerOpenClose = AnimationController(duration: new Duration(seconds: 5), vsync: this);
animationOpenClose = Tween(begin: 0.0, end: 3.14159 * 2).animate(animationControllerOpenClose);
super.initState();
}
@override
Widget build(BuildContext context) {
///A list of the items and the center menu button
final List<Widget> menuContents = <Widget>[];
///Menu Close/Open button
menuContents.add(new InkWell(
onTap: () {
if (isOpen) {
closeMenu();
} else {
openMenu();
}
},
child: Container(
padding: new EdgeInsets.all(10.0),
decoration: new BoxDecoration(
color: Colors.white,
border: new Border.all(color: Colors.black38),
shape: BoxShape.circle,
),
child: new AnimatedBuilder(
animation: animationControllerOpenClose,
builder: (context, child) {
return new Transform.rotate(angle: animationOpenClose.value, child: child);
},
child: isOpen ? new Icon(Icons.clear) : new Icon(Icons.menu),
)),
));
return new Stack(
alignment: Alignment.center,
children: menuContents,
);
}
@override
void dispose() {
animationControllerOpenClose.dispose();
super.dispose();
}
closeMenu() {
animationControllerOpenClose.forward(from: 0.0);
setState(() {
isOpen = false;
});
print("RadialMenu Closed");
}
openMenu() {
animationControllerOpenClose.forward(from: 0.0);
setState(() {
isOpen = true;
});
print("RadialMenu Opened");
}
}
Следует отметить, что я создаю минимально возможное количество виджетов в функции сборки AnimatedBuilder.Чем меньше там построено, тем лучше производительность.Поскольку значок не изменяется как часть вращения, вы можете просто передать его как дочерний элемент.
Я предполагаю, что это может произойти дальше, так что просто FYI - вы можете использовать анимированный крестисчезает виджет для перехода между иконками (просто добавьте это для потомка AnimatedBuilder):
new AnimatedCrossFade(
firstChild: new Icon(Icons.clear),
secondChild: new Icon(Icons.menu),
crossFadeState: isOpen ? CrossFadeState.showFirst : CrossFadeState.showSecond,
duration: Duration(milliseconds: 300)),