I was recently trying to add in firebase fcm and it didn't work just caused several errors, so I rolled everything back to the original RUNNING code but upgraded flutter in the process...Since v1.3.10 a Hero cannot contain another Hero widget in its children hierarchy but I cannot find a fix. (ideally don't want to change version back)
I've checked the heroTags and also can't find any nested Hero widgets - maybe it is because of the animated builder?
import 'package:flutter/material.dart';
import 'dart:math';
import 'package:vector_math/vector_math.dart' show radians, Vector3;
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import './Custom Icons/my_flutter_app_icons.dart' as CustomIcons;
import 'package:startoversword/liftPage.dart';
import 'package:startoversword/analWinkPage.dart';
import 'package:startoversword/lipPage.dart';
import 'package:startoversword/windscreenWiperPage.dart';
import 'package:startoversword/highHeelPage.dart';
import 'package:startoversword/rollerCoasterPage.dart';
import 'package:startoversword/notificationPage.dart';
import 'package:flutter/services.dart';
void main() async {
await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Menu',
home: _placeMyAppScaffold(),
);
}
}
class _placeMyAppScaffold extends StatelessWidget {
Color defaultPink = Colors.white;
Color pageThemeColor = Color(0xffF599E9);
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
body: SizedBox.expand(child: RadialMenu()),
appBar: AppBar(
actions: <Widget>[
FlatButton(
child: Icon(Icons.notifications, color: Colors.white, size: 50.0),
onPressed: () {
print("notification pressed");
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => NotificationPage()));
},
),
],
title: Text('The S Word'),
backgroundColor: pageThemeColor,
));
}
}
class RadialMenu extends StatefulWidget {
createState() => _RadialMenuState();
}
class _RadialMenuState extends State<RadialMenu>
with SingleTickerProviderStateMixin {
AnimationController controller;
@override
void initState() {
super.initState();
controller =
AnimationController(duration: Duration(milliseconds: 900), vsync: this);
}
@override
Widget build(BuildContext context) {
return RadialAnimation(controller: controller);
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
}
class RadialAnimation extends StatelessWidget {
RadialAnimation({Key key, this.controller})
: translation = Tween<double>(
begin: 0.0,
end: 100.0,
).animate(
CurvedAnimation(parent: controller, curve: Curves.elasticOut),
),
scale = Tween<double>(
begin: 1.5,
end: 0.0,
).animate(
CurvedAnimation(parent: controller, curve: Curves.fastOutSlowIn),
),
rotation = Tween<double>(
begin: 0.0,
end: 360.0,
).animate(
CurvedAnimation(
parent: controller,
curve: Interval(
0.0,
0.7,
curve: Curves.decelerate,
),
),
),
super(key: key);
final AnimationController controller;
final Animation<double> rotation;
final Animation<double> translation;
final Animation<double> scale;
@override
Widget build(BuildContext context) {
Color defaultPink = Color(0xffF599E9);
return AnimatedBuilder(
animation: controller,
builder: (context, widget) {
return Transform.rotate(
angle: radians(rotation.value),
child: Stack(alignment: Alignment.center, children: <Widget>[
Hero(
tag: "liftScreenButton",
child: Container(
child: _buildButton(
30,
color: Color(0xfff665c6),
icon: CustomIcons.YoniFonts.lift,
context: context,
nextScreen: 'LiftScreen',
),
),
),
Hero(
tag: "winkScreenButton",
child: Container(
child: _buildButton(
90,
color: Color(0xffe654be),
icon: CustomIcons.YoniFonts.dot_circled,
context: context,
nextScreen: 'winkScreen',
),
),
),
Hero(
tag: "lipScreenButton",
child: Container(
child: _buildButton(
150,
color: Color(0xffd643b7),
icon: CustomIcons.YoniFonts.lips,
context: context,
nextScreen: 'lipScreen',
),
),
),
Hero(
tag: "windscreenWiperScreenButton",
child: Container(
child: _buildButton(
210,
color: Color(0xffc632b0),
icon: CustomIcons.YoniFonts.car,
context: context,
nextScreen: 'WindscreenWiperScreen',
),
),
),
Hero(
tag: "highHeelScreenButton",
child: Container(
child: _buildButton(
270,
color: Color(0xffb621a9),
icon: CustomIcons.YoniFonts.high_heels,
context: context,
nextScreen: 'HighHeelScreen',
),
),
),
Hero(
tag: "rollerCoasterScreenButton",
child: Container(
child: _buildButton(
330,
color: Color(0xffa711a2),
icon: CustomIcons.YoniFonts.roller_coaster,
context: context,
nextScreen: 'rollerCoasterScreen',
),
),
),
Transform.scale(
scale: scale.value - 1,
child: FloatingActionButton(
child: Icon(CustomIcons.YoniFonts.upsideDownYoni),
heroTag: "upsideDownYoni",
onPressed: _close,
backgroundColor: defaultPink),
),
Transform.scale(
scale: scale.value,
child: FloatingActionButton(
heroTag: "initalYoni",
child: Icon(CustomIcons.YoniFonts.yoni),
onPressed: _open,
backgroundColor: defaultPink,
),
)
]));
});
}
_open() {
controller.forward();
}
_close({context, String nextScreen}) {
controller.reverse();
if (nextScreen == 'LiftScreen') {
print("NEXT SCREEN IS LIFTPAGE");
Navigator.push(
context, MaterialPageRoute(builder: (context) => LiftPage()));
} else if (nextScreen == "winkScreen") {
print("NEXT SCREEN IS WINKPAGE");
Navigator.push(
context, MaterialPageRoute(builder: (context) => WinkPage()));
} else if (nextScreen == "lipScreen") {
print("NEXT SCREEN IS LIP PAGE");
Navigator.push(
context, MaterialPageRoute(builder: (context) => LipPage()));
} else if (nextScreen == "WindscreenWiperScreen") {
print("NEXT SCREEN IS WINDSCREENWIPERPAGE");
Navigator.push(context,
MaterialPageRoute(builder: (context) => WindScreenWiperPage()));
} else if (nextScreen == "HighHeelScreen") {
print("NEXT SCREEN IS HIGHHEELPAGE");
Navigator.push(
context, MaterialPageRoute(builder: (context) => HighHeelPage()));
} else if (nextScreen == "rollerCoasterScreen") {
print("NEXT SCREEN IS ROLLERCOASTERPAGE");
Navigator.push(context,
MaterialPageRoute(builder: (context) => RollerCoasterPage()));
} else {
return;
}
;
}
_buildButton(double angle,
{Color color, IconData icon, context, String nextScreen}) {
final double rad = radians(angle);
return Transform(
transform: Matrix4.identity()
..translate(
(translation.value) * cos(rad), (translation.value) * sin(rad)),
child: FloatingActionButton(
child: Icon(icon),
heroTag: nextScreen,
backgroundColor: color,
onPressed: () => _close(context: context, nextScreen: nextScreen),
elevation: 0));
}
}
The error message points to
_buildButton(double angle,
{Color color, IconData icon, context, String nextScreen}) {
final double rad = radians(angle);
return Transform(
transform: Matrix4.identity()
..translate(
(translation.value) * cos(rad), (translation.value) * sin(rad)),
child: FloatingActionButton(
child: Icon(icon),
heroTag: nextScreen, //error here
backgroundColor: color,
onPressed: () => _close(context: context, nextScreen: nextScreen),
elevation: 0));
}
}
For interest here is the complete output
I/flutter (20678): #431 ComponentElement.mount
package:flutter/…/widgets/framework.dart:3911
I/flutter (20678): #432 Element.inflateWidget
package:flutter/…/widgets/framework.dart:3093
I/flutter (20678): #433 Element.updateChild
package:flutter/…/widgets/framework.dart:2896
I/flutter (20678): #434 RenderObjectToWidgetElement._rebuild
package:flutter/…/widgets/binding.dart:940
I/flutter (20678): #435 RenderObjectToWidgetElement.mount
package:flutter/…/widgets/binding.dart:911
I/flutter (20678): #436 RenderObjectToWidgetAdapter.attachToRenderTree.<anonymous closure>
package:flutter/…/widgets/binding.dart:857
I/flutter (20678): #437 BuildOwner.buildScope
package:flutter/…/widgets/framework.dart:2320
I/flutter (20678): #438 RenderObjectToWidgetAdapter.attachToRenderTree
package:flutter/…/widgets/binding.dart:856
I/flutter (20678): #439 _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&SemanticsBinding&RendererBinding&WidgetsBinding.attachRootWidget
package:flutter/…/widgets/binding.dart:737
I/flutter (20678): #440 runApp
package:flutter/…/widgets/binding.dart:787
I/flutter (20678): #441 main
package:startoversword/main.dart:21
I/flutter (20678): #452 SystemChrome.setPreferredOrientations (package:flutter/src/services/system_chrome.dart)
I/flutter (20678): #463 OptionalMethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart)
I/flutter (20678): #474 MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart)
I/flutter (20678): (elided 46 frames from class _AssertionError, package dart:async, and package dart:async-patch)
I/flutter (20678):
I/flutter (20678): ════════════════════════════════════════════════════════════════════════════════════════════════════
I/flutter (20678): Another exception was thrown: A Hero widget cannot be the descendant of another Hero widget.
I/chatty (20678): uid=10088(com.oxspines.talkingsword) 1.ui identical 3 lines
I/flutter (20678): Another exception was thrown: A Hero widget cannot be the descendant of another Hero widget.
I/OpenGLRenderer(20678): Davey! duration=865ms; Flags=0, IntendedVsync=76957734745126, Vsync=76957768078458, OldestInputEvent=9223372036854775807, NewestInputEvent=0, HandleInputStart=76957769369260, AnimationStart=76957769756360, PerformTraversalsStart=76957774959760, DrawStart=76957778308860, SyncQueued=76957778894960, SyncStart=76957788359860, IssueDrawCommandsStart=76957793180660, SwapBuffers=76957809783260, FrameCompleted=76958609467060, DequeueBufferDuration=116998000, QueueBufferDuration=12148000,
I/Choreographer(20678): Skipped 57 frames! The application may be doing too much work on its main thread.
I/OpenGLRenderer(20678): Davey! duration=1061ms; Flags=0, IntendedVsync=76957801411790, Vsync=76958751411752, OldestInputEvent=9223372036854775807, NewestInputEvent=0, HandleInputStart=76958769243160, AnimationStart=76958772853660, PerformTraversalsStart=76958779455160, DrawStart=76958795072260, SyncQueued=76958796183260, SyncStart=76958889098460, IssueDrawCommandsStart=76958889855560, SwapBuffers=76958893194360, FrameCompleted=76958955694360, DequeueBufferDuration=35517000, QueueBufferDuration=4901000,
Solution 1: Daniel Oliveira
Thats because the FloatingActionButton already has a Hero widget wrapping it (check its source code). And in your code you are embedding the FAB inside ANOTHER Hero widget.
To fix it you can just set the "heroTag" property in you FAB to "null" OR remove the wrapping Hero widget around that FAB, leaving just the default one.
Solution 2: Mayur Nile
A simple solution to this problem is use Stack and overlap those hero widgets, so the hero widget will not be a child of hero widget anymore, but keep in mind the tag of both the hero widgets should be different ! Hope this helps you.