I am creating a multi-paged app on flutter. When I am using the navigation in it, I am getting a black screen.
import 'package:flutter/material.dart';
void main() => runApp(MyHomePage());
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Page0(),
);
}
}
class Page0 extends StatefulWidget {
#override
_Page0State createState() => _Page0State();
}
class _Page0State extends State<Page0> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFF493597),
body: ListView(
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 15.0, left: 10.0),
),
SizedBox(
height: 25.0,
),
Padding(
padding: EdgeInsets.only(left: 40.0),
child: Row(
children: <Widget>[
Text(
'Expense',
style: TextStyle(
fontFamily: 'Montserrat',
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 25.0),
),
SizedBox(
width: 10.0,
),
Text(
'What',
style: TextStyle(
fontFamily: 'Montserrat',
color: Colors.white,
fontSize: 25.0,
),
),
],
),
),
SizedBox(height: 60.0),
Container(
margin: EdgeInsets.only(
left: 10.0,
right: 10.0,
),
height: MediaQuery.of(context).size.height - 150,
decoration: BoxDecoration(
color: Color(0xFFFCFCFC),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(75.0),
topRight: Radius.circular(75.0),
),
),
child: ListView(
primary: false,
padding: EdgeInsets.only(
left: 15.0,
right: 20.0,
top: 25.0,
),
children: <Widget>[
Padding(
padding: const EdgeInsets.only(
top: 30.0,
),
child: Column(
children: <Widget>[
//greeting text
Row(
children: <Widget>[
Expanded(
child: Center(
child: Text(
'Hello! :)',
style: TextStyle(
fontFamily: 'Permanent-Marker',
color: Colors.black,
fontSize: 30.0,
),
),
),
),
],
),
SizedBox(
height: 30.0,
),
//add button
Row(children: <Widget>[
Expanded(
flex: 1,
child: Container(
height: 100.0,
width: 100.0,
child: FittedBox(
child: FloatingActionButton(
elevation: 10.0,
backgroundColor: Colors.white,
child: Icon(
Icons.add,
color: Colors.black,
),
onPressed: () {
Navigator.push(context,MaterialPageRoute(builder: (context) => NewTrip()),);
},
),``
),
),
),
//add text
Expanded(
flex: 1,
child: Text(
'New trip',
style: TextStyle(
fontFamily: 'Nanum',
fontSize: 30.0,
),
),
),
]),
SizedBox(
height: 30.0,
),
//previous trip button
Row(
children: <Widget>[
Expanded(
flex: 1,
child: Container(
height: 100.0,
width: 100.0,
child: FittedBox(
child: FloatingActionButton(
elevation: 10.0,
backgroundColor: Colors.white,
onPressed: () {},
child: Icon(
Icons.assessment,
color: Colors.black,
),
),
),
),
),
//previous trip text
Expanded(
flex: 1,
child: Text(
'Previous trips',
style: TextStyle(
fontFamily: 'Nanum',
fontSize: 30.0,
),
),
)
],
),
SizedBox(
height: 50.0,
),
],
),
),
],
),
),
],
),
);
}
}
And the NewTrip widget is as follows
class NewTrip extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Text('NEW TRIP'),
),
);
}
}
The home page is loading fine but as soon as I click the new trip button, it shows a black screen. Probably there is an issue with MaterialApp or Scaffold but I am not able to fix it yet. Can anyone tell me what's the problem and how to fix it?
Updated the full code as requested in the comments.
So in NewTrip() remove MaterialApp since it inherits from the parent. Just return Scaffold.
class NewTrip extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Text('NEW TRIP'),
);
}
}
Okay so after some research on the internet, I found out that it's the FloatingActionButton that is causing the trouble.
I replaced the FloatingActionButton with MaterialButton and this fixed my issue.
Please check the full code edit from your code. Actually you are using two FloatingActionButton. So you need to use two heroTag with different name. I already added in the code. No problem with NewTrip class.
import 'package:flutter/material.dart';
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Page0(),
);
}
}
class Page0 extends StatefulWidget {
#override
_Page0State createState() => _Page0State();
}
class _Page0State extends State {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFF493597),
body: ListView(
children: [
Padding(
padding: EdgeInsets.only(top: 15.0, left: 10.0),
),
SizedBox(
height: 25.0,
),
Padding(
padding: EdgeInsets.only(left: 40.0),
child: Row(
children: [
Text(
'Expense',
style: TextStyle(
fontFamily: 'Montserrat',
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 25.0),
),
SizedBox(
width: 10.0,
),
Text(
'What',
style: TextStyle(
fontFamily: 'Montserrat',
color: Colors.white,
fontSize: 25.0,
),
),
],
),
),
SizedBox(height: 60.0),
Container(
margin: EdgeInsets.only(
left: 10.0,
right: 10.0,
),
height: MediaQuery.of(context).size.height - 150,
decoration: BoxDecoration(
color: Color(0xFFFCFCFC),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(75.0),
topRight: Radius.circular(75.0),
),
),
child: ListView(
primary: false,
padding: EdgeInsets.only(
left: 15.0,
right: 20.0,
top: 25.0,
),
children: [
Padding(
padding: const EdgeInsets.only(
top: 30.0,
),
child: Column(
children: [
//greeting text
Row(
children: [
Expanded(
child: Center(
child: Text(
'Hello! :)',
style: TextStyle(
fontFamily: 'Permanent-Marker',
color: Colors.black,
fontSize: 30.0,
),
),
),
),
],
),
SizedBox(
height: 30.0,
),
//add button
Row(children: [
Expanded(
flex: 1,
child: Container(
height: 100.0,
width: 100.0,
child: FittedBox(
child: FloatingActionButton(
heroTag: "btn",
elevation: 10.0,
backgroundColor: Colors.white,
child: Icon(
Icons.add,
color: Colors.black,
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => NewTrip()),
);
},
),
),
),
),
//add text
Expanded(
flex: 1,
child: Text(
'New trip',
style: TextStyle(
fontFamily: 'Nanum',
fontSize: 30.0,
),
),
),
]),
SizedBox(
height: 30.0,
),
//previous trip button
Row(
children: [
Expanded(
flex: 1,
child: Container(
height: 100.0,
width: 100.0,
child: FittedBox(
child: FloatingActionButton(
heroTag: "btn1",
elevation: 10.0,
backgroundColor: Colors.white,
onPressed: () {},
child: Icon(
Icons.assessment,
color: Colors.black,
),
),
),
),
),
//previous trip text
Expanded(
flex: 1,
child: Text(
'Previous trips',
style: TextStyle(
fontFamily: 'Nanum',
fontSize: 30.0,
),
),
)
],
),
SizedBox(
height: 50.0,
),
],
),
),
],
),
),
],
),
);
}
}
NewTrip class
class NewTrip extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Text('NEW TRIP'),
);
}
}
Before:
class NewTrip extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Text('NEW TRIP'),
);
}
}
So to Solve this problem we wrap the new navigate widget with scaffold widget
Solution After:
class NewTrip extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Material(
child: Text('NEW TRIP'),
),
);
}
}
The issue is that you are using a materialApp inside another materialApp
Navigator just changes the pages and we don't need separate materialApp in NewTrip().
So the NewTrip should be as follow
class NewTrip extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Text('NEW TRIP'),
);
}
}
I believe there can only be one MaterialApp Widget in the entire Flutter application because MaterialApp Widget is likely to be the main or core component of Flutter. So when you try to navigate to a new screen try returning Scaffold Widget instead of MaterialApp Widget.
class NewTrip extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Text('NEW TRIP'),
);
}
}
Use ThemeData, along with the parameter scaffoldBackgroundColor.
For example:
ThemeData (
scaffoldBackgroundColor: Colors.black,
)
In my case, it is caused by:
// to set portait screen orientation
SystemChrome.setPreferredOrientation([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
// Instead i use `android:screenOrientation="portrait"` on my AndroidManifest.xml.
That I declared when the page widget render. Removed it solve my black screen issue.
Change scaffoldBackgroundColor
theme: ThemeData(
primarySwatch: Colors.blue,
scaffoldBackgroundColor: Colors.white, //here
visualDensity: VisualDensity.adaptivePlatformDensity,
),
class NewTrip extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Text('NEW TRIP'),
);
}
}
simply just put scaffold in next page that's it.
If the page you navigate does not contain Scaffold the page will be black since Scaffold Implements the basic material design visual layout structure so apply Scaffold and the parent widget material app.
The problem you are facing because the widget you are navigating does not have any material widget.
Just wrap the navigated screen's return widget with Scaffold as a parent.
Related
I have a screen with a list of Widgets, each widet is a Dismissible with a ListTile inside, but when I swipe, the content is going outside (as pointed by the red arrow), this may be happening because of the padding around the Dismissible. There is a way to fix it?
You are not giving your code sample in your question so, I have make this type of widget to solve this problem. Please refer the code, (It's may be help to you),
class _MyHomePageState extends State<MyHomePage> {
final itemsList = List<String>.generate(10, (n) => "List item ${n}");
ListView generateItemsList() {
return ListView.builder(
itemCount: itemsList.length,
itemBuilder: (context, index) {
return Container(
margin: EdgeInsets.symmetric(horizontal: 50, vertical: 10),
child: Dismissible(
key: Key(itemsList[index]),
background: slideRightBackground(),
secondaryBackground: slideLeftBackground(),
child: InkWell(
onTap: () {
print("${itemsList[index]} clicked");
},
child: ListTile(
tileColor: Colors.yellow,
title: Text('${itemsList[index]}'))),
),
);
}
);
}
Widget slideRightBackground() {
return Container(
color: Colors.green,
child: Align(
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
SizedBox(
width: 20,
),
Icon(
Icons.edit,
color: Colors.white,
),
Text(
" Edit",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w700,
),
textAlign: TextAlign.left,
),
],
),
alignment: Alignment.centerLeft,
),
);
}
Widget slideLeftBackground() {
return Container(
color: Colors.red,
child: Align(
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Icon(
Icons.delete,
color: Colors.white,
),
Text(
" Delete",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w700,
),
textAlign: TextAlign.right,
),
SizedBox(
width: 20,
),
],
),
alignment: Alignment.centerRight,
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: generateItemsList(),
);
}
}
Output :
I am still new to flutter, and I want to position the box in the screenshot below, not in the centre of the screen, but at a certain distance away from the left side with text inside the box.
I have tried the positioning widget but still no luck.
Any advice on what widget I would use, and how to do so properly?
#override
Widget build(BuildContext context) {
return DecoratedBox(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/startbackground.jpg"),
fit: BoxFit.cover),
),
child: Center(
child: Container(
height: 500.0,
width: 120.0,
color: Colors.blue[50],
child: Align(
alignment: Alignment.topRight,
child: FlutterLogo(
size: 60,
),
),
),
));
}
}
Try out that code. I mainly used containers, paddings, alignment property as well as the axis alignment for the column. With that I achieved what you can see on the screenshot below. In order to use an image behind all that, I would just simply recommend to use a stack and then this whole code with some adaptations. The colors are just illustrative. You could set all of them transparent.
Here is the screenshot:
And here is the code:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.blue,
appBar: AppBar(
title: Text("EXAMPLE"),
),
body: Container(
color: Colors.orangeAccent,
height: double.infinity,
width: double.infinity,
alignment: Alignment.bottomLeft,
child: UnconstrainedBox(
child: Padding(
padding: const EdgeInsets.only(left: 50, bottom: 50),
child: Container(
height: 400,
width: 200,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
flex: 1,
child: Container(
child: Text("Text", style: TextStyle(fontSize: 30, fontWeight: FontWeight.w700),textAlign: TextAlign.left,),
color: Colors.purpleAccent,
),
),
Expanded(
flex: 3,
child: Container(
child: Text("Some Text", style: TextStyle(fontSize: 60, fontWeight: FontWeight.w700),),
color: Colors.purpleAccent,
),
),
Expanded(
flex: 3,
child: Container(
child: Text("Some Text", style: TextStyle(fontSize: 60, fontWeight: FontWeight.w700),),
color: Colors.teal,
),
),
Expanded(
flex: 2,
child: Padding(
padding: EdgeInsets.all(15),
child: FlatButton(
minWidth: 200,
onPressed: (){},
child: Text(
"HI",
style: TextStyle(
color: Color(0xff7638c9),
fontSize: 11),
),
color: Colors.transparent,
shape: RoundedRectangleBorder(
side: BorderSide(color: Colors.purple),
borderRadius: BorderRadius.circular(18.0),
),
),
),
),
],
),
),
),
),
),
);
}
}
Defines a background image that will be applied to all screens in the layout, according to the code below.
class _LoginWidgetState extends State<LoginWidget> {
#override
Widget build(BuildContext context) {
return Container(
child: Stack(
fit: StackFit.expand,
children: <Widget>[
Image.asset(
"assets/img/NewYorkCity.jpeg",
fit: BoxFit.cover,
),
PageView(
children: <Widget>[
SignUpPageWidget(),
LoginPageWidget(),
SignInPageWidget(),
],
)
],
),
);
}
}
And the layout with the Material and Scaffold widgets is not applied stylization color: Colors.white.withOpacity(0.8) and, therefore, the background image is not displayed. The screen is white, as opacity has not been applied to the background.
class _SignUpPageWidgetState extends State<SignUpPageWidget> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
color: Colors.white.withOpacity(0.9),
padding: EdgeInsets.symmetric(horizontal: 40),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(
Icons.local_taxi,
size: 50,
color: Theme.of(context).accentColor,
),
Container(
width: double.infinity,
child: Text(
"Already have an account?",
textAlign: TextAlign.center,
style: TextStyle(
decoration: TextDecoration.none,
fontSize: 16,
fontWeight: FontWeight.bold,
color: Theme.of(context).accentColor,
),
),
),
CircleButton(
label: "Sign Up",
)
],
),
),
);
}
}
Removing the Scaffold or Material widget, the color: Colors.white.withOpacity (0.8) stylization is applied.
class _SignUpPageWidgetState extends State<SignUpPageWidget> {
#override
Widget build(BuildContext context) {
return Container(
color: Colors.white.withOpacity(0.9),
padding: EdgeInsets.symmetric(horizontal: 40),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(
Icons.local_taxi,
size: 50,
color: Theme.of(context).accentColor,
),
Container(
width: double.infinity,
child: Text(
"Already have an account?",
textAlign: TextAlign.center,
style: TextStyle(
decoration: TextDecoration.none,
fontSize: 16,
fontWeight: FontWeight.bold,
color: Theme.of(context).accentColor,
),
),
),
CircleButton(
label: "Sign Up",
)
],
),
);
}
}
Would you know how to use the Scaffold and Material widgets by applying this stylization?
Add backgroundColor: Colors.transparent to your Scaffold widget
For Material add type:MaterialType.transparency
I am trying to make a fruithero flutter app but while changing my main page to another page, It shows only a black screen on my android emulator in laptop and on my phone, but in https://flutlab.io/ it shows perfectly, What is the problem that the app is not working on local emulator or in my phone but working on online IDE
Showing an Eror like this: -
There are multiple heroes that share the same tag within a subtree.
main.dart
import 'package:flutter/material.dart';
import './detailsPage.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
debugShowCheckedModeBanner: false,
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFF21BFBD),
body: ListView(
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 15.0, left: 10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
IconButton(
icon: Icon(Icons.arrow_back_ios),
color: Colors.white,
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailsPage(),
),
);
},
),
Container(
width: 125.0,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
IconButton(
icon: Icon(Icons.filter_list),
color: Colors.white,
onPressed: () {},
),
IconButton(
icon: Icon(Icons.menu),
color: Colors.white,
onPressed: () {},
),
],
),
),
],
),
),
SizedBox(
height: 25.0,
),
Padding(
padding: EdgeInsets.only(left: 40.0),
child: Row(
children: <Widget>[
Text(
'Healthy',
style: TextStyle(
fontFamily: 'Mont',
color: Colors.white,
fontSize: 25.0,
fontWeight: FontWeight.bold),
),
SizedBox(width: 10.0),
Text(
'Food',
style: TextStyle(
fontFamily: 'Mont', color: Colors.white, fontSize: 25.0),
),
],
),
),
SizedBox(
height: 40.0,
),
Container(
height: MediaQuery.of(context).size.height - 185.0,
decoration: BoxDecoration(
color: Colors.white,
borderRadius:
BorderRadius.only(topLeft: Radius.circular(75.0))),
child: ListView(
primary: false,
padding: EdgeInsets.only(left: 25.0, right: 20.0),
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 45.0),
child: Container(
height: MediaQuery.of(context).size.height / 1.68,
child: ListView(
children: <Widget>[
_buildFoodItem('images/one.png', 'Salmon', '\$24.0'),
_buildFoodItem('images/two.png', 'Spring', '\$22.0'),
_buildFoodItem('images/three.png', 'Sprite', '\$34.0'),
_buildFoodItem('images/one.png', 'Mut', '\$12.0')
],
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(
height: 65.0,
width: MediaQuery.of(context).size.width / 6,
decoration: BoxDecoration(
border: Border.all(
color: Colors.grey,
style: BorderStyle.solid,
width: 1.0,
),
borderRadius: BorderRadius.circular(20)),
child: Center(
child: Icon(
Icons.search,
color: Colors.black,
),
),
),
Container(
height: 65.0,
width: MediaQuery.of(context).size.width / 6,
decoration: BoxDecoration(
border: Border.all(
color: Colors.grey,
style: BorderStyle.solid,
width: 1.0,
),
borderRadius: BorderRadius.circular(20)),
child: Center(
child: Icon(
Icons.shopping_cart,
color: Colors.black,
),
),
),
Container(
height: 65.0,
width: MediaQuery.of(context).size.width / 2,
decoration: BoxDecoration(
color: Color(0xff170F1F),
border: Border.all(
color: Colors.grey,
style: BorderStyle.solid,
width: 1.0,
),
borderRadius: BorderRadius.circular(20)),
child: Center(
child: Text(
'Checkout',
style: TextStyle(
fontSize: 18.0,
color: Colors.white,
fontFamily: 'Mont',
),
)),
),
],
),
],
),
),
],
),
);
}
Widget _buildFoodItem(String imgPath, String foodName, String price) {
return Padding(
padding: EdgeInsets.only(left: 10.0, right: 10.0, top: 10.0),
child: InkWell(
onTap: () {
Navigator.push( //Here is the Navigator.push()
context,
MaterialPageRoute(builder: (BuildContext context) {
return DetailsPage();
}),
);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(
child: Row(
children: [
Hero(
tag: imgPath,
child: Image(
image: AssetImage(imgPath),
fit: BoxFit.cover,
height: 75.0,
width: 75.0,
),
),
SizedBox(width: 10.0),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
foodName,
style: TextStyle(
fontFamily: 'Mont',
fontSize: 17.0,
fontWeight: FontWeight.bold),
),
Text(
price,
style: TextStyle(
fontFamily: 'Mont',
fontSize: 15.0,
color: Colors.grey),
)
],
),
],
),
),
IconButton(
icon: Icon(Icons.add),
color: Colors.black,
onPressed: () {},
),
],
),
),
);
}
}
Navigator.push code is like this:
Navigator.push(
context,
MaterialPageRoute(builder: (BuildContext context) {
return DetailsPage();
}),
);
detailsPage.dart
import 'package:flutter/material.dart';
class DetailsPage extends StatefulWidget {
#override
_DetailsPageState createState() => _DetailsPageState();
}
class _DetailsPageState extends State<DetailsPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFF7A9BEE),
appBar: AppBar(
leading: IconButton(
onPressed: () {
Navigator.of(context).pop();
},
icon: Icon(Icons.arrow_back_ios),
color: Colors.white,
),
backgroundColor: Colors.transparent,
elevation: 0.0,
title: Text(
'Details',
style: TextStyle(
fontFamily: 'Mont',
fontSize: 18.0,
color: Colors.white,
),
),
centerTitle: true,
actions: <Widget>[
IconButton(
icon: Icon(Icons.more_horiz),
onPressed: () {},
color: Colors.white,
),
],
),
);
}
}
Here is git Repository link: 1
i dont see the hero widget in the detailsPage.dart, when you set up a Hero widget in main and Navigate to detailsPage, you have to set up a hero widget to receive a hero transition from the main page, and because you have a listView in main you have to give a dynamic tag to each list item because each hero must have a tag associated with it so when it transfer to different layout it knows which hero to transit to it,
you already set up a hero tag in main page and you already give it a tag as tag: imgPath
tag is like an id for that hero, now you need to set the same tag (id) in the detailsPage,
please watch this to understand the logic Hero Flutter Widget
You should use Hero Widgets on both screens.
I couldn't find the Hero widget, nor the tag and not the image that you used on your first screen too (AssetImage(imgPath))
Try and parameterize using the propoer Hero specs.
Here you can find an good example and instructions: Flutter example
I was listening to music on Spotify, and started wondering how to get the exact animation shown in the Artist page.
It includes sliver navigation, but also text on top of the artist image (maybe a simple stack would work)
Also there's a floating action widget (shuffle play) and, my favourite, the artist image ZOOMS back when scrolled up!
I want to recreate it on Flutter.
Can anyone help me?
I don't use Spotify.
but I hope It could give good beginning.
import 'dart:math';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
themeMode: ThemeMode.dark,
darkTheme: ThemeData.dark(),
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
home: Scaffold(
backgroundColor: Colors.black,
body: SafeArea(
child: MyHomePage(),
),
),
);
}
}
double _appTopBarHeight = 60;
String artistName = 'Dennis Lloyd';
class MyHomePage extends StatelessWidget {
const MyHomePage({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return CustomScrollView(
slivers: [
SliverPersistentHeader(
delegate: MyDelegate(),
floating: true,
pinned: true,
),
SliverList(
delegate: SliverChildBuilderDelegate(
(_, index) => Container(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(index.toString()),
SizedBox(width: 10),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Title'),
Text('Subtitle'),
],
),
),
SizedBox(width: 10),
Icon(
Icons.more_vert,
color: Colors.white,
),
],
),
),
),
childCount: 100,
),
),
],
);
}
}
class MyDelegate extends SliverPersistentHeaderDelegate {
#override
Widget build(_, double shrinkOffset, bool overlapsContent) {
var shrinkPercentage =
min(1, shrinkOffset / (maxExtent - minExtent)).toDouble();
return Stack(
overflow: Overflow.clip,
fit: StackFit.expand,
children: [
Positioned(
top: 0,
left: 0,
right: 0,
child: Container(
height: _appTopBarHeight,
color: Colors.black,
),
),
Column(
children: [
Flexible(
flex: 1,
child: Stack(
children: [
Container(
color: Colors.black,
),
Opacity(
opacity: 1 - shrinkPercentage,
child: Container(
height: 900,
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.fitWidth,
alignment: FractionalOffset.topCenter,
image: NetworkImage(
'https://66.media.tumblr.com/c063f0b98040e8ec4b07547263b8aa15/tumblr_inline_ppignaTjX21s9on4d_540.jpg'),
)),
),
),
],
),
),
Container(
height: 50,
)
],
),
Stack(
overflow: Overflow.clip,
fit: StackFit.expand,
children: [
Positioned(
top: 0,
left: 0,
right: 0,
child: Column(
children: [
Container(
height: _appTopBarHeight,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Icon(
Icons.arrow_back,
color: Colors.white,
),
Flexible(
child: Opacity(
opacity: shrinkPercentage,
child: Text(
artistName,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
),
),
Icon(
Icons.more_vert,
color: Colors.white,
),
],
),
),
),
Opacity(
opacity: max(1 - shrinkPercentage * 6, 0),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
SizedBox(height: 200),
Text(
artistName,
style: TextStyle(
fontSize: 48,
fontWeight: FontWeight.bold,
),
),
Text(
'Subtitle',
style: TextStyle(color: Colors.white),
),
],
),
)
],
),
),
Positioned(
bottom: 0,
left: 0,
right: 0,
child: Center(
child: RaisedButton(
color: Colors.green,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18.0),
side: BorderSide(),
),
onPressed: () {},
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 30, vertical: 5),
child: Text(
'SHUFFLE PLAY',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w400,
),
),
),
),
),
)
],
),
],
);
}
#override
double get maxExtent => 400;
#override
double get minExtent => 110;
#override
bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) => true;
}