How to make this design in flutter - flutter

I have to make it carousel slider and the data will be come from API's. So, how we can show API's data in vertical format like one by one. So you can help me in these.
So, this the image like how I have to make from taking data through API's.

Without more info from your side it's hard to provide you with an accurate implementation but here's what I've been able to reproduce:
I've been using the package polygon to draw the star-like shapes (note that you might not be needing this package in a future Flutter version) and here's the full code:
import 'package:flutter/material.dart';
import 'package:polygon/polygon.dart';
class CryptoCard extends StatelessWidget {
final int id;
final String title;
final double bid;
final String creatorName;
final String creatorPictureUrl;
final double height;
final double width;
const CryptoCard({
super.key,
required this.id,
required this.title,
required this.bid,
required this.creatorName,
required this.creatorPictureUrl,
this.height = 500.0,
this.width = 400.0,
});
#override
Widget build(BuildContext context) {
return Stack(
children: [
Container(
alignment: Alignment.bottomCenter,
margin: const EdgeInsets.symmetric(vertical: 12, horizontal: 12),
height: height,
width: width,
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
color: Color(0xFFc4c4c4),
borderRadius: BorderRadius.circular(48),
),
child: _InfoContainer(
title: title,
imageUrl: creatorPictureUrl,
name: creatorName,
bid: bid,
),
),
Positioned(
left: 0,
top: 0,
child: _IdHandler(id),
),
],
);
}
}
class _IdHandler extends StatelessWidget {
final int id;
const _IdHandler(this.id);
#override
Widget build(BuildContext context) {
const size = 120.0;
return Container(
height: size,
width: size,
alignment: Alignment.center,
decoration: ShapeDecoration(
shape: PolygonBorder(
polygon: RegularStarPolygon(
vertexCount: 15,
ratio: 0.84,
),
radius: 20,
),
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [Color(0xFF40c75c), Color(0xFF70fbb0)],
),
),
child: Text(
'$id',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 48,
),
),
);
}
}
class _InfoContainer extends StatelessWidget {
final String title;
final String imageUrl;
final String name;
final double bid;
const _InfoContainer({
required this.title,
required this.imageUrl,
required this.name,
required this.bid,
});
#override
Widget build(BuildContext context) {
return Container(
width: double.maxFinite,
padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 8),
color: Color(0xFF9c9c9c),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(title, style: TextStyle(color: Colors.white, fontSize: 20)),
const SizedBox(height: 12),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_Creator(name: name, imageUrl: imageUrl),
const SizedBox(width: 12),
_Bid(bid),
],
),
const SizedBox(height: 12),
const _Bottom(),
],
),
);
}
}
class _Creator extends StatelessWidget {
final String name;
final String imageUrl;
const _Creator({required this.name, required this.imageUrl});
#override
Widget build(BuildContext context) {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
_CreatorAvatar(imageUrl),
const SizedBox(width: 12),
Flexible(
child: _Section(
title: 'Creator',
content: name,
),
),
],
);
}
}
class _CreatorAvatar extends StatelessWidget {
final String imageUrl;
const _CreatorAvatar(this.imageUrl);
#override
Widget build(BuildContext context) {
const size = 48.0;
return Stack(
clipBehavior: Clip.none,
children: [
Container(
clipBehavior: Clip.antiAlias,
width: size,
height: size,
decoration: BoxDecoration(
shape: BoxShape.circle,
image: DecorationImage(image: NetworkImage(imageUrl), fit: BoxFit.cover),
border: Border.all(color: Colors.white, width: 2),
),
),
Positioned(
bottom: 0,
right: -8,
child: Container(
padding: const EdgeInsets.all(4),
decoration: ShapeDecoration(
shape: PolygonBorder(
polygon: RegularStarPolygon(
vertexCount: 10,
ratio: 0.8,
),
),
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [Color(0xFF40c75c), Color(0xFF70fbb0)],
),
),
child: Icon(Icons.check, color: Colors.white, size: 16),
),
),
],
);
}
}
class _Bid extends StatelessWidget {
final double bid;
const _Bid(this.bid);
#override
Widget build(BuildContext context) {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
Container(
height: 48,
width: 48,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Color(0xFFb9b9b9),
),
),
const SizedBox(width: 12),
Flexible(
child: _Section(
title: 'Current bid',
content: '$bid ETH',
),
),
],
);
}
}
class _Section extends StatelessWidget {
final String title;
final String content;
const _Section({required this.title, required this.content});
#override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(title, style: TextStyle(color: Colors.white, fontSize: 10)),
Text(content, style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold)),
],
);
}
}
class _Bottom extends StatelessWidget {
const _Bottom();
#override
Widget build(BuildContext context) {
return Container(
width: 168.0,
height: 48.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(24),
color: Colors.white,
),
);
}
}
You can also check the live example on zapp.run.

