{"id":15567,"date":"2019-03-19T09:10:18","date_gmt":"2019-03-19T08:10:18","guid":{"rendered":"https:\/\/www.inovex.de\/blog\/?p=15567"},"modified":"2026-03-17T07:59:32","modified_gmt":"2026-03-17T06:59:32","slug":"flutter-the-finalizer-part-4","status":"publish","type":"post","link":"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/","title":{"rendered":"Flutter: The Finalizer (Part 4)"},"content":{"rendered":"<p><a href=\"https:\/\/www.inovex.de\/blog\/flutter-the-profiler-part-3\/\">Previously<\/a> we have created the basic structure of the Flutter application by defining the GeneralPage and the DetailsPage. In this article, I will concentrate on routing, layout, animation and data sharing.<!--more--><\/p>\n<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_79_2 counter-hierarchy ez-toc-counter ez-toc-custom ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\"><p class=\"ez-toc-title\" style=\"cursor:inherit\"><\/p>\n<\/div><nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/#The-Flutter-Profile-App\" >The Flutter Profile App<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/#Setting-up-the-Pages\" >Setting up the Pages<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/#Create-the-Widgets\" >Create the Widgets<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/#Get-Widget-Title\" >Get Widget Title<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/#AppBar\" >AppBar<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/#BottomNavigationBar-custom\" >BottomNavigationBar (custom)<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/#Grid\" >Grid<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/#GenreralCell\" >GenreralCell<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/#Stack\" >Stack<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/#Conclusion\" >Conclusion<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-11\" href=\"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/#All-articles-in-this-series\" >All articles in this series<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-12\" href=\"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/#Read-on\" >Read on<\/a><\/li><\/ul><\/nav><\/div>\n<h2><span class=\"ez-toc-section\" id=\"The-Flutter-Profile-App\"><\/span>The Flutter Profile App<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>The basic structure of the <em>profile app<\/em> is defined by the Scaffold widget. In order to build the UI, we create custom widgets as we refactor the application.<\/p>\n<p><em>Scaffold<\/em> <em>Sections<\/em><\/p>\n<ul>\n<li>appBar: \u00a0 \u00a0<em><strong>new<\/strong><\/em>AppBar(&#8230;)<\/li>\n<li>body: \u00a0 \u00a0 \u00a0 \u00a0<strong><em>new<\/em><\/strong> Container(&#8230;)<\/li>\n<li>bottomNavigationBar: \u00a0\u00a0<strong><em>new\u00a0<\/em><\/strong>BottomAppBar(&#8230;)<\/li>\n<\/ul>\n<p>When creating custom widgets, we have to think about the UI. A responsive UI can be achieved with the <em>MediaQuery.of(&#8230;)<\/em> function. This function provides the device dimensions and can therefore be used to adjust all widgets in the widget tree.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Setting-up-the-Pages\"><\/span>Setting up the Pages<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p><em>Create init function to get device dimensions<\/em><\/p>\n<pre class=\"font-size:14 line-height:20 lang:default decode:true\">\/\/ GeneralPage.dart and DetailsPage.dart\r\n\r\ndouble calc_height = 0.0;\r\n\r\ndouble calc_width = 0.0;\r\n\r\nint counter = 0;\r\n\r\n_init(){\r\n\r\n    if(counter == 0) {\r\n\r\n      this.calc_height = MediaQuery.of(context).size.height;\r\n\r\n      this.calc_width = MediaQuery.of(context).size.width;\r\n\r\n    }\r\n\r\n    counter++;\r\n\r\n}<\/pre>\n<p>The counter will trigger the dimension calculation only once. This will prevent\u00a0<em>MediaQuery.of(&#8230;)<\/em> being triggered with every state change. The next step will be to define the custom widgets that have to be built.<\/p>\n<p><em>Widgets to create for GeneralPage.dart\u00a0<\/em>and <em>DetailsPage.dart<\/em><\/p>\n<ul>\n<li>AppBar<\/li>\n<li>Grid and Stack<\/li>\n<li>BottomNavigationBar<\/li>\n<\/ul>\n<h2><span class=\"ez-toc-section\" id=\"Create-the-Widgets\"><\/span>Create the Widgets<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Let&#8217;s create the AppBar and BottomNavigationBar first, since they are not as complex as the Stack or Grid. I prefer creating a new widget and passing it to the <em>Scaffold<\/em> attribute. This will make refactoring at a later stage much easier.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Get-Widget-Title\"><\/span>Get Widget Title<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<pre class=\"font-size:14 line-height:20 lang:default decode:true\">String title = widget.title;<\/pre>\n<p>In order to retrieve the widget title, we have to call the parent widget in the same context.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"AppBar\"><\/span>AppBar<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<pre class=\"font-size:14 line-height:20 lang:default decode:true\">\/\/ Scaffold\r\n\r\nappBar: _getAppBar(),\r\n\r\n...\r\n\r\n_getAppBar(){\r\n\r\n  return new AppBar(\r\n\r\n    title: new Text(widget.title, style: TextStyle(color: Colors.blueGrey)),\r\n\r\n    backgroundColor: Colors.white,\r\n\r\n  );\r\n\r\n}\r\n\r\n<\/pre>\n<p>As long as the types match, we can use the same concept to create a custom <em>BottomNavigationBar.\u00a0<\/em><\/p>\n<h3><span class=\"ez-toc-section\" id=\"BottomNavigationBar-custom\"><\/span>BottomNavigationBar (custom)<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<pre class=\"font-size:14 line-height:20 lang:default decode:true\">\/\/ Scaffold\r\n\r\nbottomNavigationBar: _getBottomNavBar(),\r\n\r\n...\r\n\r\n_getBottomNavBar(){\r\n\r\n  return new CustomBottomNavBar();\r\n\r\n}<\/pre>\n<p>The <em>CustomBottomNavBar<\/em>\u00a0has a few minor functions and is therefore moved to a separate <em>Dart<\/em> file. I have included a simple <em>switch-case<\/em> to alternate the naming of the buttons according to their page (<em>General \/ Details<\/em>). At this point in development, you will notice something about the application&#8217;s architecture. We are able to drill down all pages to a widget within widgets containing widgets. It becomes crucial to have a clear structure in your application. The structure helps you to keep your code organized and traceable. The Flutter Development Team recommends using patterns for that case as your app grows (<a href=\"https:\/\/www.youtube.com\/watch?v=fahC3ky_zW0\">BLoC<\/a>).<\/p>\n<p>The\u00a0<em>CustomBottomNavBar<\/em> is a widget with two capsulated tasks. First, the correct widget according to their parent page is returned. Second, an event from a generic button is triggered. There is only one BottomNavBar template implemented. The only difference is the naming of the button and the connected events.<\/p>\n<p><em>Set correct naming of buttons according to parent page<\/em><\/p>\n<pre class=\"font-size:14 line-height:20 lang:default decode:true\">\/\/ CustomBottomAppBar.dart\r\n\r\n...\r\n\r\n  _switchNamesByPage(){\r\n\r\n      if(widgetName == \"general\"){\r\n\r\n        menu_left = \"menu\";\r\n\r\n        menu_right = \"donate\";\r\n\r\n        menu_center = \"contact\";\r\n\r\n      } else if(widgetName == \"detail\"){\r\n\r\n        menu_left = \"menu\";\r\n\r\n        menu_center = \"back\";\r\n\r\n        menu_right = \"contact\";\r\n\r\n      }\r\n\r\n  }<\/pre>\n<p><em>Set event trigger according to button name \/ tag<\/em><\/p>\n<pre class=\"font-size:14 line-height:20 lang:default decode:true\">\/\/ CustomBottomAppBar.dart\r\n\r\n...\r\n\r\n  _triggerEventByName(String tag){\r\n\r\n      if(tag == \"back\"){\r\n\r\n          Navigator.pop(context);\r\n\r\n        } else if(tag == \"menu\"){\r\n\r\n          ...\r\n\r\n        } else if(tag == \"contact\"){\r\n\r\n          ...\r\n\r\n        } else if(tag == \"donate\"){\r\n\r\n          ...\r\n\r\n        }\r\n\r\n  }\r\n\r\n}<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"size-large wp-image-15594 aligncenter\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/2019\/02\/BottomAppBarCorr-1024x302.png\" alt=\"Custom BottomNavigationBar\" width=\"1024\" height=\"302\" \/><\/p>\n<p>The complete\u00a0<em>CustomBottomNavBar\u00a0<\/em>can be seen as a collection of low level widgets. You can now connect all widgets and call the\u00a0<i>CustomBottomNavBar\u00a0<\/i>everywhere in your application.<\/p>\n<pre class=\"font-size:14 line-height:20 lang:default decode:true\">class CustomBottomBar extends StatelessWidget {\r\n\r\n  CustomBottomBar(this.widgetName);\r\n\r\n  @override\r\n\r\n  Widget build(BuildContext context) {\r\n\r\n    _switchNamesByPage();\r\n\r\n    return\r\n\r\n      SafeArea(\r\n\r\n      child: BottomAppBar(\r\n\r\n        child: Row(\r\n\r\n          mainAxisSize: MainAxisSize.max,\r\n\r\n          mainAxisAlignment: MainAxisAlignment.spaceBetween,\r\n\r\n          children: &lt;Widget&gt;[\r\n\r\n              _getMenu(context, menu_left),\r\n\r\n              _getMenu(context, menu_center),\r\n\r\n              _getMenu(context, menu_right),\r\n\r\n          ],\r\n\r\n        ),\r\n\r\n      ),\r\n\r\n    );\r\n\r\n  }\r\n\r\n  _getMenu(BuildContext context, String tag){\r\n\r\n    return Container(\r\n\r\n      child: FlatButton(\r\n\r\n          child: Text(tag,style: TextStyle(color: Colors.blue)),\r\n\r\n          onPressed: () {\r\n\r\n              _triggerEventByName(tag);\r\n\r\n          }\r\n\r\n      ),\r\n\r\n    );\r\n\r\n  }\r\n\r\n}<\/pre>\n<p>Bottom and Top widgets are done and only the main content per page remains. The main content is placed in the<em> body<\/em> attribute of the<em> Scaffold<\/em> widget. Each page has a different UI. The <em>GeneralPage<\/em> should contain something like a <em>grid<\/em>. The <em>DetailsPage<\/em> should be structured with a<em> stack<\/em> widget, because we need to build layers of widgets.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Grid\"><\/span>Grid<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>A <em>grid<\/em> is made out of <em>slivers<\/em>\u00a0and it is not scrollable by default. To make it scrollable requires a wrapper around the <em>SliverGrid<\/em>\u00a0within a\u00a0<em>CustomScrollView<\/em> widget. Before we implement the <em>grid<\/em>, I suggest you prepare a list of data that we can display in our <em>grid<\/em>. We have prepared the application structure, included assets in the previous article and can use them for this matter.<\/p>\n<p><em>Create display data<\/em><\/p>\n<ol>\n<li>Create a model<\/li>\n<li>Create display data<\/li>\n<li>Add display data models to a list<\/li>\n<li>List &lt;Model&gt; list = [model_00, model_01, &#8230;]<\/li>\n<\/ol>\n<p>Please refer to the <a href=\"https:\/\/github.com\/SeemannMx\/flutter_profile_final\">Github<\/a> repository and find the <em>Model.dart<\/em> and <em>Provider.dart<\/em> file. These files can help you to implement a data set, which we use to populate the <em>grid<\/em> widgets.<\/p>\n<pre class=\"font-size:14 line-height:20 lang:default decode:true\">\/\/ GeneralPage.dart - Scaffold\r\n\r\nbody: _getGeneralGrid(),\r\n\r\n...\r\n\r\n  _getGeneralGrid(){\r\n\r\n      return CustomScrollView(\r\n\r\n        slivers: &lt;Widget&gt;[\r\n\r\n          SliverGrid(\r\n\r\n            gridDelegate: _getGridDelegate(),\r\n\r\n            delegate: _getSliverDelegate(),\r\n\r\n          )\r\n\r\n        ],\r\n\r\n      );\r\n\r\n  }<\/pre>\n<p>The<em> gridDelegate<\/em> attribute defines the <em>grid<\/em> attributes, such as the number of axis and the space in between the axis.<\/p>\n<pre class=\"font-size:14 line-height:20 lang:default decode:true\">_getGridDelegate(){\r\n\r\n  return SliverGridDelegateWithFixedCrossAxisCount(\r\n\r\n    crossAxisCount: 2,\r\n\r\n    mainAxisSpacing: 2.0,\r\n\r\n    crossAxisSpacing: 2.0,\r\n\r\n  );\r\n\r\n}<\/pre>\n<p>The<em>\u00a0delegate<\/em> attribute defines the individual <i>sliver <\/i>inside the <em>grid<\/em>. This <em>sliver<\/em> can be as complex as you want as long as it does not violate the layout of the parent widget.<\/p>\n<pre class=\"font-size:14 line-height:20 lang:default decode:true\">_getSliverDelegate(){\r\n\r\n  return SliverChildBuilderDelegate((BuildContext context, int index){\r\n\r\n        \/\/ define a custom sliver with display data\r\n\r\n        return GeneralCell(list[index]);\r\n\r\n      },\r\n\r\n       childCount: list.length\r\n\r\n  );\r\n\r\n}<\/pre>\n<p>As you may notice, we are going down the widget tree wrapping widgets inside of widgets. The <em>GeneralCell<\/em> widget is a custom-built widget. It is used as a container for the content of each <em>grid sliver<\/em>.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"GenreralCell\"><\/span>GenreralCell<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>In this project, I decided to place the <em>routing<\/em> function inside the\u00a0<em>GeneralCell <\/em>widget. Basically, the widget is a plain StatefulWidget and provides a state where the device dimensions are calculated. Furthermore, it receives the <em>model\u00a0<\/em>for each <em>sliver<\/em>\u00a0from the <em>GeneralPage<\/em> widget.<\/p>\n<pre class=\"font-size:14 line-height:20 lang:default decode:true\">class GeneralCell extends StatefulWidget {\r\n\r\n  Model cellItem;\r\n\r\n  GeneralCell(this.cellItem);\r\n\r\n  @override\r\n\r\n  _GeneralCellState createState() =&gt; new _GeneralCellState();\r\n\r\n}\r\n\r\nclass _GeneralCellState extends State&lt;GeneralCell&gt; {\r\n\r\n  double calc_width = 0.0;\r\n\r\n  double calc_height = 0.0;\r\n\r\n  @override\r\n\r\n  Widget build(BuildContext context) {\r\n\r\n    this.calc_height = MediaQuery.of(context).size.height;\r\n\r\n    this.calc_width = MediaQuery.of(context).size.width;\r\n\r\n    return Container(\r\n\r\n      alignment: Alignment.center,\r\n\r\n      child: Column(\r\n\r\n        children: &lt;Widget&gt;[\r\n\r\n          GestureDetector(\r\n\r\n           child: _getImage(),\r\n\r\n           onTap: _goTo,\r\n\r\n          ),\r\n\r\n          _getText(),\r\n\r\n        ],\r\n\r\n      ),\r\n\r\n    );\/\/ card\r\n\r\n  }\r\n\r\n}<\/pre>\n<p>From here on matters become repetitive and we have to define our UI again. The structure has been laid out in the previous article. The code fragment below shows the two required sections:<\/p>\n<ol>\n<li>Image<\/li>\n<li>Text<\/li>\n<\/ol>\n<p>Each section stands for a new widget that holds some kind of content. In addition, the whole <em>sliver<\/em>\u00a0is wrapped with a <em>GestureDetector<\/em> widget. This widget provides functions to detect gestures like <em>onTap<\/em>, <em>onDoubleTap,<\/em> etc. The next steps are to define how we navigate to another page and where we have to place the animation logic for this. We need three functions, as shown in the code fragment above, to get the required widgets and to manage the routing.<\/p>\n<p>&nbsp;<\/p>\n<p><em>TEXT: \u00a0according to the generated model item<\/em><\/p>\n<pre class=\"font-size:14 line-height:20 lang:default decode:true\">\/\/ GeneralCell.dart\r\n\r\n...\r\n\r\n  _getText(){\r\n\r\n    return Container(\r\n\r\n        child:\r\n\r\n        Center(\r\n\r\n            child:\r\n\r\n            Text(widget.cellItem.name,\r\n\r\n                style: TextStyle(color: Colors.blueGrey)\r\n\r\n            )\r\n\r\n        )\r\n\r\n    );\r\n\r\n  }<\/pre>\n<p>&nbsp;<\/p>\n<p><em>IMAGE: \u00a0according to the generated model item, with Hero\u00a0<\/em><i>animation<\/i><\/p>\n<p>I removed the implementation for padding, decoration and borders in order to keep the code readable.\u00a0Please refer to the <a href=\"https:\/\/github.com\/SeemannMx\/flutter_profile_final\">Github<\/a> repository and find the <em>GeneralCell.dart <\/em>for the complete code example.<\/p>\n<pre class=\"font-size:14 line-height:20 lang:default decode:true\">\/\/ GeneralCell.dart\r\n\r\n...\r\n\r\n  _getImage(){\r\n\r\n    return Padding(\r\n\r\n      padding: ...,\r\n\r\n      child: Container(\r\n\r\n        child: Hero(\r\n\r\n          tag: widget.cellItem.pathToImage,\r\n\r\n          child: CircleAvatar(\r\n\r\n            backgroundImage: new AssetImage(widget.cellItem.pathToImage),\r\n\r\n            backgroundColor: Colors.black,\r\n\r\n            radius: calc_height * 0.06,\r\n\r\n          ),\r\n\r\n        ),\r\n\r\n      ),\r\n\r\n    );\r\n\r\n  }<\/pre>\n<p>Please notice that the <em>Hero<\/em> widget, which wraps only the <em>CircleAvatar<\/em> widget (image), has an identifier <em>tag<\/em>. This widget manages the animation for the page change. We have to ensure that the identifiers match in\u00a0<em>type<\/em> and <em>tag<\/em>.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"size-large wp-image-15589 aligncenter\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/2019\/02\/Hero-Navigation-corr-1024x591.png\" alt=\"Hero-Navigation\" width=\"1024\" height=\"591\" \/><\/p>\n<p>The <em>GeneralCell<\/em> widget contains the routing logic as well. We attach the <em>model<\/em>\u00a0that we tap and send it to the <em>DetailsWidget<\/em>. To simply send the data we use the <em>MaterialPageRoute<\/em> builder.<\/p>\n<pre class=\"font-size:14 line-height:20 lang:default decode:true\">\/\/ GeneralCell.dart\r\n\r\n...\r\n\r\n  _goTo(){\r\n\r\n    \/\/ slow down animation\r\n\r\n    timeDilation = 2.0;\r\n\r\n    Navigator.push(context,\r\n\r\n        MaterialPageRoute(\r\n\r\n            builder: (context) =&gt; DetailsPage(widget.cellItem)\r\n\r\n        )\r\n\r\n    );\r\n\r\n  }<\/pre>\n<p>Fifty percent of the application is completed and only the UI of the DetailsPage widget remains. This I will leave to you since it will be the same process as with the <em>GeneralPage <\/em>all over again. I will continue with the initial setup of the S<em>tack<\/em> widget, the Hero animation, and the extraction of the model.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Stack\"><\/span>Stack<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>A stack is a common principle in development. It can be seen as layers on top of each other. The structure of the <em>DetailsPage<\/em> is shown below and is organized into different sections:<\/p>\n<ul>\n<li>Header<\/li>\n<li>SubHeader<\/li>\n<li>Body<\/li>\n<li>Image<\/li>\n<\/ul>\n<p>All widgets, except the image, are collected in a <em>Column<\/em> widget, which we return to the <em>Scaffold<\/em> widget&#8217;s <em>body.<\/em><\/p>\n<pre class=\"font-size:14 line-height:20 lang:default decode:true\">\/\/ DetailsPage.dart\r\n\r\n...\r\n\r\n  _getStack(){\r\n\r\n    return Stack(\r\n\r\n      children: &lt;Widget&gt;[\r\n\r\n        Column(\r\n\r\n          children: &lt;Widget&gt;[\r\n\r\n            _getHeader(),\r\n\r\n            _getSubHeader(),\r\n\r\n            _getBody(),\r\n\r\n          ],\r\n\r\n        ),\r\n\r\n        _getImage(),\r\n\r\n      ],\r\n\r\n    );\r\n\r\n  }<\/pre>\n<p>You can organize these sections as you like and create layer by layer. Here, I will skip defining those layers except for the image layer.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"size-large wp-image-15590 aligncenter\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/2019\/02\/Stack-Widget-1024x419.png\" alt=\"DetailsPage - Structure \" width=\"1024\" height=\"419\" \/><\/p>\n<p>The image layer holds the <em>tag<\/em> that is identified during the <em>routing<\/em> process from <em>GeneralPage<\/em> \u2192\u00a0<em>GeneralCell<\/em> \u2192\u00a0<em>DetailsPage<\/em> with a <em>Hero<\/em> \u2192 <em>Hero<\/em> animation.<\/p>\n<pre class=\"font-size:14 line-height:20 lang:default decode:true\">\/\/ DetailsPage.dart\r\n\r\n...\r\n\r\n  _getImage(){\r\n\r\n      return Container(\r\n\r\n        child: Hero(\r\n\r\n          tag: widget.model_item.pathToImage,\r\n\r\n          child: CircleAvatar(\r\n\r\n            backgroundImage: new AssetImage(widget.model_item.pathToImage),\r\n\r\n            backgroundColor: Colors.black,\r\n\r\n            radius: calc_width*0.18,\r\n\r\n          ),\r\n\r\n        ),\r\n\r\n      ),\r\n\r\n  }<\/pre>\n<p>The <em>Hero tag<\/em> must contain the same identifier in both widgets. Otherwise, we cannot determine which widget we should animate. As mentioned above, you can continue implementing new custom widgets to fill the <em>DetailsPage<\/em>. When you&#8217;re ready, try to run the application and test the <em>Hero<\/em>\u00a0animation.<\/p>\n<p style=\"text-align: center;\"><em>And thus, the simple Profil App is completed. <\/em><\/p>\n<p>We have generated two pages with a nice animation. Feel free to adopt and extend this structure in your projects!<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Conclusion\"><\/span>Conclusion<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Building a simple two page application is not so hard, but even here you can see that structure is important. Widgets should be handled in a pattern (<a href=\"https:\/\/www.youtube.com\/watch?v=fahC3ky_zW0\">BLoC<\/a> or <a href=\"https:\/\/pub.dartlang.org\/packages\/scoped_model\">ScopeModel<\/a>) to keep the project organized. The application architecture can be deeply nested and hard to follow. Make sure you document all interfaces and define <em>Keys<\/em> for each widget. In this project, I removed all <em>Keys,<\/em>\u00a0but keep in mind that they are crucial for testing.<\/p>\n<p>If you are interested in more detailed concepts and processes, you can visit my other articles as mentioned below.<\/p>\n<p>The complete example can be found on\u00a0<a href=\"https:\/\/github.com\/SeemannMx\/flutter_profile_final\">GitHub<\/a>. Please be aware that I adjusted the code to make it more readable. Therefore, I refactored the code and removed imports from the article.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"All-articles-in-this-series\"><\/span>All articles in this series<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<ul>\n<li><a href=\"https:\/\/www.inovex.de\/blog\/flutter-beginning-of-a-new-era-part-1\/\">Flutter: The Beginning of New Era? (Part 1)<\/a><\/li>\n<li><a href=\"https:\/\/www.inovex.de\/blog\/flutter-new-concepts-part-2\/\">Flutter: New Concepts? (Part 2)<\/a><\/li>\n<li><a href=\"https:\/\/www.inovex.de\/blog\/flutter-the-profiler-part-3\/\">Flutter: The Profiler (Part 3)<\/a><\/li>\n<\/ul>\n<h2><span class=\"ez-toc-section\" id=\"Read-on\"><\/span>Read on<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Find out more about our <a href=\"https:\/\/www.inovex.de\/en\/our-services\/apps\/\">Android and iOS portfolio<\/a> or join us as a mobile developer! You can read more about Flutter development in particular on my\u00a0<a href=\"https:\/\/medium.com\/search?q=Tino%20Kallinich\">Flutter Medium Blog.\u00a0<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Previously we have created the basic structure of the Flutter application by defining the GeneralPage and the DetailsPage. In this article, I will concentrate on routing, layout, animation and data sharing.<\/p>\n","protected":false},"author":97,"featured_media":15079,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"ep_exclude_from_search":false,"footnotes":""},"tags":[510,376],"service":[420],"coauthors":[],"class_list":["post-15567","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","tag-apps-2","tag-cross-platform","service-apps"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Flutter: Finishing our first Mobile App - inovex blog<\/title>\n<meta name=\"description\" content=\"In this last article of my series on app development with Flutter we will have a look on routing, layout, animation and data sharing to finish our first flutter app!\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Flutter: Finishing our first Mobile App - inovex blog\" \/>\n<meta property=\"og:description\" content=\"In this last article of my series on app development with Flutter we will have a look on routing, layout, animation and data sharing to finish our first flutter app!\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/\" \/>\n<meta property=\"og:site_name\" content=\"inovex GmbH\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/inovexde\" \/>\n<meta property=\"article:published_time\" content=\"2019-03-19T08:10:18+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-03-17T06:59:32+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.inovex.de\/wp-content\/uploads\/2019\/01\/Flutter-4.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1920\" \/>\n\t<meta property=\"og:image:height\" content=\"1080\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Tino Kallinich-Friedrich\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/www.inovex.de\/wp-content\/uploads\/2019\/01\/Flutter-4-1024x576.png\" \/>\n<meta name=\"twitter:creator\" content=\"@mx_tino\" \/>\n<meta name=\"twitter:site\" content=\"@inovexgmbh\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Tino Kallinich-Friedrich\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"9\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/\"},\"author\":{\"name\":\"Tino Kallinich-Friedrich\",\"@id\":\"https:\/\/www.inovex.de\/de\/#\/schema\/person\/fcabd1e46229e68364e666b6732ff86f\"},\"headline\":\"Flutter: The Finalizer (Part 4)\",\"datePublished\":\"2019-03-19T08:10:18+00:00\",\"dateModified\":\"2026-03-17T06:59:32+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/\"},\"wordCount\":1424,\"commentCount\":1,\"publisher\":{\"@id\":\"https:\/\/www.inovex.de\/de\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/2019\/01\/Flutter-4.png\",\"keywords\":[\"Apps\",\"Cross-Platform\"],\"articleSection\":[\"Applications\",\"English Content\",\"General\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/\",\"url\":\"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/\",\"name\":\"Flutter: Finishing our first Mobile App - inovex blog\",\"isPartOf\":{\"@id\":\"https:\/\/www.inovex.de\/de\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/2019\/01\/Flutter-4.png\",\"datePublished\":\"2019-03-19T08:10:18+00:00\",\"dateModified\":\"2026-03-17T06:59:32+00:00\",\"description\":\"In this last article of my series on app development with Flutter we will have a look on routing, layout, animation and data sharing to finish our first flutter app!\",\"breadcrumb\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/#primaryimage\",\"url\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/2019\/01\/Flutter-4.png\",\"contentUrl\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/2019\/01\/Flutter-4.png\",\"width\":1920,\"height\":1080,\"caption\":\"Flutter Logo\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.inovex.de\/de\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Flutter: The Finalizer (Part 4)\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.inovex.de\/de\/#website\",\"url\":\"https:\/\/www.inovex.de\/de\/\",\"name\":\"inovex GmbH\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/www.inovex.de\/de\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.inovex.de\/de\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"de\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.inovex.de\/de\/#organization\",\"name\":\"inovex GmbH\",\"url\":\"https:\/\/www.inovex.de\/de\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/www.inovex.de\/de\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/2021\/03\/inovex-logo-16-9-1.png\",\"contentUrl\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/2021\/03\/inovex-logo-16-9-1.png\",\"width\":1921,\"height\":1081,\"caption\":\"inovex GmbH\"},\"image\":{\"@id\":\"https:\/\/www.inovex.de\/de\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/inovexde\",\"https:\/\/x.com\/inovexgmbh\",\"https:\/\/www.instagram.com\/inovexlife\/\",\"https:\/\/www.linkedin.com\/company\/inovex\",\"https:\/\/www.youtube.com\/channel\/UC7r66GT14hROB_RQsQBAQUQ\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.inovex.de\/de\/#\/schema\/person\/fcabd1e46229e68364e666b6732ff86f\",\"name\":\"Tino Kallinich-Friedrich\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/www.inovex.de\/de\/#\/schema\/person\/image\/163197d5916185dd18c854751cbd8b08\",\"url\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/cropped-profil-small-96x96.jpg\",\"contentUrl\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/cropped-profil-small-96x96.jpg\",\"caption\":\"Tino Kallinich-Friedrich\"},\"description\":\"B.Sc. Informatik and B.Sc. Nautik\",\"sameAs\":[\"https:\/\/www.linkedin.com\/in\/tino-k-friedrich\/\",\"https:\/\/x.com\/mx_tino\"],\"url\":\"https:\/\/www.inovex.de\/de\/blog\/author\/tkallinich-2-2-2-2-2\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Flutter: Finishing our first Mobile App - inovex blog","description":"In this last article of my series on app development with Flutter we will have a look on routing, layout, animation and data sharing to finish our first flutter app!","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/","og_locale":"de_DE","og_type":"article","og_title":"Flutter: Finishing our first Mobile App - inovex blog","og_description":"In this last article of my series on app development with Flutter we will have a look on routing, layout, animation and data sharing to finish our first flutter app!","og_url":"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/","og_site_name":"inovex GmbH","article_publisher":"https:\/\/www.facebook.com\/inovexde","article_published_time":"2019-03-19T08:10:18+00:00","article_modified_time":"2026-03-17T06:59:32+00:00","og_image":[{"width":1920,"height":1080,"url":"https:\/\/www.inovex.de\/wp-content\/uploads\/2019\/01\/Flutter-4.png","type":"image\/png"}],"author":"Tino Kallinich-Friedrich","twitter_card":"summary_large_image","twitter_image":"https:\/\/www.inovex.de\/wp-content\/uploads\/2019\/01\/Flutter-4-1024x576.png","twitter_creator":"@mx_tino","twitter_site":"@inovexgmbh","twitter_misc":{"Verfasst von":"Tino Kallinich-Friedrich","Gesch\u00e4tzte Lesezeit":"9\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/#article","isPartOf":{"@id":"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/"},"author":{"name":"Tino Kallinich-Friedrich","@id":"https:\/\/www.inovex.de\/de\/#\/schema\/person\/fcabd1e46229e68364e666b6732ff86f"},"headline":"Flutter: The Finalizer (Part 4)","datePublished":"2019-03-19T08:10:18+00:00","dateModified":"2026-03-17T06:59:32+00:00","mainEntityOfPage":{"@id":"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/"},"wordCount":1424,"commentCount":1,"publisher":{"@id":"https:\/\/www.inovex.de\/de\/#organization"},"image":{"@id":"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/#primaryimage"},"thumbnailUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/2019\/01\/Flutter-4.png","keywords":["Apps","Cross-Platform"],"articleSection":["Applications","English Content","General"],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/","url":"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/","name":"Flutter: Finishing our first Mobile App - inovex blog","isPartOf":{"@id":"https:\/\/www.inovex.de\/de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/#primaryimage"},"image":{"@id":"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/#primaryimage"},"thumbnailUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/2019\/01\/Flutter-4.png","datePublished":"2019-03-19T08:10:18+00:00","dateModified":"2026-03-17T06:59:32+00:00","description":"In this last article of my series on app development with Flutter we will have a look on routing, layout, animation and data sharing to finish our first flutter app!","breadcrumb":{"@id":"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/#primaryimage","url":"https:\/\/www.inovex.de\/wp-content\/uploads\/2019\/01\/Flutter-4.png","contentUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/2019\/01\/Flutter-4.png","width":1920,"height":1080,"caption":"Flutter Logo"},{"@type":"BreadcrumbList","@id":"https:\/\/www.inovex.de\/de\/blog\/flutter-the-finalizer-part-4\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.inovex.de\/de\/"},{"@type":"ListItem","position":2,"name":"Flutter: The Finalizer (Part 4)"}]},{"@type":"WebSite","@id":"https:\/\/www.inovex.de\/de\/#website","url":"https:\/\/www.inovex.de\/de\/","name":"inovex GmbH","description":"","publisher":{"@id":"https:\/\/www.inovex.de\/de\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.inovex.de\/de\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"de"},{"@type":"Organization","@id":"https:\/\/www.inovex.de\/de\/#organization","name":"inovex GmbH","url":"https:\/\/www.inovex.de\/de\/","logo":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/www.inovex.de\/de\/#\/schema\/logo\/image\/","url":"https:\/\/www.inovex.de\/wp-content\/uploads\/2021\/03\/inovex-logo-16-9-1.png","contentUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/2021\/03\/inovex-logo-16-9-1.png","width":1921,"height":1081,"caption":"inovex GmbH"},"image":{"@id":"https:\/\/www.inovex.de\/de\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/inovexde","https:\/\/x.com\/inovexgmbh","https:\/\/www.instagram.com\/inovexlife\/","https:\/\/www.linkedin.com\/company\/inovex","https:\/\/www.youtube.com\/channel\/UC7r66GT14hROB_RQsQBAQUQ"]},{"@type":"Person","@id":"https:\/\/www.inovex.de\/de\/#\/schema\/person\/fcabd1e46229e68364e666b6732ff86f","name":"Tino Kallinich-Friedrich","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/www.inovex.de\/de\/#\/schema\/person\/image\/163197d5916185dd18c854751cbd8b08","url":"https:\/\/www.inovex.de\/wp-content\/uploads\/cropped-profil-small-96x96.jpg","contentUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/cropped-profil-small-96x96.jpg","caption":"Tino Kallinich-Friedrich"},"description":"B.Sc. Informatik and B.Sc. Nautik","sameAs":["https:\/\/www.linkedin.com\/in\/tino-k-friedrich\/","https:\/\/x.com\/mx_tino"],"url":"https:\/\/www.inovex.de\/de\/blog\/author\/tkallinich-2-2-2-2-2\/"}]}},"_links":{"self":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/posts\/15567","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/users\/97"}],"replies":[{"embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/comments?post=15567"}],"version-history":[{"count":4,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/posts\/15567\/revisions"}],"predecessor-version":[{"id":66525,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/posts\/15567\/revisions\/66525"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/media\/15079"}],"wp:attachment":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/media?parent=15567"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/tags?post=15567"},{"taxonomy":"service","embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/service?post=15567"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/coauthors?post=15567"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}