I am developing a city travel guide application for my project. In this project, I have page like this:
Screenshot
In this page, I want to make the container with red border scrollable vertically until green line with DraggableScrollableSheet . And also I want to add TabBarView to the same container and scroll horizontally.
But I can not handle, encountered with many render errors.
How can i fix this?
Here is the full code:
import 'package:after_layout/after_layout.dart';
import 'package:flutter/material.dart';
class CategoryScreen extends StatefulWidget {
final double _expandedBottomSheetBottomPosition = 0;
final townimage;
const CategoryScreen({Key key, this.townimage}) : super(key: key);
#override
_CategoryScreen createState() => _CategoryScreen(
townimage: this.townimage,
);
}
class _CategoryScreen extends State<CategoryScreen>
with TickerProviderStateMixin, AfterLayoutMixin<CategoryScreen> {
var townimage;
_CategoryScreen({this.townimage});
double _bottomSheetBottomPosition = -330;
bool isCollapsed = false;
TabController _tabController;
#override
void initState() {
super.initState();
_tabController = TabController(length: 2, vsync: this);
}
#override
Widget build(BuildContext context) {
return Scaffold(
extendBodyBehindAppBar: true,
appBar: AppBar(elevation: 0, backgroundColor: Colors.transparent),
body: Container(
child: Stack(
fit: StackFit.expand,
children: <Widget>[
Hero(
tag: "image" + townimage,
child: Image.asset(
"images/photos/turkey.jpg",
fit: BoxFit.cover,
)),
AnimatedPositioned(
duration: const Duration(milliseconds: 500),
curve: Curves.decelerate,
bottom: _bottomSheetBottomPosition,
left: 0,
right: 0,
child: Column(
children: [
_tabBar(),
Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.red, width: 3.0),
color: Theme.of(context).canvasColor,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(40),
topRight: Radius.circular(40),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
alignment: Alignment.centerLeft,
padding: const EdgeInsets.symmetric(horizontal: 32),
height: 90,
child: Row(
children: [
Text(
"Historical Places",
style: TextStyle(
fontSize: 28.0,
color: Colors.white,
fontWeight: FontWeight.bold),
),
],
),
),
SingleChildScrollView(
physics: ScrollPhysics(),
child: _clipsWidget(),
),
],
),
),
],
),
),
],
),
),
);
}
Widget _clipsWidget() {
return Container(
color: Theme.of(context).canvasColor,
height: 250,
margin: const EdgeInsets.symmetric(horizontal: 16),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.account_balance_rounded),
Text("I want to add TabBarView to this area"),
Text(
"Some Future Builder elements will be implemented.",
)
],
),
));
}
#override
void afterFirstLayout(BuildContext context) {
Future.delayed(const Duration(milliseconds: 500), () {
setState(() {
isCollapsed = true;
_bottomSheetBottomPosition = widget._expandedBottomSheetBottomPosition;
});
});
}
Widget _tabBar() {
return TabBar(
controller: _tabController,
indicatorColor: Colors.transparent,
isScrollable: true,
labelColor: Colors.white,
unselectedLabelColor: Colors.grey,
labelPadding: EdgeInsets.symmetric(horizontal: 10),
tabs: [
Container(
height: 70,
child: Tab(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
margin: EdgeInsets.all(5),
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(100),
color: Theme.of(context).canvasColor.withOpacity(0.8),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(
Icons.account_balance_rounded,
),
),
),
],
)),
),
Container(
height: 70,
child: Tab(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
margin: EdgeInsets.all(5),
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(100),
color: Theme.of(context).canvasColor.withOpacity(0.8),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(
Icons.park,
),
),
),
],
)),
),
]);
}
}
Related
Bottom align clipped image in Flutter
Hello!
I'm beginner in Flutter
The following image:
I clipped the lettuce image in half with ClipPath:
I'm trying to move it into bottom right to be similar to the following image:
I tried many times with my available experience with no luck
Here's the code:
class GroceryPage extends StatelessWidget {
const GroceryPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(15.0),
child: SingleChildScrollView(
child: Column(
children: [
const SizedBox(height: 10.0),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30.0),
color: const Color(0xFFE9F9F2),
),
width: double.infinity,
child: Stack(
children: [
ClipPath(
clipper: HalfClip(),
child: Align(
alignment: Alignment.bottomRight,
child: Image.asset(
'${kProductsImagesAsset}lettuce.png',
height: 150,
// width: 150,
fit: BoxFit.cover,
),
),
),
Padding(
padding: const EdgeInsets.all(40.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Get Up To',
style: kGreenTitleStyle.copyWith(
fontSize: 20.0,
),
),
Text(
'%10 off',
style: kGreenTitleStyle.copyWith(
fontSize: 40.0,
),
),
],
),
),
],
),
),
],
),
),
),
),
);
}
}
Can anyone help me doing so?
Use Positioned widget as Stack child.
Positioned(
top: 0,
left: 0,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Get Up To',
style: kGreenTitleStyle.copyWith(
fontSize: 20.0,
),
),
Text(
'%10 off',
style: kGreenTitleStyle.copyWith(
fontSize: 40.0,
),
),
],
),
),
More about using Stack
class GroceryPage extends StatelessWidget {
const GroceryPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(15.0),
child: SingleChildScrollView(
child: Column(
children: [
const SizedBox(height: 10.0),
Container(
height: 300, //cardHeight
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30.0),
color: const Color(0xFFE9F9F2),
),
child: Stack(
children: [
Align(
child: Container(
height: 600, // full image height= cardHeight*2
color: Colors.red,
),
// child: Image.asset(
// '${kProductsImagesAsset}lettuce.png',
// height: 150,
// // width: 150,
// fit: BoxFit.cover,
// ),
),
Positioned(
top: 0,
left: 0,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Get Up To',
style: TextStyle(
fontSize: 20.0,
),
),
Text(
'%10 off',
style: TextStyle(
fontSize: 40.0,
),
),
],
),
),
],
),
),
],
),
),
),
),
);
}
}
I am using carousal slider with page view but when I am sliding the images in scroll view it is sliding to me to next page instead of next image. I just want to slide images when I slide on image and i want to slide to the next page when i slide below the image. but now wherever i slide on the screen it take me to the next page.
This is my page view.
import 'package:bartermade/controllers/profileController.dart';
import 'package:bartermade/models/tradeModel.dart';
import 'package:bartermade/widgets/profileView.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../screens/home/bottomBarViews/homeView/categoriesDetailScreen.dart';
class PageViewHolder extends StatelessWidget {
final PageController pageController = PageController(
initialPage: 0,
);
ProfileController _profileController = Get.find();
final String reciverId;
final String currentUserId;
final TradeModel catData;
PageViewHolder(
{required this.reciverId,
required this.currentUserId,
required this.catData});
var followersList = ['Ali', 'Hussain', 'Hassan', 'Akhtar'];
#override
Widget build(BuildContext context) {
// print("cat ID " + "${catData.user.id}");
// print("profile ID " + "${_profileController.profileId}");
return Scaffold(
body: PageView(
// physics: catData.user.id != _profileController.profileId.value
// ? AlwaysScrollableScrollPhysics()
// : NeverScrollableScrollPhysics(),
physics: ClampingScrollPhysics(),
pageSnapping: false,
onPageChanged: (index) {
},
controller: pageController,
children: [
//first screen in page view
TradeDetailScreen(
catData: catData,
currentUserId: currentUserId,
reciverId: reciverId,
),
//second screen here
ProfileView(
firstName: catData.user.firstName,
lastName: catData.user.lastName,
followers: followersList,
profileUrl: catData.user.profilePictureUrl,
screenState: true,
),
],
),
);
}
}
And this is my screen page
#override
Widget build(BuildContext context) {
return Scaffold(
body: LayoutBuilder(
builder: (context, constraints) {
return OrientationBuilder(
builder: (context, orientation) => SafeArea(
child: SingleChildScrollView(
child: Column(children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
IconButton(
onPressed: () {
Get.back();
},
icon: Icon(
Icons.arrow_back_ios,
color: Colors.grey,
)),
Container(
clipBehavior: Clip.antiAlias,
height: 50,
width: 50,
decoration: BoxDecoration(
shape: BoxShape.circle,
),
child: CachedNetworkImage(
fit: BoxFit.cover,
imageUrl: '${widget.profileUrl}',
placeholder: (context, url) =>
Center(child: CircularProgressIndicator()),
errorWidget: (context, url, error) =>
Icon(Icons.error),
),
),
SizedBox(
width: 7,
),
Flexible(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
"${widget.lastName ?? " " "${widget.firstName ?? " "}"}",
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: (MediaQuery.of(context)
.size
.height /
100) *
2),
),
widget.catData["user"] ==
profileController.userId.value
? Container(
height: 0,
width: 0,
)
: Container(
padding: EdgeInsets.all(5),
child: Center(
child: Text(
'Follow',
style: TextStyle(
color: Colors.white,
fontSize: 12),
),
),
//width: 50,
decoration: BoxDecoration(
color: AppColors.pinkAppBar,
borderRadius: BorderRadius.all(
Radius.circular(20)))),
],
),
Row(
//crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'4.3',
style: TextStyle(
color: Colors.grey,
fontWeight: FontWeight.bold,
fontSize: (MediaQuery.of(context)
.size
.height /
100) *
1.8),
),
Icon(
Icons.star,
size: 15,
color: Colors.yellow,
),
],
),
],
),
)
],
),
),
Column(
children: [
widget.catData["pictures"] == [] ||
widget.catData["pictures"].length == 0 ||
widget.catData["pictures"].isEmpty ||
widget.catData["pictures"] == null
? Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height * 0.6,
child: Center(child: Text(" No Image to show")))
: Stack(
children: [
CarouselSlider(
items: widget.catData["tradeWithPictures"]
.map<Widget>((e) {
return Container(
width: Get.width,
child: CachedNetworkImage(
fit: BoxFit.cover,
imageUrl: e['url'],
placeholder: (context, url) => Center(
child: CircularProgressIndicator()),
errorWidget: (context, url, error) =>
Icon(Icons.error),
),
);
}).toList(),
carouselController:
postController.carouselController,
options: CarouselOptions(
autoPlay: true,
enableInfiniteScroll: true,
height: Get.height * .7,
viewportFraction: 1.0,
enlargeCenterPage: false,
aspectRatio: 1 / 1.3,
onPageChanged: (index, reason) {
// postController.tradeImagesIndex(index);
// postController.carouselController.nextPage();
},
),
),
Positioned(
top: MediaQuery.of(context).size.height * 0.3,
bottom:
MediaQuery.of(context).size.height * 0.3,
left: 0,
right: 0,
child: Container(
padding:
EdgeInsets.symmetric(horizontal: 10),
width: MediaQuery.of(context).size.width,
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
ElevatedButton(
child: Icon(Icons.arrow_back_ios),
style: ButtonStyle(
splashFactory:
NoSplash.splashFactory,
shape: MaterialStateProperty.all<
RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(25.0),
side: BorderSide(
color: AppColors.pinkColor),
),
),
),
onPressed: () {
postController.carouselController
.previousPage();
},
),
ElevatedButton(
child: Icon(Icons.arrow_forward_ios),
style: ButtonStyle(
splashFactory:
NoSplash.splashFactory,
shape: MaterialStateProperty.all<
RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(25.0),
side: BorderSide(
color: AppColors.pinkColor),
),
),
),
onPressed: () {
postController.carouselController
.nextPage();
},
),
],
),
),
),
],
),
SizedBox(
height: 10,
),
],
),
Container(
margin: EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
widget.catData["title"],
style: TextStyle(
color: AppColors.detailTextsColor,
fontWeight: FontWeight.bold),
),
profileController.userId == widget.catData["user"]
? Container(
height: 0,
width: 0,
)
: InkWell(
onTap: () {
},
child: Container(
padding: EdgeInsets.all(5),
child: Center(
child: Text(
'Offer Trade',
style: TextStyle(
color: Colors.white,
fontSize: 12),
),
),
//width: 50,
decoration: BoxDecoration(
color: AppColors.pinkAppBar,
borderRadius: BorderRadius.all(
Radius.circular(20),
),
),
),
),
],
I have implemented BLOC architecture for a user profile edit for a logged in user in flutter. The inputs are filled with user's existing info which I got from the API. But whenever input is focused and keyboard closes the entered value gets replaced with the initial value which I got from the API response.
This is my View profile UI
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:payd/services/profile_service.dart';
import 'package:payd/bloc/profile_bloc.dart';
import 'package:payd/model/profile_model.dart';
void main() {
runApp(EditProfile());
}
class EditProfile extends StatefulWidget {
#override
_EditProfilesState createState() => _EditProfilesState();
}
class _EditProfilesState extends State<EditProfile>
with AutomaticKeepAliveClientMixin {
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
title: Image.asset('assets/logo.png', fit: BoxFit.cover),
actions: [
IconButton(
onPressed: () {},
icon: Image.asset('assets/Icon feather-bell.png'),
iconSize: 30,
),
],
elevation: 5,
),
backgroundColor: Color(0xFF33138C),
body: BlocProvider(
create: (context) => ProfileBloc(ProfileService()),
child: Body(),
),
);
}
#override
// TODO: implement wantKeepAlive
bool get wantKeepAlive => true;
}
class Body extends StatelessWidget {
static final _formKey = GlobalKey<FormState>();
void _submit() {
final isValid = _formKey.currentState.validate();
if (!isValid) {
return;
}
_formKey.currentState.save();
}
#override
Widget build(BuildContext context) {
final textFieldFocusNode = FocusNode();
final profileBloc = BlocProvider.of<ProfileBloc>(context);
var userSlug = '52q6x93k4y';
profileBloc.add(FetchProfile(userSlug));
Size size = MediaQuery.of(context).size;
return Container(
constraints: BoxConstraints.expand(),
decoration: BoxDecoration(
image: DecorationImage(
image: new ExactAssetImage('assets/app-background.png'),
fit: BoxFit.cover)),
child: Padding(
padding: const EdgeInsets.all(0),
child: SingleChildScrollView(
physics: NeverScrollableScrollPhysics(),
child: Column(
children: <Widget>[
SizedBox(
height: size.height,
child: Stack(
children: <Widget>[
Container(
margin: EdgeInsets.only(top: size.height * 0.04),
// height: 400,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(40.0),
topRight: Radius.circular(40.0),
),
),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Column(
children: [
Container(
padding: EdgeInsets.only(
top: 30.0,
left: 20.0, bottom: 25.0),
alignment: Alignment.centerLeft,
child: IconButton(
onPressed: () {
Navigator.pop(context);
},
icon: Icon(Icons.keyboard_arrow_left),
iconSize: 30,
),
),
],
),
Column(
children: [
Container(
padding: EdgeInsets.only(
top: 30.0,
right: 30.0, bottom: 25.0),
alignment: Alignment.centerLeft,
child: Text(
'Edit Account',
style: const TextStyle(
fontSize: 17.0,
fontWeight: FontWeight.w600,
color: Colors.black54),
),
),
],
),
],
),
BlocBuilder<ProfileBloc, ProfileState>(
builder: (context, state) {
print(state);
if (state is ProfileIsLoaded) {
return Container(
child: Flexible(
child: SingleChildScrollView(
reverse: true,
padding:
EdgeInsets.only(left: 16, right: 16),
child: Column(
children: <Widget>[
Container(
margin: EdgeInsets.only(
bottom:
size.height > 700
? 20
: 15),
padding: EdgeInsets.only(
left: 20.0,
right: 20.0,
bottom: 25.0),
child: Form(
key: _formKey,
child: Column(
children: <Widget>[
TextFormField(
controller: TextEditingController(
text: state.getProfile.firstName),
decoration: InputDecoration(
labelText: 'First Name'),
keyboardType: TextInputType
.name,
onFieldSubmitted: (
value) {
//Validator
},
validator: (value) {
if (value.isEmpty) {
return 'Required';
}
return null;
},
),
//box styling
SizedBox(
height: MediaQuery
.of(context)
.size
.width *
0.1,
),
TextFormField(
controller: TextEditingController(
text: state.getProfile.lastName),
decoration: InputDecoration(
labelText: 'Last Name'),
keyboardType: TextInputType
.name,
onFieldSubmitted: (
value) {
//Validator
},
validator: (value) {
if (value.isEmpty) {
return 'Required';
}
return null;
},
),
//box styling
SizedBox(
height: MediaQuery
.of(context)
.size
.width *
0.1,
),
SizedBox(
width: double.infinity,
child: TextButton(
style: ButtonStyle(
padding: MaterialStateProperty
.all(
EdgeInsets.only(
top: 16.0,
bottom: 16.0),),
foregroundColor:
MaterialStateProperty
.all<Color>(
Colors.white),
backgroundColor: MaterialStateProperty
.all<Color>(
Color(
0xFF33138C)),
shape: MaterialStateProperty
.all<
RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius
.circular(
25.0),
side: BorderSide(
color: Color(
0xFF33138C)))),),
onPressed: () =>
_submit(),
child: Text('Save',
style: TextStyle(
fontSize: 16.0
),),
),
),
],
),
),
),
],
),
),
),
);
} else {
return Center(child : CircularProgressIndicator());
}
}
),
SizedBox(height: 150),
],
)),
],
))
],
),
),
),
);
}
}
class ProfileError extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[Image.asset('assets/empty-list.png')],
),
Text(
'Error',
style: const TextStyle(
fontSize: 16.0,
fontWeight: FontWeight.w600,
color: Colors.black87),
),
Padding(
padding: EdgeInsets.only(left: 30.0, right: 30.0),
child: Text(
'After your first order you\'ll be able to view it here',
style: const TextStyle(
fontSize: 15.0,
fontWeight: FontWeight.w600,
color: Colors.grey,
),
textAlign: TextAlign.center,
),
),
],
),
);
}
}
I was trying to recreate a design concept from this guy(https://dribbble.com/shots/3812962-iPhone-X-Todo-Concept) but I'm getting some troubles with the ListView alignment or so I think.
What I'm trying to do is moving the List to the right without cutting the edges of the cards when I swipe.
I already tried with margin and padding but none of this applied to the container produces the results I want to obtain.Edges are cutted off when I swipe.
I leave here the Container with the ListView inside it.
Screenshoots of the actual app:
https://imgur.com/a/hJ96sEv
Container(
height: 350.0,
child: ListView.builder(
physics: NeverScrollableScrollPhysics(),
itemCount: 3,
controller: scrollController,
scrollDirection: Axis.horizontal,
itemBuilder: (context, position) {
return GestureDetector(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
child: Container(
width: 250.0,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: <Widget>[
Icon(
cardsList[position].icon,
color: appColors[position],
),
Icon(
Icons.more_vert,
color: Colors.grey,
)
],
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 8.0, vertical: 4.0),
child: Text(
"${cardsList[position].tasksRemaining} Tasks",
style:
TextStyle(color: Colors.grey),
),
),
Padding(
padding:
const EdgeInsets.symmetric(
horizontal: 8.0,
vertical: 4.0),
child: Text(
"${cardsList[position].cardTitle}",
style:
TextStyle(fontSize: 28.0),
)),
Padding(
padding: const EdgeInsets.all(8.0),
child: LinearProgressIndicator(
value: cardsList[position]
.taskCompletion,
),
)
],
),
),
],
),
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0)),
),
),
onHorizontalDragEnd: (details) {
animationController = AnimationController(
vsync: this,
duration: Duration(milliseconds: 450));
curvedAnimation = CurvedAnimation(
parent: animationController,
curve: Curves.fastOutSlowIn);
animationController.addListener(() {
setState(() {
currentColor =
colorTween.evaluate(curvedAnimation);
});
});
if (details.velocity.pixelsPerSecond.dx > 0) {
if (cardIndex > 0) {
cardIndex--;
colorTween = ColorTween(
begin: currentColor,
end: appColors[cardIndex]);
}
} else {
if (cardIndex < 2) {
cardIndex++;
colorTween = ColorTween(
begin: currentColor,
end: appColors[cardIndex]);
}
}
setState(() {
scrollController.animateTo((cardIndex) * 256.0,
duration: Duration(milliseconds: 450),
curve: Curves.fastOutSlowIn);
});
colorTween.animate(curvedAnimation);
animationController.forward();
});
},
),
),
What I'm trying to do is moving the List to the right without cutting the edges of the cards when I swipe.
To achieve that goal you need a PageView instead of a ListView, that way you can swipe and "snap" the views when you reach and specific position:
PageView.builder(
itemCount: tasks.length,
controller: PageController(initialPage: 0, viewportFraction: 0.8),
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 10),
child: Container(
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Color(0x40000000),
blurRadius: 10,
offset: Offset(0, 12),
),
],
),
child: Card(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10),
),
color: Colors.white,
child: Padding(
padding: const EdgeInsets.all(15),
child: Column(
children: <Widget>[
IntrinsicHeight(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Icon(tasks[index].icon),
Expanded(
child: Container(
child: Align(
alignment: Alignment.topRight,
child: Icon(Icons.menu),
),
),
),
],
),
),
Expanded(
child: Container(
width: double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Text(
"${tasks[index].tasks} tasks",
style: TextStyle(
color: Color(0xD0000000),
fontSize: 15,
),
),
SizedBox(height: 10),
Text(
"${tasks[index].title}",
style: TextStyle(
color: Color(0xD0000000),
fontSize: 24,
),
),
SizedBox(height: 10),
LinearProgressIndicator(
value: tasks[index].percentage,
backgroundColor: Color(0x300000FF),
)
],
),
),
),
],
),
),
),
),
);
},
)
The result of this implementation is something like this:
If you want to change the offset of the cards, you need to modify the value viewportFraction: 0.8 to anything you'd like. 1.0 is the value without offset.
You can find my full implementation over this Gist Github
Hi I want to display the CircularProgressIndicator in centre of my screen on top of all widget. it should be like overlay.
Right now when CircularProgressIndicator is visible all widgets move down a bit to display CircularProgressIndicator . I want it should be overlay. Does anyone know how to do that ?
import 'package:flutter/material.dart';
import 'package:roomie/auth/Auth.dart';
class ForgotPasswordScreen extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return ForgotPasswordScreenState();
}
}
class ForgotPasswordScreenState extends State<ForgotPasswordScreen> {
var emailController = new TextEditingController();
var authHandler = new Auth();
bool isLoading = false;
#override
Widget build(BuildContext context) {
return new Scaffold(
body: Container(
height: MediaQuery.of(context).size.height,
decoration: BoxDecoration(
color: Colors.white,
),
child: new Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Row(
children: <Widget>[
new Expanded(
child: isLoading
? Center(child: CircularProgressIndicator())
: new Container()),
],
),
new Row(
children: <Widget>[
new Expanded(
child: new Padding(
padding: const EdgeInsets.only(left: 40.0),
child: new Text(
"EMAIL",
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.redAccent,
fontSize: 15.0,
),
),
),
),
],
),
new Container(
width: MediaQuery.of(context).size.width,
margin:
const EdgeInsets.only(left: 40.0, right: 40.0, top: 10.0),
alignment: Alignment.center,
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: Colors.redAccent,
width: 0.5,
style: BorderStyle.solid),
),
),
padding: const EdgeInsets.only(left: 0.0, right: 10.0),
child: new Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
new Expanded(
child: TextField(
controller: emailController,
textAlign: TextAlign.left,
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'PLEASE ENTER YOUR EMAIL',
hintStyle: TextStyle(color: Colors.grey),
),
),
),
],
),
),
Divider(
height: 24.0,
),
new Container(
width: MediaQuery.of(context).size.width,
margin:
const EdgeInsets.only(left: 30.0, right: 30.0, top: 20.0),
alignment: Alignment.center,
child: new Row(
children: <Widget>[
new Expanded(
child: new FlatButton(
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(30.0),
),
color: Colors.redAccent,
onPressed: () {
setState(() {
isLoading = true;
});
authHandler
.sendPasswordResetEmail(emailController.text)
.then((void nothing) async {
await showDialog(
context: context,
builder: (BuildContext context) {
// return object of type Dialog
return AlertDialog(
content: new Text(
"Password reset email has been sent."),
actions: <Widget>[
// usually buttons at the bottom of the dialog
new FlatButton(
child: new Text("OK"),
onPressed: () {
Navigator.pop(context);
},
),
],
);
},
);
Navigator.pop(context);
setState(() {
isLoading = false;
});
}).catchError((e) => print(e));
},
child: new Container(
padding: const EdgeInsets.symmetric(
vertical: 20.0,
horizontal: 20.0,
),
child: new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Expanded(
child: Text(
"FORGOT PASSWORD",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold),
),
),
],
),
),
),
),
],
),
),
],
)));
}
}
Stack is what you'r looking for :
https://docs.flutter.io/flutter/widgets/Stack-class.html
#override
Widget build(BuildContext context) {
return new Scaffold(
body: Stack(
children:<Widget>[ Container(
height: MediaQuery.of(context).size.height,
decoration: BoxDecoration(
color: Colors.white,
),
child: new Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Row(
children: <Widget>[
new Expanded(
child: new Padding(
padding: const EdgeInsets.only(left: 40.0),
child: new Text(
"EMAIL",
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.redAccent,
fontSize: 15.0,
),
),
),
),
],
),
new Container(
width: MediaQuery.of(context).size.width,
margin:
const EdgeInsets.only(left: 40.0, right: 40.0, top: 10.0),
alignment: Alignment.center,
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: Colors.redAccent,
width: 0.5,
style: BorderStyle.solid),
),
),
padding: const EdgeInsets.only(left: 0.0, right: 10.0),
child: new Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
new Expanded(
child: TextField(
controller: emailController,
textAlign: TextAlign.left,
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'PLEASE ENTER YOUR EMAIL',
hintStyle: TextStyle(color: Colors.grey),
),
),
),
],
),
),
Divider(
height: 24.0,
),
new Container(
width: MediaQuery.of(context).size.width,
margin:
const EdgeInsets.only(left: 30.0, right: 30.0, top: 20.0),
alignment: Alignment.center,
child: new Row(
children: <Widget>[
new Expanded(
child: new FlatButton(
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(30.0),
),
color: Colors.redAccent,
onPressed: () {
setState(() {
isLoading = true;
});
authHandler
.sendPasswordResetEmail(emailController.text)
.then((void nothing) async {
await showDialog(
context: context,
builder: (BuildContext context) {
// return object of type Dialog
return AlertDialog(
content: new Text(
"Password reset email has been sent."),
actions: <Widget>[
// usually buttons at the bottom of the dialog
new FlatButton(
child: new Text("OK"),
onPressed: () {
Navigator.pop(context);
},
),
],
);
},
);
Navigator.pop(context);
setState(() {
isLoading = false;
});
}).catchError((e) => print(e));
},
child: new Container(
padding: const EdgeInsets.symmetric(
vertical: 20.0,
horizontal: 20.0,
),
child: new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Expanded(
child: Text(
"FORGOT PASSWORD",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold),
),
),
],
),
),
),
),
],
),
),
],
)),
isLoading ? Container(
color: Colors.black.withOpacity(0.5),
child: Center(
child: CircularProgressIndicator(),
),
) : Container()
],
));
}
2021: Although Stack is a phenomenal option, a simple showDialog will do the trick. It is clean, efficient, and will give you a fade in/out animation. Code:
onEvent: () {
showDialog(
barrierDismissible: false,
builder: (ctx) {
return Center(
child: CircularProgressIndicator(
strokeWidth: 2,
),
)
},
context: context,
);
},
When the event is completed, call Navigator.of(context).pop();. If you want the user to be able to tap the screen and close the dialog manually, delete the barrierDismissable: false code. If you have issues with the .pop(), you may want to specifically use the dialog's context when dismissing.