Related

FirebaseAnimatedList doesn't return anything

I'm trying to write an app that will detect Barcode ID. Once detected, it will fetch value in my Firebase Database and display them inside my Widget. I want my widget to be dynamic since i don't know how many items could be inside each ID. So i tried using FirebaseAnimatedList class. Issue is i can't get my Widget show up in my page at all.
Here's my code
import 'dart:async';
import 'package:firebase_database/ui/firebase_animated_list.dart';
import 'package:flutter/material.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:logistec/widget/result_page/productlist.dart';
class Scanning_Result_Page extends StatefulWidget {
Scanning_Result_Page(this.phyid, {Key? key}) : super(key: key);
String phyid;
#override
State<Scanning_Result_Page> createState() => _Scanning_Result_PageState();
}
class _Scanning_Result_PageState extends State<Scanning_Result_Page> {
late String productcode;
late String productname;
late int quantity;
late Query _ref =
FirebaseDatabase.instance.ref().child('Database').child(widget.phyid);
//firebase structure currently goes like this
//PHYID
//|---number
//|-----items_name
//|-----items_codes etc...
//Therefore i need it to first fetch PHYID
//then after that, use for loop from 0 to the full lenght of that ID
//
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: PreferredSize(
preferredSize: Size(40, 40),
child: AppBar(
backgroundColor: Colors.amber.shade400,
)),
body: Container(
height: double.infinity,
child: FirebaseAnimatedList(
shrinkWrap: true,
query: _ref.equalTo(widget.phyid),
itemBuilder: (BuildContext context, DataSnapshot snapshot,
Animation<double> animation, int index) {
Map database = snapshot.value as Map;
if (database != null) {
//result = key - phyid | value - 0?
return ProductList(
productcode: 'Test 1', //will change this later. just need it to work for now.
productname: 'Test 1',
serial: 'Test 1',
quantity: 1,
phyid_result: widget.phyid,
);
} else {
return Text("no data");
}
return CircularProgressIndicator();
},
),
),
);
}
}
And here's my Widget page. (I don't think it's related to my issue but i'll include them regardless.)
import 'package:flutter/material.dart';
class ProductList extends StatelessWidget {
ProductList({
Key? key,
required this.productcode,
required this.productname,
required this.quantity,
required this.phyid_result,
required this.serial,
}) : super(key: key);
final String productcode;
final String productname;
final int quantity;
final String phyid_result;
final String serial;
//The Look in my head
//Each Container will have
///////////////////////////////////
///ProductCode /
///ProductName /
/// /
/// ///////////////////////////////
/// Quantity/
/// ///////////////////////////////
final appBar = AppBar();
#override
Widget build(BuildContext context) {
final screenSize = MediaQuery.of(context);
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
resizeToAvoidBottomInset: false,
body: CustomScrollView(
scrollDirection: Axis.vertical,
slivers: [
SliverList(
delegate: SliverChildListDelegate([
Container(
padding: const EdgeInsets.all(15.0),
alignment: Alignment.center,
color: Colors.black,
height: 70.0,
child: Text(
phyid_result,
style: const TextStyle(
color: Colors.white,
fontSize: 25,
),
),
),
Container(
height: screenSize.size.height,
decoration: BoxDecoration(
border: Border.all(color: Colors.grey.shade600)),
child: IntrinsicHeight(
child: Column(
//mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
padding: EdgeInsets.all(5),
child: Text(
productcode,
style: const TextStyle(fontSize: 20),
),
),
Container(
padding: EdgeInsets.all(5),
width: screenSize.size.width,
decoration: BoxDecoration(
border: Border.all(
color: Colors.grey.shade200,
strokeAlign: StrokeAlign.inside)),
child: Text(
productname,
style: const TextStyle(fontSize: 20),
),
),
Container(
padding: EdgeInsets.all(5),
width: screenSize.size.width,
decoration: BoxDecoration(
border: Border.all(
color: Colors.grey.shade200,
strokeAlign: StrokeAlign.inside)),
child: Text(
serial,
style: const TextStyle(fontSize: 20),
),
),
Align(
alignment: Alignment.topRight,
child: Flexible(
fit: FlexFit.loose,
child: SizedBox(
width: 90,
child: Container(
decoration: BoxDecoration(
border:
Border.all(color: Colors.grey.shade200),
),
padding: EdgeInsets.all(5),
child: Text(
'Quantity : \n\v${quantity}',
style: TextStyle(fontSize: 18),
textAlign: TextAlign.right,
)),
),
),
)
],
),
),
),
]))
],
),
),
);
}
}
The Scaffold part works. But everything inside FirebaseAnimated List all the way to CircularProgressIndicator doesn't work at all. It didn't even return if else statement. Just empty blank page with Scaffold.
The Widget itself will work fine if i remove everything out, and return only the ProductList widget itself. I tried searching on Google and didn't find anyone having issue like me. So i think i'm stuck. Does anyone know what could be the issue? Thanks for the assistance in advance!
So i solve my own issue.
It turns out that my Widget is the actual root cause. I don't think SliverList is playing well with FirebaseAnimatedList (maybe because they are doing essentially the same thing?) So i refactor and remove everything related to SliverList.
Widget build(BuildContext context) {
final screenSize = MediaQuery.of(context);
return Container(
decoration:
BoxDecoration(border: Border.all(color: Colors.grey.shade600)),
child: Column(
//mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
padding: EdgeInsets.all(5),
child: Text(
productcode,
style: const TextStyle(fontSize: 20),
),
),
Container(
padding: EdgeInsets.all(5),
width: screenSize.size.width,
decoration: BoxDecoration(
border: Border.all(
color: Colors.grey.shade200,
strokeAlign: StrokeAlign.inside)),
child: Text(
productname,
style: const TextStyle(fontSize: 20),
),
),
Container(
padding: EdgeInsets.all(5),
width: screenSize.size.width,
decoration: BoxDecoration(
border: Border.all(
color: Colors.grey.shade200,
strokeAlign: StrokeAlign.inside)),
child: Text(
serial,
style: const TextStyle(fontSize: 20),
),
),
Align(
alignment: Alignment.topRight,
child: Flexible(
fit: FlexFit.loose,
child: SizedBox(
width: 90,
child: Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.grey.shade200),
),
padding: EdgeInsets.all(5),
child: Text(
'Quantity : \n\v${quantity}',
style: TextStyle(fontSize: 18),
textAlign: TextAlign.right,
)),
),
),
)
],
),
);
Then i reimplemented it into my pages. Now it works as expected. all is well again!

