Related
I am trying to achieve the following result in one of my app in flutter.
But I cannot figure out how to animate the "SKYGOAL" text that comes fading and sliding.
I've animated the rest of the components using AnimatedContainer or AnimatedOpacity, but I've been stuck on this one. I am new to animations so I don't know much.
Any help would be useful.
Thank you!
My current related snippet is :
class SplashScreen1 extends StatefulWidget {
const SplashScreen1({Key? key}) : super(key: key);
#override
State<SplashScreen1> createState() => _SplashScreen1State();
}
class _SplashScreen1State extends State<SplashScreen1> with SingleTickerProviderStateMixin {
double _skygoalLogoOpacity = 0;
double _syjOpacity = 0;
double _skygoalTextWidth = 0;
#override
void initState() {
// TODO: implement initState
super.initState();
Future.delayed(const Duration(seconds: 0)).then((value) => setState(() {
_skygoalLogoOpacity = 1;
_syjOpacity = 1;
_skygoalTextWidth = 2000;
}));
Future.delayed(const Duration(milliseconds: 4800)).then((value) => Navigator.pushReplacement(context, AnimatedPageRoute(SplashScreen2())));
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
color: Color(0xFF0E3C6E),
width: MediaQuery.of(context).size.width,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
SizedBox(height: 250,),
Stack(
children: [
Container(
decoration: BoxDecoration(
shape: BoxShape.circle, color: Colors.white
),
height: 185,
width: 185,
),
AnimatedOpacity(
duration: const Duration(milliseconds: 1000),
opacity: _skygoalLogoOpacity,
child: Container(
padding: EdgeInsets.only(top: 20),
child: Image.asset("assets/images/skygoal-logo.png"),
// height: 135,
width: 164,
),
),
],
),
Stack(
children: [
AnimatedOpacity(
duration: const Duration(milliseconds: 2000),
opacity: _syjOpacity,
child: Container(
margin: EdgeInsets.only(left: 40, top: 37),
height: 29,
width: 153,
child: Image.asset("assets/images/start-your-journey.png"),
),
),
Container(
margin: EdgeInsets.only(top: 5,left: 20),
child: Text(
"SKYGOAL",
style: GoogleFonts.poppins(
fontSize: 30,
fontWeight: FontWeight.w800,
color: Colors.white
),
textAlign: TextAlign.center,
),
),
],
),
Spacer(),
Text(
"By Skygoal",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 13
),
),
Container(
margin: EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10)
),
height: 5,
width: 134,
)
],
),
),
);
}
}
You can try animated_text_kit fade transition.
Example from doc
return SizedBox(
width: 250.0,
child: DefaultTextStyle(
style: const TextStyle(
fontSize: 32.0,
fontWeight: FontWeight.bold,
),
child: AnimatedTextKit(
animatedTexts: [
FadeAnimatedText( "SKYGOAL"),
],
onTap: () {
print("Tap Event");
},
),
),
);
I dont know whether it is the correct solution or not, But you can try something like this . I created a stack and its first child is the text and the other child is a container with boxShadow . Have a look at this.
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key,}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
MediaQueryData mediaQueryData = MediaQuery.of(context);
return Scaffold(
appBar: AppBar(),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SizedBox(
height: mediaQueryData.size.width,
width: mediaQueryData.size.width,
child: ColoredBox(
color: Colors.yellowAccent,
child: Stack(
alignment: Alignment.centerRight,
children: [
Container(
width: mediaQueryData.size.width,
height: 80,
alignment: Alignment.center,
child: Text(
'Hello World',
style: TextStyle(
fontSize: mediaQueryData.textScaleFactor * 50,
),
),
),
TweenAnimationBuilder(
tween: Tween<double>(
end: 0,
begin: 1,
),
duration: const Duration(
seconds: 5,
),
builder: (context, double tween, _ ){
return Container(
//alignment: Alignment.centerRight,
height: 50, //mediaQueryData.size.width,
width: mediaQueryData.size.width * tween,
decoration: const BoxDecoration(
color: Colors.yellowAccent,
boxShadow: [
BoxShadow(
blurRadius: 80,
spreadRadius: 30,
color: Colors.yellowAccent,
),
]
),
);
},
)
],
),
),
)
],
),
),
);
}
}
I am trying to put some widgets in a row where the first widget should be square shaped and use the intrinsic width and height to modify the smaller one of these values so it results in a square shape. The side length should depend on the child widget, which is in my case a Text. Padding the text equally from all sides does not look right. I already tried achieving this with the AspectRatio widget and its working as far as it results in the expected square shape, but it does not use the minimal space but rather scales up as much as possible.
Any idea how to get this result without hardcoding the width and height?
example code
import 'package:flutter/material.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',
home: Scaffold(
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 100),
Text(' current status:'),
SizedBox(height: 5),
Row(
children: [
Container(
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.red.shade300,
borderRadius: BorderRadius.circular(10),
border: Border.all(color: Colors.blue),
),
child: const Center(
child: Text(
'square',
textAlign: TextAlign.center,
),
),
),
SizedBox(width: 10),
Flexible(
child: Container(
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.blue.shade200,
borderRadius: BorderRadius.circular(10),
border: Border.all(color: Colors.red),
),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'placeholder for other widgets',
style: Theme.of(context).textTheme.bodySmall,
),
],
),
),
),
],
),
SizedBox(height: 50),
Text(' I want this:'),
SizedBox(height: 5),
Row(
children: [
SizedBox(
height: 50,
child: AspectRatio(
aspectRatio: 1,
child: Container(
decoration: BoxDecoration(
color: Colors.red.shade300,
borderRadius: BorderRadius.circular(10),
border: Border.all(color: Colors.blue),
),
child: Center(
child: Text(
'square',
textAlign: TextAlign.center,
),
),
),
),
),
SizedBox(width: 10),
Flexible(
child: Container(
height: 50,
decoration: BoxDecoration(
color: Colors.blue.shade200,
borderRadius: BorderRadius.circular(10),
border: Border.all(color: Colors.red),
),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'placeholder for other widgets',
style: Theme.of(context).textTheme.bodySmall,
),
],
),
),
),
],
),
],
),
),
);
}
}
EDIT:
my code looks like this now
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final GlobalKey _key = GlobalKey();
double boxWidth = 0.0;
final String inputText = 'square';
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
setState(() {
BuildContext? keyContext = _key.currentContext;
if (keyContext != null) {
RenderBox renderBox = keyContext.findRenderObject() as RenderBox;
boxWidth = renderBox.size.width;
}
});
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 100),
Text(' input: $inputText'),
const SizedBox(height: 50),
const Text(' with StatefulWidget'),
const SizedBox(height: 10),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: const EdgeInsets.all(10),
key: _key,
height: boxWidth,
decoration: BoxDecoration(
color: Colors.red.shade300,
borderRadius: BorderRadius.circular(10),
border: Border.all(color: Colors.blue),
),
child: Center(
child: Text(
inputText,
textAlign: TextAlign.center,
),
),
),
const SizedBox(width: 10),
Flexible(
child: Container(
padding: const EdgeInsets.all(10),
height: boxWidth,
decoration: BoxDecoration(
color: Colors.blue.shade200,
borderRadius: BorderRadius.circular(10),
border: Border.all(color: Colors.red),
),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'placeholder for other widgets',
style: Theme.of(context).textTheme.bodySmall,
),
],
),
),
),
],
),
const SizedBox(height: 50),
const Text(' with AspectRatio'),
const SizedBox(height: 10),
Row(
children: [
Flexible(
flex: 2,
child: AspectRatio(
aspectRatio: 1,
child: Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.red.shade300,
borderRadius: BorderRadius.circular(10),
border: Border.all(color: Colors.blue),
),
child: Center(
child: Text(
inputText,
textAlign: TextAlign.center,
),
),
),
),
),
const SizedBox(width: 10),
Flexible(
flex: 8,
child: Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.blue.shade200,
borderRadius: BorderRadius.circular(10),
border: Border.all(color: Colors.red),
),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'placeholder for other widgets',
style: Theme.of(context).textTheme.bodySmall,
),
],
),
),
),
],
),
],
),
),
);
}
}
This is how the different solution approaches behave:
You can achieve this using flexible and aspect ratio
Row(
children : [
Flexible(
flex: 2,
child: AspectRatio(
aspectRatio: 1,
Container(
color: Colors.red,
)
)
),
Flexible(
flex: 8,
child: Text(),
)
]
)
You can change the flex value as per your requirement
Edit
You can use intrinsic height in a row to set the child to the tallest child
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyWidget(),
),
),
);
}
}
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return SizedBox(
width: MediaQuery.of(context).size.width,
child: IntrinsicHeight(
child: Row(children: [
AspectRatio(aspectRatio: 1, child: Container(color: Colors.red)),
Flexible(
child: Text(
"djdjdjdhjvc gf\nf bg \nhg hshs\nfjgdhjfhj \n hxhkj \n fjdjd d \n ejejdj "))
])));
}
}
you can do this:
GlobalKey _key = GlobalKey();
double boxWidth = 0.0;
#override
void initState() {
// TODO: implement initState
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
setState(() {
final _keyContext = _key.currentContext;
if (_keyContext != null) {
final box = _keyContext.findRenderObject() as RenderBox;
boxWidth = box.size.width;
}
});
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: EdgeInsets.all(10),
key: _key,
height: boxWidth,
decoration: BoxDecoration(
color: Colors.red.shade300,
borderRadius: BorderRadius.circular(10),
border: Border.all(color: Colors.blue),
),
child: const Center(
child: Text(
'square',
textAlign: TextAlign.center,
),
),
),
SizedBox(width: 10),
Flexible(
child: Container(
padding: EdgeInsets.all(10),
height: boxWidth,
decoration: BoxDecoration(
color: Colors.blue.shade200,
borderRadius: BorderRadius.circular(10),
border: Border.all(color: Colors.red),
),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'placeholder for other widgets',
style: Theme.of(context).textTheme.bodySmall,
),
],
),
),
),
],
),
],
),
),
);
}
I have seen many questions about Navigator.pop(context) but I didn't find my answer.
As you can see there are three screens so far. The Navigator.pop(context) works fine in the StoryDetailScreen and turns me back to the MainPage. The problem here with EditStoryScreen page, when I get into it I cant go back to the MainPage, when I click on the IconButton I see a black screen.
main.dart
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return
MultiProvider(
providers: [
ChangeNotifierProvider<Stories>(
create: (_) =>
Stories(),
),
ChangeNotifierProvider<Story>(
create:(ctx) => Story(),
),
],
child: MaterialApp(
title: 'MyShop',
theme: ThemeData(
primarySwatch: Colors.purple,
accentColor: Colors.deepOrange,
fontFamily: 'Lato',
),
home: Mainpage(),
routes: {
StoryDetailScreen.routeName: (ctx) => StoryDetailScreen(),
UserStory.routeName: (ctx) => UserStory(),
EditStoryScreen.routeName: (ctx) => EditStoryScreen(),
}),
);
}
}
Mainpage.dart
class Mainpage extends StatefulWidget {
static const routeName = 'main';
#override
_MainpageState createState() => _MainpageState();
}
class _MainpageState extends State<Mainpage> {
var _showOnlyFav = false;
#override
Widget build(BuildContext context) {
final storyCon = Provider.of<Stories>(context);
return Scaffold(
body: SingleChildScrollView(
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("images/back.jpg"), fit: BoxFit.fill)),
child: Column(children: <Widget>[
SizedBox(
height: 50,
),
Container(
child: Text("Short Stories",
style: TextStyle(
fontSize: 40, backgroundColor: Colors.grey[300])),
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
child: Row(
children: [
Container(
height: 40,
width: 290,
decoration: BoxDecoration(
color: Colors.grey[300],
border: Border.all(width: 1, color: Colors.black),
borderRadius: BorderRadius.circular(7)
// image: DecorationImage(
// image: AssetImage("images/text.png"))
),
child: Center(
child: Row(
children: [
InkWell(
onTap: () {
Navigator.of(context).pushReplacementNamed(UserStory.routeName);
},
child: Text(
"Edit Stroy",
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black,
fontSize: 30,
// backgroundColor: Colors.grey[300]),
),
),
),
InkWell(
onTap: () {
Navigator.of(context).pushReplacementNamed(EditStoryScreen.routeName);
},
child:Text(
"Add Stroy",
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black,
fontSize: 30,
// backgroundColor: Colors.grey[300]),
),
),)
],
),
),
),
],
))),
StorysGrid(_showOnlyFav),
]),
),
),
);
}
}
EditStoryScreen.dart
class EditStoryScreen extends StatefulWidget {
static const routeName = 'edit';
#override
_EditStoryScreenState createState() => _EditStoryScreenState();
}
class _EditStoryScreenState extends State<EditStoryScreen> {
final _storyFocusNode = FocusNode();
final _imgController = TextEditingController();
final _imgFocusNode = FocusNode();
#override
void initState() {
_imgFocusNode.addListener(updateImg);
super.initState();
}
#override
void dispose() {
_imgFocusNode.removeListener(updateImg);
_storyFocusNode.dispose();
_imgController.dispose();
_imgFocusNode.dispose();
super.dispose();
}
void updateImg() {
if (!_imgFocusNode.hasFocus) {
setState(() {});
}
}
// void backToHome(context) {
// Navigator.pushReplacementNamed(BuildContext(), context);
// }
#override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: Container(
height: 650,
color: Colors.white,
child: Column(
children: [
SizedBox(
height: 30,
),
Align(
alignment: Alignment.topLeft,
child: RaisedButton(
child: Icon(Icons.arrow_back_ios),
onPressed: () => Navigator.pop(context)
)),
Padding(
padding: const EdgeInsets.fromLTRB(15, 10, 15, 15),
child: Form(
child: ListView(
shrinkWrap: true,
children: <Widget>[
TextFormField(
decoration: InputDecoration(labelText: "Title"),
textInputAction: TextInputAction.next,
onFieldSubmitted: (_) {
FocusScope.of(context).requestFocus(_storyFocusNode);
},
),
TextFormField(
decoration: InputDecoration(labelText: "Story's text"),
maxLines: 14,
keyboardType: TextInputType.multiline,
focusNode: _storyFocusNode,
),
Row(
children: [
Container(
width: 100,
height: 100,
margin: EdgeInsets.only(top: 8, right: 10),
decoration: BoxDecoration(
border: Border.all(width: 1, color: Colors.grey),
),
child: _imgController.text.isEmpty
? Text("Enter a Url")
: Center(
child: FittedBox(
child: Image.network(
_imgController.text,
),
),
),
),
Container(
width: 200,
child: TextFormField(
decoration: InputDecoration(
labelText: "Image URL",
),
keyboardType: TextInputType.url,
textInputAction: TextInputAction.done,
controller: _imgController,
focusNode: _imgFocusNode,
),
)
],
),
],
),
),
),
],
),
),
),
);
}
}
StoryDetailScreen.dart
class StoryDetailScreen extends StatelessWidget {
// final String title;
// final double price;
// ProductDetailScreen(this.title, this.price);
static const routeName = '/story-detail';
#override
Widget build(BuildContext context) {
final storyId =
ModalRoute.of(context).settings.arguments as String; // is the id!
final loadedStory = Provider.of<Stories>(
context,
listen: false,
).findById(storyId);
return Scaffold(
body: SingleChildScrollView(
child: Container(
width: double.infinity,
// height: 700,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("images/back1.jpg"), fit: BoxFit.fill)),
// color: Color(0xfffae3d9),
// child: Column(children: <Widget>[
// SizedBox(
// height: 10,
// ),
// Container(
// width: 340,
child:
Column(crossAxisAlignment: CrossAxisAlignment.center, children: [
SizedBox(
height: 50,
),
Align(
alignment: Alignment.topLeft,
child: RaisedButton(
child: Icon(Icons.arrow_back_ios),
onPressed: (){
Navigator.pop(context);
})
),
Card(
elevation: 10,
margin: EdgeInsets.all(10),
child: Text("${loadedStory.title}",
softWrap: false,
textDirection: TextDirection.ltr,
style: TextStyle(
color: Color(0xFF6a2c70),
decorationColor: Colors.black,
fontSize: 25,
fontWeight: FontWeight.bold,
)),
),
SizedBox(height: 30),
Container(
width: double.infinity,
color: Colors.white70,
child: Padding(
padding:
const EdgeInsets.symmetric(vertical: 10, horizontal: 5),
child: Text(
loadedStory.story,
textDirection: TextDirection.rtl,
style: TextStyle(
color: Color(0xFF6a2c70),
decorationColor: Colors.black,
fontSize: 25,
fontWeight: FontWeight.bold,
// fontFamily: "Kufam"),
),
),
),
),
SizedBox(
height: 20,
),
Card(
child: Container(
height: 60,
width: 210,
decoration: BoxDecoration(color: Colors.white60),
child: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Like(),
]),
),
),
),
// ],
// )
SizedBox(
height: 30,
)
]),
)
// ]
,
),
// ),
// ),
);
}
}
You're invoking
Navigator.of(context).pushReplacementNamed(UserStory.routeName)
so this is removing your Mainpage from the navigation stack and replacing it with UserStory, which is why when you call Navigator.pop(context), there's nothing to go back to and all you get is a black screen.
Change it to Navigator.of(context).pushNamed(UserStory.routeName).
You have to define the Mainpage route as well in the routes.
Currently this code works to resize a container to toggle between different content, but it's not animating. I think that I need to provide a height property to make the animation work, and when I do provide a height to toggle between it does match, like this:
height: selected ? 400 : 100,
The container animates smoothly between the two states. However the height is no longer adaptive. So I try to supply a height using:
GlobalKey _key = GlobalKey();
_size = _key.currentContext.size;
height: _size.height,
But it gives me errors and I'm not sure how to fix it.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool selected = false;
// GlobalKey _key = GlobalKey();
// Size _size = _key.currentContext.size;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Expanded(
child: ListView(
children: [
GestureDetector(
onTap: () {
setState(() {
selected = !selected;
// _size = _key.currentContext.size;
});
},
child: Padding(
padding: EdgeInsets.all(5),
child: AnimatedContainer(
// height: _size.height,
// key: _key,
duration: Duration(seconds: 1),
curve: Curves.fastOutSlowIn,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: Colors.white,
boxShadow: [
BoxShadow(
blurRadius: 2.5,
spreadRadius: 0.4,
color: Colors.grey,
offset: Offset(0, 0.5),
),
],
),
child: Padding(
padding: EdgeInsets.all(17),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Move fridge up stairs',
style: TextStyle(fontSize: 16),
),
SizedBox(height: 5),
Text(
'Sarah - 2 days ago - 2.3km',
style: TextStyle(color: Colors.black54),
),
if (selected)
Container(
child: Column(
children: [
Padding(
padding: EdgeInsets.fromLTRB(0, 20, 0, 20),
child: Text(
'Fridge is a single door. Sitting in kitchen. Need one strong person as I will help move it.',
style: TextStyle(
color: Colors.black54,
),
),
),
Padding(
padding: EdgeInsets.fromLTRB(0, 0, 0, 10),
child: Row(
children: [
Icon(
Icons.calendar_today,
color: Colors.black54,
size: 20,
),
Text(
' In three days',
style: TextStyle(
color: Colors.black54,
),
),
],
),
),
Padding(
padding: EdgeInsets.fromLTRB(0, 0, 0, 10),
child: Row(
children: [
Icon(
Icons.attach_money,
color: Colors.black54,
),
Text(
' 30',
style: TextStyle(
color: Colors.black54,
),
),
],
),
),
Row(
children: [
Text('Price : '),
Container(
width: 140,
margin: EdgeInsets.fromLTRB(0, 0, 0, 0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20.0),
color: Colors.white,
border: Border.all(color: Colors.white),
),
child: Container(
child: TextField(
decoration: new InputDecoration(
hintText: "Your price",
contentPadding: const EdgeInsets.all(10.0)),
keyboardType: TextInputType.number,
maxLines: null,
),
),
),
],
),
Row(
children: [
Text('Reply : '),
Expanded(
child: TextField(
decoration: new InputDecoration(
hintText: "Enter your reply",
contentPadding: const EdgeInsets.all(10.0)),
keyboardType: TextInputType.multiline,
maxLines: null,
),
),
],
),
SizedBox(height:20),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
width: 10,
),
FlatButton(
shape: RoundedRectangleBorder(
side: BorderSide(
color: Colors.blue, width: 1, style: BorderStyle.solid),
borderRadius: BorderRadius.circular(50),
),
color: Colors.white,
textColor: Colors.black,
onPressed: () {
/*...*/
},
child: Padding(
padding: EdgeInsets.fromLTRB(0, 10, 0, 10),
child: Text(
"Reply",
),
),
),
],
)
],
),
),
],
),
),
),
),
),
],
),
),
],
)
);
}
}
I thing AnimatedContainer is not Appropriate for this situation. I think its better to use AnimatedCrossFade. The AnimatedContainer will automatically animate between the old and new values of properties when they change using the provided curve and duration.
following code is refactored for using AnimatedCrossFade:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool selected = false;
// GlobalKey _key = GlobalKey();
// Size _size = _key.currentContext.size;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Expanded(
child: ListView(
children: [
GestureDetector(
onTap: () {
setState(() {
selected = !selected;
// _size = _key.currentContext.size;
});
},
child: Padding(
padding: EdgeInsets.all(5),
child: AnimatedCrossFade(
duration: Duration(seconds: 1),
crossFadeState: selected
? CrossFadeState.showFirst
: CrossFadeState.showSecond,
firstChild: Container(
// height: !selected ? 100 : 400,
// key: _key,
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: Colors.white,
boxShadow: [
BoxShadow(
blurRadius: 2.5,
spreadRadius: 0.4,
color: Colors.grey,
offset: Offset(0, 0.5),
),
],
),
child: Padding(
padding: EdgeInsets.all(17),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Move fridge up stairs',
style: TextStyle(fontSize: 16),
),
SizedBox(height: 5),
Text(
'Sarah - 2 days ago - 2.3km',
style: TextStyle(color: Colors.black54),
),
if (selected)
Container(
child: Column(
children: [
Padding(
padding:
EdgeInsets.fromLTRB(0, 20, 0, 20),
child: Text(
'Fridge is a single door. Sitting in kitchen. Need one strong person as I will help move it.',
style: TextStyle(
color: Colors.black54,
),
),
),
Padding(
padding: EdgeInsets.fromLTRB(0, 0, 0, 10),
child: Row(
children: [
Icon(
Icons.calendar_today,
color: Colors.black54,
size: 20,
),
Text(
' In three days',
style: TextStyle(
color: Colors.black54,
),
),
],
),
),
Padding(
padding: EdgeInsets.fromLTRB(0, 0, 0, 10),
child: Row(
children: [
Icon(
Icons.attach_money,
color: Colors.black54,
),
Text(
' 30',
style: TextStyle(
color: Colors.black54,
),
),
],
),
),
Row(
children: [
Text('Price : '),
Container(
width: 140,
margin:
EdgeInsets.fromLTRB(0, 0, 0, 0),
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(20.0),
color: Colors.white,
border:
Border.all(color: Colors.white),
),
child: Container(
child: TextField(
decoration: new InputDecoration(
hintText: "Your price",
contentPadding:
const EdgeInsets.all(
10.0)),
keyboardType:
TextInputType.number,
maxLines: null,
),
),
),
],
),
Row(
children: [
Text('Reply : '),
Expanded(
child: TextField(
decoration: new InputDecoration(
hintText: "Enter your reply",
contentPadding:
const EdgeInsets.all(10.0)),
keyboardType:
TextInputType.multiline,
maxLines: null,
),
),
],
),
SizedBox(height: 20),
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
SizedBox(
width: 10,
),
FlatButton(
shape: RoundedRectangleBorder(
side: BorderSide(
color: Colors.blue,
width: 1,
style: BorderStyle.solid),
borderRadius:
BorderRadius.circular(50),
),
color: Colors.white,
textColor: Colors.black,
onPressed: () {
/*...*/
},
child: Padding(
padding: EdgeInsets.fromLTRB(
0, 10, 0, 10),
child: Text(
"Reply",
),
),
),
],
)
],
),
),
],
),
),
),
secondChild: Container(
// height: !selected ? 100 : 400,
// key: _key,
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: Colors.white,
boxShadow: [
BoxShadow(
blurRadius: 2.5,
spreadRadius: 0.4,
color: Colors.grey,
offset: Offset(0, 0.5),
),
],
),
child: Padding(
padding: EdgeInsets.all(17),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Move fridge up stairs',
style: TextStyle(fontSize: 16),
),
SizedBox(height: 5),
Text(
'Sarah - 2 days ago - 2.3km',
style: TextStyle(color: Colors.black54),
),
],
),
),
),
),
),
),
],
),
),
],
));
}
}
You can use custom animation to do this, like this:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
bool selected = false;
GlobalKey _key1 = GlobalKey();
GlobalKey _key2 = GlobalKey();
AnimationController _controller;
Animation _animation;
bool foward = false;
#override
void initState() {
super.initState();
_controller =
AnimationController(vsync: this, duration: Duration(seconds: 1));
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
void didChangeDependencies() {
super.didChangeDependencies();
WidgetsBinding.instance.addPostFrameCallback((_) {
setState(() {
_animation = Tween<double>(
begin: _key1.currentContext.size.height,
end: _key2.currentContext.size.height +
_key1.currentContext.size.height)
.chain(CurveTween(curve: Curves.fastOutSlowIn))
.animate(_controller);
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: ListView(
children: [
Padding(
padding: EdgeInsets.all(5),
child: GestureDetector(
onTap: () {
if (foward) {
_controller.reverse();
} else {
_controller.forward();
}
foward = !foward;
},
child: (_animation == null)
? _buildWidget(_key1, _key2)
: AnimatedBuilder(
// curve: Curves.fastOutSlowIn,
animation: _controller,
builder: (context, child) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: Colors.white,
boxShadow: [
BoxShadow(
blurRadius: 2.5,
spreadRadius: 0.4,
color: Colors.grey,
offset: Offset(0, 0.5),
),
],
),
child: Padding(
padding: EdgeInsets.all(17.0),
child: Container(
height: _animation.value, child: child),
));
},
child: _buildWidget(_key1, _key2)),
),
),
],
)));
}
Widget _buildWidget(Key key1, Key key2) {
return SingleChildScrollView(
physics: const NeverScrollableScrollPhysics(),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Widget1(
key: _key1,
),
Widget2(
key: _key2,
),
],
),
);
}
}
class Widget1 extends StatefulWidget {
Widget1({Key key}) : super(key: key);
#override
_Widget1State createState() => _Widget1State();
}
class _Widget1State extends State<Widget1> {
#override
Widget build(BuildContext context) {
return Column(mainAxisSize: MainAxisSize.min, children: [
Text(
'Move fridge up stairs',
style: TextStyle(fontSize: 16),
),
SizedBox(height: 5),
Text(
'Sarah - 2 days ago - 2.3km',
style: TextStyle(color: Colors.black54),
),
]);
}
}
class Widget2 extends StatefulWidget {
Widget2({Key key}) : super(key: key);
#override
Widget2State createState() => Widget2State();
}
class Widget2State extends State<Widget2> {
#override
Widget build(BuildContext context) {
return Column(mainAxisSize: MainAxisSize.min, children: [
Container(
child: Column(children: [
Padding(
padding: EdgeInsets.fromLTRB(0, 20, 0, 20),
child: Text(
'Fridge is a single door. Sitting in kitchen. Need one strong person as I will help move it.',
style: TextStyle(
color: Colors.black54,
),
),
),
Padding(
padding: EdgeInsets.fromLTRB(0, 0, 0, 10),
child: Row(
children: [
Icon(
Icons.calendar_today,
color: Colors.black54,
size: 20,
),
Text(
' In three days',
style: TextStyle(
color: Colors.black54,
),
),
],
),
),
Padding(
padding: EdgeInsets.fromLTRB(0, 0, 0, 10),
child: Row(
children: [
Icon(
Icons.attach_money,
color: Colors.black54,
),
Text(
' 30',
style: TextStyle(
color: Colors.black54,
),
),
],
),
),
Row(
children: [
Text('Price : '),
Container(
width: 140,
margin: EdgeInsets.fromLTRB(0, 0, 0, 0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20.0),
color: Colors.white,
border: Border.all(color: Colors.white),
),
child: Container(
child: TextField(
decoration: new InputDecoration(
hintText: "Your price",
contentPadding: const EdgeInsets.all(10.0)),
keyboardType: TextInputType.number,
maxLines: null,
),
),
),
],
),
Row(
children: [
Text('Reply : '),
Expanded(
child: TextField(
decoration: new InputDecoration(
hintText: "Enter your reply",
contentPadding: const EdgeInsets.all(10.0)),
keyboardType: TextInputType.multiline,
maxLines: null,
),
),
],
),
SizedBox(height: 20),
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
SizedBox(
width: 10,
),
FlatButton(
shape: RoundedRectangleBorder(
side: BorderSide(
color: Colors.blue, width: 1, style: BorderStyle.solid),
borderRadius: BorderRadius.circular(50),
),
color: Colors.white,
textColor: Colors.black,
onPressed: () {
/*...*/
},
child: Padding(
padding: EdgeInsets.fromLTRB(0, 10, 0, 10),
child: Text(
"Reply",
),
))
])
]))
]);
}
}
How to make tab bar like below image in flutter?Is it possible to develop a Tabbar like below ?If not possible then what is the next better working solution?
Thank you for the support and i solved this issue my self without using any answers from stackoverflow
Try this way
I have created tab layout using ScrollablePositionedList
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_widgets/flutter_widgets.dart';
void main() => runApp(HomeScreen());
int currentTab = 0;
class HomeScreen extends StatefulWidget {
#override
_HomeScreenPage createState() => _HomeScreenPage();
}
class TabModel {
String text;
TabModel({this.text});
}
List<TabModel> _tabList = [
TabModel(text: "Android"),
TabModel(text: "IOS"),
TabModel(text: "Java"),
TabModel(text: "JavaScript"),
TabModel(text: "PHP"),
TabModel(text: "HTML"),
TabModel(text: "C++"),
];
class _HomeScreenPage extends State<HomeScreen>
with SingleTickerProviderStateMixin {
PageController _controller = PageController(initialPage: 0, keepPage: false);
final ItemScrollController itemScrollController = ItemScrollController();
final ItemPositionsListener itemPositionListener =
ItemPositionsListener.create();
#override
void initState() {
super.initState();
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.purple,
brightness: Brightness.light,
accentColor: Colors.red),
darkTheme: ThemeData(
brightness: Brightness.dark,
),
home: Scaffold(
appBar: AppBar(
title: Text("Custom TabBar"),
),
body: Column(
children: <Widget>[
Container(
height: 60,
margin: EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(14.0),
border: Border.all(color: Colors.black, width: 1.0)),
child: ScrollablePositionedList.builder(
scrollDirection: Axis.horizontal,
itemCount: _tabList.length,
itemBuilder: (context, index) {
return Container(
decoration: BoxDecoration(
gradient: currentTab == index
? LinearGradient(
colors: [
Colors.redAccent,
Colors.redAccent[200],
Colors.redAccent[100]
],
)
: null,
borderRadius: BorderRadius.circular(13.0),
),
child: FlatButton(
color: Colors.transparent,
onPressed: () {
setState(() {
currentTab = index;
_controller.jumpToPage(currentTab);
});
},
child: Text(
_tabList[index].text,
),
),
);
},
itemScrollController: itemScrollController,
itemPositionsListener: itemPositionListener,
)),
Flexible(
child: Container(
child: PageView(
controller: _controller,
onPageChanged: (pageId) {
setState(() {
currentTab = pageId;
itemScrollController.scrollTo(
index: currentTab, duration: Duration(seconds: 1));
});
},
children: <Widget>[
Container(
color: Colors.pink,
child: Center(
child: Text(
_tabList[currentTab].text,
style: TextStyle(
color: Colors.white,
fontSize: 50,
fontWeight: FontWeight.bold),
),
),
),
Container(
color: Colors.cyan,
child: Center(
child: Text(
_tabList[currentTab].text,
style: TextStyle(
color: Colors.white,
fontSize: 50,
fontWeight: FontWeight.bold),
),
),
),
Container(
color: Colors.red,
child: Center(
child: Text(
_tabList[currentTab].text,
style: TextStyle(
color: Colors.white,
fontSize: 50,
fontWeight: FontWeight.bold),
),
),
),
Container(
color: Colors.green,
child: Center(
child: Text(
_tabList[currentTab].text,
style: TextStyle(
color: Colors.white,
fontSize: 50,
fontWeight: FontWeight.bold),
),
),
),
Container(
color: Colors.grey,
child: Center(
child: Text(
_tabList[currentTab].text,
style: TextStyle(
color: Colors.white,
fontSize: 50,
fontWeight: FontWeight.bold),
),
),
),
Container(
color: Colors.purple,
child: Center(
child: Text(
_tabList[currentTab].text,
style: TextStyle(
color: Colors.white,
fontSize: 50,
fontWeight: FontWeight.bold),
),
),
),
Container(
color: Colors.teal,
child: Center(
child: Text(
_tabList[currentTab].text,
style: TextStyle(
color: Colors.white,
fontSize: 50,
fontWeight: FontWeight.bold),
),
),
),
],
),
)),
],
)));
}
}
You can find source code for this demo from my github account
OUTPUT
import 'package:flutter/material.dart';
void main() => runApp(
MaterialApp(home: MainScreen()),
);
class MainScreen extends StatefulWidget {
_MainState createState() => _MainState();
}
class _MainState extends State<MainScreen> {
int viewChoice = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text(
'Toolbar Title',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold /*fontSize,etc*/),
),
actions: [
IconButton(
icon: Icon(Icons.account_circle),
onPressed: () {
//Todo when pressed
}),
]),
body: Container(
child: Column(mainAxisSize: MainAxisSize.min, children: [
SizedBox(
height: 200,
width: double.infinity,
child: Stack(children: [
Container(
padding: EdgeInsets.all(10.0),
alignment: Alignment.centerLeft,
color: Colors.yellow,
height: 100.0,
width: double.infinity,
child: Text('Tem',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 20.0)), //Tem is in your ex pic
),
Positioned(
top: 75.0,
left: 40.0,
right: 40.0,
child: Container(
margin: EdgeInsets.only(left: 25.0, right: 25.0),
alignment: Alignment.topCenter,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(14.0),
border: Border.all(color: Colors.black, width: 1.0)),
child: Row(mainAxisSize: MainAxisSize.min, children: [
Expanded(
child: Container(
decoration: BoxDecoration(
gradient: viewChoice == 0
? LinearGradient(
colors: [Colors.orange, Colors.orangeAccent],
)
: null,
borderRadius: BorderRadius.circular(13.0),
border: viewChoice == 0
? Border.all(color: Colors.black, width: 1.0)
: null,
),
child: FlatButton(
color: Colors.transparent,
onPressed: () {
setState(() {
viewChoice = 0;
});
},
child: Text(
'All',
/*style as your requirement*/
),
),
),
),
Expanded(
child: Container(
decoration: BoxDecoration(
gradient: viewChoice == 1
? LinearGradient(
colors: [Colors.orange, Colors.orangeAccent],
)
: null,
borderRadius: BorderRadius.circular(13.0),
border: viewChoice == 1
? Border.all(color: Colors.black, width: 1.0)
: null,
),
child: FlatButton(
onPressed: () {
setState(() {
viewChoice = 1;
});
},
child: Text(
'Favorites',
/*style as your requirement*/
),
),
),
),
]),
),
),
]),
),
viewChoice == 0
? ListView(shrinkWrap: true, children: [
//Content of All categories
])
: ListView(shrinkWrap: true, children: [
//Content of All categories
])
]),
),
);
}
}
TabBar without AppBar
Give a try to below code.
import 'package:flutter/material.dart';
import 'package:flutter_text_to_image/utils/app_colors.dart';
class TabBarWidget extends StatefulWidget {
final String firstTabTxt;
final String firstTabViewTxt;
final String secondTabTxt;
final String secondTabViewTxt;
const TabBarWidget({
super.key,
required this.firstTabTxt,
required this.secondTabTxt,
required this.firstTabViewTxt,
required this.secondTabViewTxt,
});
#override
State
<TabBarWidget>
createState() => _TabBarWidgetState();
}
class _TabBarWidgetState extends State
<TabBarWidget>
with SingleTickerProviderStateMixin {
TabController? _tabController;
#override
void initState() {
_tabController = TabController(length: 2, vsync: this);
super.initState();
}
#override
void dispose() {
_tabController?.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Container(
height: 100,
child: Column(
children: [
Container(
height: 35,
decoration: BoxDecoration(
border: Border.all(
color: AppColors.tabBorderColor,
),
borderRadius: BorderRadius.circular(
5.0,
),
),
child: TabBar(
controller: _tabController,
indicator: BoxDecoration(
gradient: LinearGradient(
colors: [
AppColors.waterMelonColor,
AppColors.mangoColor,
AppColors.azureColor,
AppColors.sapphireColor,
],
begin: FractionalOffset(0.0, 0.0),
end: FractionalOffset(1.0, 0.0),
stops: [
0.1,
0.4,
0.6,
1.0,
],
tileMode: TileMode.clamp,
),
borderRadius: BorderRadius.circular(
2.0,
),
),
labelColor: AppColors.whiteColor,
unselectedLabelColor: AppColors.blackColor,
tabs: [
Tab(
text: widget.firstTabTxt,
),
Tab(
text: widget.secondTabTxt,
),
],
),
),
Expanded(
child: TabBarView(
controller: _tabController,
children: [
Padding(
padding: EdgeInsets.only(top: 10),
child: Column(
children: [
Text(
widget.firstTabViewTxt,
),
],
),
),
Padding(
padding: EdgeInsets.only(top: 10),
child: Column(
children: [
Text(
widget.secondTabViewTxt,
),
],
),
),
],
),
),
],
),
);
}
}