flutter - PageView Builder & Card - displaying different info on each card

I am trying to use PageView and Card. My objective is to display different information on the fourth cards that the user can see.
To be more precise, on one card, I could display a title for example. On the second card, I will display dates, on the third card, it could be some random text...
I hope this is clear.
To give you more color on this, the information will come from FireBase.
I do not know how to do this easily. I have considered to create 4 widget myCard, with different info on it and to use them. But I would like to do something more professional and efficient. Thank you
About FireBase, I do not use json. I have a simple document in FireBase. In this document, I have several fields, like 'price' 'quantity' 'reference'...
I just want that each card to display two or three fields from this FireBase document.
class MyBodyWindMill extends StatefulWidget {
const MyBodyWindMill({Key key}) : super(key: key);
#override
_MyBodyWindMillState createState() => _MyBodyWindMillState();
}
class _MyBodyWindMillState extends State<MyBodyWindMill> {
#override
Widget build(BuildContext context) {
return
Container(
height: 260,
child: PageView.builder(controller: PageController(viewportFraction: 0.88),
itemCount: 4,
itemBuilder: ( _, i){
return GestureDetector(
child: Container(
padding: const EdgeInsets.only(left:20, top:20),
height: 220,
width: MediaQuery.of(context).size.width-20,
margin: const EdgeInsets.only(right:10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30),
),
child:Column(
children: [
MyCard(),
],
))
);
},
));
}}
class MyCard extends StatefulWidget {
const MyCard( {Key key} ) : super(key: key);
#override
_MyCardState createState() => _MyCardState();
}
class _MyCardState extends State<MyCard> {
//String monText;
#override
Widget build(BuildContext context) {
return Container(
height: 230,
child: Stack(
children: [
Positioned(
top: 35,
left: 20,
child: Card(
elevation: 6.0,
shadowColor: Colors.grey,
child: Container(
height: 180,
width: 0.9,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(0.0),
boxShadow: [BoxShadow(
color: Colors.black.withOpacity(0.3),
offset: Offset(-10.0, 10.0),
blurRadius: 20.0,
spreadRadius: 4.0,
),
])
),
),
),
Positioned(
top: 0.0,
left: 30.0,
child:Card(
elevation: 10.0,
shadowColor: Colors.grey.withOpacity(0.5),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
child: Container(
height: 200,
width: 150,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
image: DecorationImage(
fit: BoxFit.fill,
image:AssetImage('assets/header.jpg'),
),
),
))),
Positioned(
top:40,
left:200,
child:
Container(
height: 150,
width: 170,
child:Column(
crossAxisAlignment: CrossAxisAlignment.start,
children:[
Text('Title: ', style: TextStyle(fontSize:16,
color:Colors.red),),
Divider(color:Colors.black),
Text('Info 1: ', style: TextStyle(fontSize:16,
color:Colors.red),),
Text('Info 2'),
])
))
],
),
);
}
}
Based on what you're trying to do it looks like what you need is something like this widget:
class InfoBlock {
final String title;
final String description;
InfoBlock({
required this.title,
required this.description,
});
}
class MyCard extends StatefulWidget {
String title;
List<InfoBlock> infoBlocks;
MyCard({
Key? key,
required this.title,
required this.infoBlocks,
}) : super(key: key);
#override
_MyCardState createState() => _MyCardState();
}
class _MyCardState extends State<MyCard> {
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 200,
width: 200,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
image: const DecorationImage(
fit: BoxFit.fill,
image: AssetImage('header.jpeg'),
))),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.title,
style: const TextStyle(fontSize: 30),
),
...widget.infoBlocks.map((block) {
return Text(
'${block.title}: ${block.description}',
style: const TextStyle(fontSize: 16),
);
}),
],
)
],
),
);
}
}
And then you can use it like-so:
Column(
children: [
MyCard(
title: 'Quantity',
infoBlocks: [
InfoBlock(title: 'Price', description: '100'),
],
),
MyCard(
title: 'Status',
infoBlocks: [
InfoBlock(title: 'Txt1', description: 'value1'),
InfoBlock(title: 'Txt2', description: 'value2'),
InfoBlock(title: 'Txt3', description: 'value3'),
],
),
],
));
And here's what the output would look like:
Here's a a link to Flutlab with the above code fully functional: https://flutlab.io/ide/6d8762de-50b1-4cfe-a509-a301edaacebf

How to expand list items without affecting other items. (flutter)

I want to create the Netflix home page in flutter, and I'm stuck while creating this hover state.
I have created two base widgets. One for the number plus the thumbnail and the other one for the expanded view when the widget is hovered. Then I put them in a stack with an Inkwell where the onHover changes the state to show the expanded widget.
When I hover on the widget, it does switch between the normal state an expanded state, the problem comes when I try to put a list of these widgets together.
When using row (or ListView) to put them together, after hovering, the expanded widget makes the other widgets move. (which is not the wanted behaviour, I want them to overlap)
When I use it with stack, the widgets do overlap but now it isn't scrollable anymore.
I have added the link to the repo for anyone that wants to clone it and try running it themselves, I'm running it on flutter web.
https://github.com/Advait1306/netflix-flutter
Widget with thumbnail and number:
class TopListItem extends StatelessWidget {
final int index;
const TopListItem({Key? key, required this.index}) : super(key: key);
#override
Widget build(BuildContext context) {
const double height = 250;
return SizedBox(
height: height,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
SvgPicture.asset("assets/numbers/$index.svg",
fit: BoxFit.fitHeight, height: height),
Transform.translate(
offset: const Offset(-30, 0),
child: Image.asset("assets/thumbnails/thumb1.jpg"))
],
),
);
}
}
Expanded view widget:
import 'package:flutter/material.dart';
class HoverMovieTrailer extends StatelessWidget {
const HoverMovieTrailer({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
const textTheme = TextStyle(color: Colors.white);
return SizedBox(
width: 400,
height: 400,
child: Container(
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: const Color(0xFF242424)),
child: Column(
children: [
Image.asset("assets/backgrounds/background1.jpg"),
const SizedBox(
height: 20,
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 18),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: const [
RoundIconButton(icon: Icons.play_arrow_outlined),
SizedBox(width: 5),
RoundIconButton(icon: Icons.add_outlined),
SizedBox(width: 5),
RoundIconButton(icon: Icons.thumb_up_alt_outlined),
SizedBox(width: 5),
],
),
Row(
children: const [
RoundIconButton(icon: Icons.keyboard_arrow_down_outlined),
],
),
],
),
),
const SizedBox(
height: 20,
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 18),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
const Text(
"98% Match",
style: TextStyle(
color: Colors.green,
fontWeight: FontWeight.bold
),
),
const SizedBox(width: 5),
Container(
padding: const EdgeInsets.all(1),
decoration: BoxDecoration(
border: Border.all(color: Colors.white, width: 1)
),
child: const Text(
"18+",
style: textTheme,
),
),
const SizedBox(width: 5),
const Text(
"4 Seasons",
style: textTheme,
),
const SizedBox(width: 5),
Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.white, width: 1)
),
child: const Text(
"HD",
style: textTheme,
),
)
],
),
),
const SizedBox(
height: 5,
),
Padding(
padding: const EdgeInsets.all(18.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
const Text(
"Captivating",
style: textTheme,
),
const SizedBox(width: 5),
Container(
width: 5,
height: 5,
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: Colors.white54
),
),
const SizedBox(width: 5),
const Text(
"Exciting",
style: textTheme,
),
const SizedBox(width: 5),
Container(
width: 5,
height: 5,
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: Colors.white54
),
),
const SizedBox(width: 5),
const Text(
"Docuseries",
style: textTheme,
),
],
),
),
],
),
),
);
}
}
class RoundIconButton extends StatelessWidget {
final IconData icon;
const RoundIconButton({Key? key, required this.icon}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.transparent,
border: Border.all(width: 2, color: Colors.white)),
margin: const EdgeInsets.all(1),
child: IconButton(
onPressed: () {},
icon: Icon(icon),
color: Colors.white,
),
);
}
}
Combining the widgets in the single widget:
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:netflix_flutter/widgets/hover_movie_trailer.dart';
import 'package:netflix_flutter/widgets/top_list_item.dart';
class TopListItemWithHover extends StatefulWidget {
const TopListItemWithHover({Key? key}) : super(key: key);
#override
State<TopListItemWithHover> createState() => _TopListItemWithHoverState();
}
class _TopListItemWithHoverState extends State<TopListItemWithHover> {
bool hover = false;
#override
Widget build(BuildContext context) {
return InkWell(
onTap: (){},
onHover: (value){
log("Hover value: $value");
setState(() {
hover = value;
});
},
child: Stack(
clipBehavior: Clip.none,
children: [
TopListItem(index: 1),
if(hover) HoverMovieTrailer(),
],
),
);
}
}
Lists:
import 'package:flutter/material.dart';
import 'package:netflix_flutter/widgets/hover_movie_trailer.dart';
import 'package:netflix_flutter/widgets/top_list_item.dart';
import 'package:netflix_flutter/widgets/top_list_item_with_hover.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: SizedBox(
height: 400,
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
clipBehavior: Clip.none,
itemCount: 8,
itemBuilder: (context, index) {
return TopListItemWithHover();
},
),
),
),
const SizedBox(height: 50),
SingleChildScrollView(
child: SizedBox(
height: 400,
child: Stack(
fit: StackFit.passthrough,
children: [
for (var i = 10; i >= 0; i--)
Positioned(
left: (i) * 300,
child: TopListItemWithHover(),
)
],
),
),
)
],
),
);
}
}
So finally found the solution to this problem, the way to move forward is to use a stack in SingleChildScrollView.
A mistake that I made is, I did not set the SingleChildScrollView's direction to horizontal. So I added that.
And then one more addition that's needed is -- A empty sized box which has the width of sum of all the items in the stack.
Stack(
clipBehavior: Clip.none,
children: [
const SizedBox(
width: 300*10,
),
for (var i = 10; i >= 0; i--)
Positioned(
left: (i) * 300,
child: TopListItemWithHover(),
)
],
)
This finally expanded the stack to the required width and then made is scrollable also.

Change Notifier Provider to add widget to Favourite Screen

I've made screen with details of movies and with favourite movies. Also I've got a list of movies. In Detail Screen, there is favourite icon. I want to make that when you tap on this Icon, I want to add this movie to Favourite Screen.
There is a list of movies.
class Movie {
String imgUrl;
String title;
String categories;
int year;
String country;
int length;
String description;
List<String> screenshots;
Movie({
required this.imgUrl,
required this.title,
required this.categories,
required this.year,
required this.country,
required this.length,
required this.description,
required this.screenshots,
});
}
final List<Movie> movies = [
Movie(
imgUrl:
'https://static.posters.cz/image/1300/plakaty/james-bond-no-time-to-die-profile-i114389.jpg',
title: 'No time to die',
categories: 'Adventure',
year: 2021,
country: 'USA/England',
length: 183,
description:
'James Bond has left active service. His peace is short-lived when Felix Leiter, an old friend from the CIA, turns up asking for help, leading Bond onto the trail of a mysterious villain armed with dangerous new technology.',
screenshots: [
'https://i.pinimg.com/originals/fd/5e/1d/fd5e1d8878c402aaba2fb6373e880b1f.webp',
'https://cdn.mos.cms.futurecdn.net/dNmCDjJT5G76aDKiYphTkF.jpg',
'https://i.imgur.com/Zm9X4lT.jpg',
'https://images.complex.com/complex/images/c_fill,f_auto,g_center,w_1200/fl_lossy,pg_1/knie3z7uwe3inyua5kft/no-time-to-die-04'
]),
]
There I've got Detail Screen.
class MovieScreen extends StatefulWidget {
final String photo, title, categories, country, description;
final int year, length;
final List<String> screenshots;
const MovieScreen(
{Key? key,
required this.photo,
required this.title,
required this.categories,
required this.year,
required this.country,
required this.description,
required this.length,
required this.screenshots})
: super(key: key);
#override
_MovieScreenState createState() => _MovieScreenState();
}
class _MovieScreenState extends State<MovieScreen> {
#override
Widget build(BuildContext context) {
final filmData = Provider.of<MovieProvider>(context);
final films = filmData.items;
return Scaffold(
backgroundColor: Colors.white,
body: ListView(
children: [
Stack(
children: [
Container(
transform: Matrix4.translationValues(0, -50, 0),
width: double.infinity,
child: Hero(
tag: widget.photo,
child: ClipShadowPath(
clipper: CircularClipper(),
shadow: Shadow(blurRadius: 20),
child: Image(
height: 400,
image: NetworkImage(widget.photo),
fit: BoxFit.cover,
),
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
IconButton(
padding: EdgeInsets.only(left: 20),
onPressed: () => Navigator.pop(context),
icon: Icon(Icons.arrow_back),
iconSize: 40,
),
IconButton(
padding: EdgeInsets.only(right: 20),
onPressed: () {},
icon: Icon(Icons.favorite_outline),
iconSize: 30,
color: Colors.red,
),
],
),
],
),
],
),
);
}
}
There is Favourite Screen.
class MyList extends StatefulWidget {
#override
_MyListState createState() => _MyListState();
}
class _MyListState extends State<MyList> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Navbar1(),
Container(
width: MediaQuery.of(context).size.width - 60,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: ListView(
children: <Widget>[
SizedBox(
height: 50,
),
HeadMenuMylist(),
SizedBox(
height: 20,
),
GridView.count(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
mainAxisSpacing: 10,
crossAxisSpacing: 10,
crossAxisCount: 2,
childAspectRatio: 1 / 2,
children: [
Stack(
children: [
Positioned.fill(
child: Container(
height: 200,
foregroundDecoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [Colors.transparent, Colors.black],
),
),
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Image.network(imgUrl
,
loadingBuilder: (BuildContext context,
Widget child,
ImageChunkEvent? loadingProgress) {
if (loadingProgress == null) return child;
return Center(
child: SizedBox(
height: 50,
width: 50,
child: CircularProgressIndicator(
strokeWidth: 4,
color: Colors.red,
),
),
);
},
fit: BoxFit.cover,
),
),
),
),
Padding(
padding: const EdgeInsets.only(bottom: 15),
child: Align(
alignment: Alignment.bottomCenter,
child: Text(
'Peaky Blinders',
style: GoogleFonts.openSans(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.w700),
),
),
),
Padding(
padding: const EdgeInsets.only(top: 10, right: 10),
child: Align(
alignment: Alignment.topRight,
child: GestureDetector(
onTap: () {},
child: Icon(
Icons.delete,
color: Colors.white,
),
)),
),
],
),
],
),
],
),
),
),
],
),
);
}
}
I tried with Change Notifier Provider but it doesn't work and I don't have clue why it didn't work. Is there something else I can use instead Change Notifier Provider?
Thanks for help.
if you want to save the favorite movie of a user permanently, then you have to save the JSON data in firestore database.
Create a function to store the favorite movie json data to firestore, i,e , store the json data to collection like;
saveFavrotiesMovies() async {
final User user = auth.currentUser;
final uid = user.uid;
try {
await FirebaseFirestore.instance
.collection('Favorite Movies')
.doc()
.collection(uid.toString())
.doc()
.set(
movies.toJson());
print('data adedd succesfullyyyyyy');
} catch (e, s) {
print("#DatabaseService Exception IN ADDNG FAVOTRITE DATA $e");
print(s);
}
}
This function store the favorite movie of a specific user in his/her collection
Retrive and the Favorite movie json data of a user from the Firestore database using a function in same manner as will do in storing the favorite data, and display the data in the Favorite Screen

Design this animation using SliverAppBar flutter

Here's what I want to build but I am able to achieve this
by the following code,
#override
Widget build(BuildContext context) {
return Scaffold(
body: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled){
return [
SliverAppBar(
expandedHeight: 120,
floating: false,
pinned: false,
flexibleSpace: Container(
padding: EdgeInsets.all(10),
height: 160,
width: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Align(
alignment: Alignment.topCenter,
child: Text(
'Hello World',
)),
Padding(
padding: EdgeInsets.only(top: 16),
child: Image.asset(
'assets/images/banner.png',
),
),
],
),
),
),
];
},
body: ListView.builder(),
),
);
}
I have tried SliverAppBar using flexible and expanded, but was not able to achieve.
Update -
First element of list is going behind text field. I want to scroll only when the animation is completed
updated answer,
#override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: <Widget>[
TransitionAppBar(
extent: 250,
avatar: Text("Rancho"),
title: Container(
margin: EdgeInsets.symmetric(horizontal: 20.0, vertical: 0),
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.all(Radius.circular(5.0))),
child: Row(children: <Widget>[
Padding(
padding: EdgeInsets.only(left: 20.0, right: 10.0),
child: Icon(Icons.search),
),
Expanded(
child: TextFormField(
keyboardType: TextInputType.text,
textInputAction: TextInputAction.done,
cursorColor: Colors.black,
autofocus: false,
style: TextField_Style,
decoration: InputDecoration(
filled: true,
fillColor: Colors.transparent,
contentPadding:
EdgeInsets.symmetric(vertical: 10, horizontal: 15),
hintText: "Search",
border: InputBorder.none,
disabledBorder: OutlineInputBorder(
borderSide: new BorderSide(color: Colors.transparent),
borderRadius: new BorderRadius.circular(2),
),
focusedBorder: OutlineInputBorder(
borderSide: new BorderSide(color: Colors.transparent),
borderRadius: new BorderRadius.circular(2),
)),
),
)
]),
),
),
SliverList(
delegate: SliverChildBuilderDelegate((context, index) {
return Container(
color: Colors.blue,
child: ListTile(
title: Text("${index}a"),
));
}, childCount: 25))
],
),
);
}
.
class TransitionAppBar extends StatelessWidget {
final Widget avatar;
final Widget title;
final double extent;
TransitionAppBar({this.avatar, this.title, this.extent = 250, Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return SliverPersistentHeader(
pinned: true,
delegate: _TransitionAppBarDelegate(
avatar: avatar,
title: title,
extent: extent > 200 ? extent : 200
),
);
}
}
class _TransitionAppBarDelegate extends SliverPersistentHeaderDelegate {
final _avatarMarginTween = EdgeInsetsTween(
begin: EdgeInsets.only(bottom: 70, left: 30),
end: EdgeInsets.only(left: 0.0, top: 30.0));
final _avatarAlignTween =
AlignmentTween(begin: Alignment.bottomLeft, end: Alignment.topCenter);
final Widget avatar;
final Widget title;
final double extent;
_TransitionAppBarDelegate({this.avatar, this.title, this.extent = 250})
: assert(avatar != null),
assert(extent == null || extent >= 200),
assert(title != null);
#override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
double tempVal = 34 * maxExtent / 100;
final progress = shrinkOffset > tempVal ? 1.0 : shrinkOffset / tempVal;
print("Objechjkf === ${progress} ${shrinkOffset}");
final avatarMargin = _avatarMarginTween.lerp(progress);
final avatarAlign = _avatarAlignTween.lerp(progress);
return Stack(
children: <Widget>[
AnimatedContainer(
duration: Duration(milliseconds: 100),
height: shrinkOffset * 2,
constraints: BoxConstraints(maxHeight: minExtent),
color: Colors.redAccent,
),
Padding(
padding: avatarMargin,
child: Align(
alignment: avatarAlign,
child: avatar
),
),
Padding(
padding: EdgeInsets.only(bottom: 10),
child: Align(
alignment: Alignment.bottomCenter,
child: title,
),
)
],
);
}
#override
double get maxExtent => extent;
#override
double get minExtent => (maxExtent * 68) / 100;
#override
bool shouldRebuild(_TransitionAppBarDelegate oldDelegate) {
return avatar != oldDelegate.avatar || title != oldDelegate.title;
}
}