I am currently working on the ui stuff for the appliction, so the thing is i have one gesture as a parent that swipes up and down and based on it the position of the widgets gets changed but the problem is the child gesture does not get any precedence when tapped on it it gives the precedence. So my tree structure is Pageview.builder which has single widget with topmost parent as Gesturedetector and the children accrodingly, Can any one tell me what i am doing wrong or any improvements to get the gesture for each.
Below is the sample code that i have been working on:
import 'dart:math';
import 'package:LocationAnimation/Model/device_model.dart';
import 'package:LocationAnimation/SplashPage/splash_page.dart';
import 'package:LocationAnimation/widgets/device_function_widget.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:google_fonts/google_fonts.dart';
import 'Model/device_model.dart' as devices;
import 'Model/locations_model.dart' as locations;
import 'extensions/capitalize.dart';
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'HAL',
home: MyHomePage(),
);
}
}
class SampleList {
final String locationName;
SampleList({this.locationName});
}
class MyHomePage extends StatefulWidget {
#override
State createState() => new MyHomePageState();
}
class MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
final _controller = new PageController();
final _kArrowColor = Colors.black.withOpacity(0.8);
bool _isSwipe = false;
bool _isLoading = false;
var list = [
SampleList(locationName: 'Living Room'),
SampleList(locationName: 'Bed Room'),
SampleList(locationName: 'Back Porch Lights'),
SampleList(locationName: 'Basement Porch Lights'),
SampleList(locationName: 'Sample Room'),
];
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new IconTheme(
data: new IconThemeData(color: _kArrowColor),
child: new Stack(
children: <Widget>[
new PageView.builder(
physics: _isSwipe
? NeverScrollableScrollPhysics()
: AlwaysScrollableScrollPhysics(),
controller: _controller,
itemCount: list.length,
itemBuilder: (BuildContext context, int index) {
return LocationDetails(
isLoading: _isLoading,
item: list[index],
onSwipeDown: () {
setState(() {
_isSwipe = false;
});
},
onSwipeUp: () {
setState(() {
_isSwipe = true;
});
},
);
},
),
],
),
),
);
}
}
class LocationDetails extends StatefulWidget {
final bool isLoading;
SampleList item;
final Function() onSwipeUp;
final Function() onSwipeDown;
LocationDetails(
{Key key, this.item, this.onSwipeUp, this.onSwipeDown, this.isLoading})
: super(key: key);
#override
_LocationDetailsState createState() => _LocationDetailsState();
}
class _LocationDetailsState extends State<LocationDetails> {
DragStartDetails startVerticalDragDetails;
DragUpdateDetails updateVerticalDragDetails;
bool moveWidget = false;
bool dismissSwipeText = true;
bool _isRotate = false;
int currentSelectedIndex = 0;
bool ignoreChildGestures = true;
bool _isSwpie = false;
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Container(
child: GestureDetector(
onTap: () {
print('Tap');
},
onVerticalDragStart: (dragDetails) {
startVerticalDragDetails = dragDetails;
},
onVerticalDragUpdate: (dragDetails) {
updateVerticalDragDetails = dragDetails;
},
onVerticalDragEnd: (endDetails) {
double dx = updateVerticalDragDetails.globalPosition.dx -
startVerticalDragDetails.globalPosition.dx;
double dy = updateVerticalDragDetails.globalPosition.dy -
startVerticalDragDetails.globalPosition.dy;
double velocity = endDetails.primaryVelocity;
//Convert values to be positive
if (dx < 0) dx = -dx;
if (dy < 0) dy = -dy;
if (velocity < 0) {
widget.onSwipeUp();
print('drag up');
setState(() {
moveWidget = true;
_isSwpie = true;
});
} else {
widget.onSwipeDown();
print(' drag down');
setState(() {
moveWidget = false;
_isSwpie = false;
});
}
},
child: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
decoration: new BoxDecoration(
image: new DecorationImage(
colorFilter: ColorFilter.mode(
Colors.black.withOpacity(0.8), BlendMode.srcOver),
image: /* moveWidget
? */
AssetImage(
'Assets/backgroundImage.jpg',
),
/* : NetworkImage(widget.samplePage.networkImage), */
fit: BoxFit.fill,
),
),
child:
/* widget.isLoading
? Center(
child: CircularProgressIndicator(),
)
: */
Stack(
children: <Widget>[
AnimatedOpacity(
opacity: moveWidget ? 0 : 1,
duration: Duration(microseconds: 100),
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Column(
children: <Widget>[
Icon(
Icons.power_settings_new,
color: Colors.white,
size: 30,
),
Icon(
Icons.more_horiz,
color: Colors.white,
size: 25,
)
],
),
Row(
children: <Widget>[
Column(
children: <Widget>[
Text(
'Inside Temp',
style: TextStyle(
color: Colors.white, fontSize: 18),
),
SizedBox(
height: 5,
),
Row(
children: <Widget>[
Icon(
Icons.ac_unit,
color: Colors.white,
size: 20,
),
SizedBox(
width: 10,
),
Text(
'19 C',
style: TextStyle(color: Colors.white),
),
],
)
],
),
SizedBox(
width: 10,
),
Column(
children: <Widget>[
Text(
'Outside Temp',
style: TextStyle(
color: Colors.white, fontSize: 18),
),
SizedBox(
height: 5,
),
Row(
children: <Widget>[
Icon(
Icons.ac_unit,
color: Colors.white,
size: 20,
),
SizedBox(
width: 10,
),
Text(
'19 C',
style: TextStyle(color: Colors.white),
),
],
)
],
),
],
)
],
),
),
),
AnimatedPositioned(
onEnd: () {
setState(() {
dismissSwipeText = !dismissSwipeText;
//print(dismissSwipeText);
});
},
curve: Curves.ease,
duration: Duration(milliseconds: 700),
bottom: moveWidget
? 10
: MediaQuery.of(context).size.height * 0.18,
left: 10.0,
right: 0.0,
top: moveWidget
? 50
: MediaQuery.of(context).size.height * 0.75,
child: AnimatedOpacity(
opacity: dismissSwipeText ? 1 : 0,
duration: Duration(milliseconds: 500),
child: Text(
'Swipe up to customize',
style: TextStyle(color: Colors.white, fontSize: 20),
),
),
),
AnimatedPositioned(
curve: Curves.ease,
duration: Duration(milliseconds: 700),
onEnd: () {
setState(() {
_isSwpie = true;
});
},
left: 10,
top: moveWidget
? 80
: MediaQuery.of(context).size.height * 0.80,
child: Container(
width: MediaQuery.of(context).size.width * 0.97,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
GestureDetector(
onTap: () {
setState(() {
currentSelectedIndex = 0;
});
},
child: Container(
width: MediaQuery.of(context).size.width * 0.20,
height:
MediaQuery.of(context).size.height * 0.10,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: currentSelectedIndex == 0
? Colors.blue
: Colors.grey[900],
),
child: Center(
child: Text(
'Lights',
style: GoogleFonts.lato(
color: Colors.white,
fontWeight: FontWeight.w700),
)),
),
),
Row(
children: <Widget>[
SizedBox(
width: 10,
),
GestureDetector(
onTap: () {
setState(() {
currentSelectedIndex = 1;
});
},
child: Container(
width: MediaQuery.of(context).size.width *
0.20,
height: MediaQuery.of(context).size.height *
0.10,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: currentSelectedIndex == 1
? Colors.blue
: Colors.grey[900],
),
child: Center(
child: Text(
'Applicanes',
style: GoogleFonts.lato(
color: Colors.white,
fontWeight: FontWeight.w700),
)),
),
),
],
),
Row(
children: <Widget>[
SizedBox(
width: 10,
),
GestureDetector(
onTap: () {
setState(() {
currentSelectedIndex = 2;
});
},
child: Container(
width: MediaQuery.of(context).size.width *
0.20,
height: MediaQuery.of(context).size.height *
0.10,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: currentSelectedIndex == 2
? Colors.blue
: Colors.grey[900],
),
child: Center(
child: Text(
'Sensors',
style: GoogleFonts.lato(
color: Colors.white,
fontWeight: FontWeight.w700),
)),
),
),
],
),
Row(
children: <Widget>[
SizedBox(
width: 10,
),
Container(
width:
MediaQuery.of(context).size.width * 0.20,
height:
MediaQuery.of(context).size.height * 0.10,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Colors.grey[900],
),
child: Center(
child: Text(
'Doors \n& Locks',
style: GoogleFonts.lato(
color: Colors.white,
fontWeight: FontWeight.w700),
)),
),
],
),
SizedBox(
width: 10,
),
],
),
),
),
AnimatedPositioned(
curve: Curves.ease,
duration: Duration(milliseconds: 400),
bottom: moveWidget
? 10
: MediaQuery.of(context).size.height * 0.20,
left: 10.0,
right: 0.0,
top: moveWidget
? 15
: MediaQuery.of(context).size.height * 0.70,
child: Text(
'${widget.item.locationName}',
style: TextStyle(fontSize: 30, color: Colors.white),
),
),
],
)),
),
),
),
);
}
}
You can add Color to the last AnimatedPositioned which use text widget.item.locationName in your code, like:
AnimatedPositioned(
curve: Curves.ease,
duration: Duration(milliseconds: 400),
bottom: moveWidget
? 10
: MediaQuery.of(context).size.height * 0.20,
left: 10.0,
right: 0.0,
top: moveWidget
? 15
: MediaQuery.of(context).size.height * 0.70,
child: Container(
color: Colors.white,
Text(
'${widget.item.locationName}',
style: TextStyle(fontSize: 30, color: Colors.white),
),
),
),
You will see a white screen (the widget which blocking you) when you scroll up. You can fix it by 2 ways
Change the bottom 10 to a larger number
Move this part of AnimatedPositioned to Top of the Stack widget
The Nested Gesture should work probably as you expected.
First of All you are using multiple Scaffold in a single page which is not recommended.
And remove the unwanted widgets from your tree which will help you to debug a way more better level. And Next you can try with passing a Callback function from parent to child which can eventually solve your problem
Related
I want when I click on the + Button it shows the next 3 containers that in the listVeiw it is horizontally direction.
Here is my code.
when I tap for the first time it works, but it doesn't work for the others taps
import 'package:flutter/material.dart';
class FindCars extends StatefulWidget {
const FindCars({Key? key}) : super(key: key);
#override
State<NewWayToFindCars> createState() => _NewWayToFindCarsState();
}
class _NewWayToFindCarsState extends State<NewWayToFindCars> {
var pricesListNumber = 10;
int counter = 1;
List months = [
'يناير',
'فبراير',
'مارس',
'ابريل',
'مايو',
'يونيو',
'يوليو',
'اغسطس',
'سبتمبر',
'اكتوبر',
'نوفمبر',
'ديسمبر'
];
var currentMonth = new DateTime.now().month;
var currentDay = new DateTime.now().day;
late ScrollController _scrollController;
#override
void initState() {
_scrollController = ScrollController();
super.initState();
}
#override
Widget build(BuildContext context) {
print(months[currentMonth - 1]);
print(currentDay);
print(DateTime.now());
return Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Directionality(
textDirection: TextDirection.rtl,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(
'${months[currentMonth - 1]} 2022',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.black,
fontFamily: 'cairo',
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
InkWell(
onTap: () {
_scrollController.animateTo(-200,
duration: const Duration(milliseconds: 500),
curve: Curves.easeInOut);
},
child: Container(
child: Icon(Icons.remove, size: 22),
width: 50,
height: 50,
decoration: BoxDecoration(
color: Color(0xFFDCEDC8).withOpacity(0.5),
border: Border.all(
color: Color(0xFFDDE7DD).withOpacity(0.5),
width: 2.5,
),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10),
bottomLeft: Radius.circular(10),
),
),
),
),
InkWell(
onTap: () {
_scrollController.animateTo(200,
duration: const Duration(milliseconds: 500),
curve: Curves.easeInOut);
},
child: Container(
child: Center(child: Icon(Icons.add_sharp, size: 22)),
width: 50,
height: 50,
decoration: BoxDecoration(
color: Color(0xFFDCEDC8).withOpacity(0.25),
border: Border.all(
color: Color(0xFFDDE7DD).withOpacity(0.5),
width: 2.5,
),
borderRadius: BorderRadius.only(
topRight: Radius.circular(10),
bottomRight: Radius.circular(10),
),
),
),
),
],
),
Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height * 0.1,
child: ListView(
controller: _scrollController, // scroll contoller
scrollDirection: Axis.horizontal,
children: new List.generate(
pricesListNumber,
(index) => Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
child: Center(child: Text('${currentDay++}')),
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 5,
blurRadius: 7,
offset: Offset(0, 3), // changes position of shadow
),
],
color: Color(0xFFDCEDC8).withOpacity(0.5),
border: Border.all(
color: Color(0xFFDDE7DD).withOpacity(0.5),
width: 2.5,
),
borderRadius: BorderRadius.circular(10),
),
height: 50,
width: MediaQuery.of(context).size.width * 0.25,
),
),
),
),
),
],
),
),
);
}
}
Here is my code for the UI, and now it is only works in the first click put it does not work until the end.
Can you please help me with that?
Attach a ScrollController to your scrollable widget and then use scrollController.animateTo(//offset) to reach where you want.
Do check the animateTo method on this page.
EDIT:
sample code:
ScrollController scrollController = ScrollController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter'),
centerTitle: true,
),
body: Column(
children: [
ElevatedButton(
onPressed: () {
scrollController.animateTo(0,
duration: Duration(seconds: 1), curve: Curves.easeIn);
},
child: Text("go top")),
Expanded(
flex: 1,
child: ListView.builder(
controller: scrollController,
itemCount: 100,
itemBuilder: (context, index) {
return Text('This is it.');
},
),
),
],
),
);
}
Try it in your IDE.
EDIT:
Here is the problem in your code, you need to decrease/increase the current offset of the scroll controller by subtracting/adding 200 from the scrollController.position. You are getting it moved for the first time because at that time offset is not at 200 and for the second time it is there at 200. That is why it is not moving which is obviously no error.
Just use a scrollController, attach it to your ListView builder,
then on your Button's onPress/onTap method, call _scrolController.animateTo(someOffset)
Copy the code below and run into your project. I have customized it based on your needs.
import 'package:flutter/material.dart';
class TestView extends StatefulWidget {
const TestView({Key? key}) : super(key: key);
#override
State<TestView> createState() => _TestViewState();
}
class _TestViewState extends State<TestView> {
late ScrollController _scrollController;
#override
void initState() {
_scrollController = ScrollController();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ElevatedButton(
onPressed: () {
_scrollController.animateTo(-500,
duration: const Duration(milliseconds: 500),
curve: Curves.easeInOut);
},
child: const Text("-")),
ElevatedButton(
onPressed: () {
_scrollController.animateTo(500,
duration: const Duration(milliseconds: 500),
curve: Curves.easeInOut);
},
child: const Text("+"),
),
],
),
SizedBox(
height: 200,
child: ListView(
controller: _scrollController,
scrollDirection: Axis.horizontal,
children: List.generate(20, (index) {
return Container(
color: Colors.amber,
height: 100,
width: 100,
margin: const EdgeInsets.only(right: 10),
child: Center(child: Text("$index")),
);
}),
),
)
],
),
);
}
}
Image looks like this
I have this widget that acts as a tab bar but was not create with a Tab bar. I want that widget to behave like a collapsing toolbar. Can anyone please help me out? This is the code
This is the code for the animated container which I want to behave like a collapsing toolbar...
Here is the code:
class Watching extends StatefulWidget {
final set_state;
const Watching(this.set_state, {Key? key}) : super(key: key);
#override
_WatchState createState() => _WatchState();
}
class _WatchState extends State<Watching> with TickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> animation, animation2;
final double startingHeight = 20.0;
List pages = [];
int index = 0;
GlobalKey _bottomNavigationKey = GlobalKey();
List titles = [feed, trending, explore];
#override
void initState() {
super.initState();
pages = [
MainPage(
set_state: widget.set_state,
),
TrendingPage(set_state: widget.set_state),
ExplorePage()
];
_controller =
AnimationController(vsync: this, duration: Duration(seconds: 5));
animation = Tween<double>(begin: 125, end: 150).animate(_controller);
animation2 = Tween<double>(begin: 125, end: 150).animate(_controller);
_controller.forward(from: 0.0);
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
backgroundColor: Colors.white,
appBar: PreferredSize(
preferredSize: Size(MediaQuery.of(context).size.width, twoFiftyDp),
child: Container(
color: Colors.teal,
child: Stack(
children: [
AnimatedContainer(
duration: Duration(milliseconds: 400),
width: animation.value,
height: animation.value <= 150 ? 150 : animation.value,
decoration: BoxDecoration(
color: Colors.teal,
),
),
Align(
alignment: Alignment.bottomRight,
child: RotationTransition(
turns: AlwaysStoppedAnimation(0 / 360),
child: ClipPath(
clipper: LeftRoundedClipper(flip: true),
child: AnimatedContainer(
duration: Duration(milliseconds: 400),
width: animation2.value - 10,
height: animation2.value *
MediaQuery.of(context)
.size
.height, //<= 150 ? 200 :animation.value,
decoration: BoxDecoration(
color: Colors.teal,
gradient: LinearGradient(
colors: [
Colors.lightGreen.withGreen(10),
Colors.greenAccent,
Colors.greenAccent
],
)),
),
),
),
),
Align(
alignment: Alignment.bottomCenter,
child: CurvedNavigationBar(
key: _bottomNavigationKey,
height: 65,
color: Colors.white,
buttonBackgroundColor: Colors.transparent,
backgroundColor: Colors.transparent,
animationCurve: Curves.easeInOut,
animationDuration: Duration(milliseconds: 600),
index: 0,
onTap: (value) {
switch (value) {
case 0:
/* animation = Tween<double>(begin: 125, end: 0)
.animate(_controller);*/
animation2 = Tween<double>(begin: 125, end: 500)
.animate(_controller);
break;
case 1:
animation2 = Tween<double>(begin: 125, end: 700)
.animate(_controller);
/* animation = Tween<double>(begin: -10, end: 50)
.animate(_controller);*/
break;
case 2:
animation = Tween<double>(begin: 125, end: 500)
.animate(_controller);
animation2 = Tween<double>(begin: 150, end: 200)
.animate(_controller);
break;
}
setState(() {
index = value;
});
},
items: [
Text(
Main,
style: index == 0
? TextStyle(
color: Colors.white, fontWeight: FontWeight.bold)
: TextStyle(color: Colors.black54),
),
Text(
trending,
style: index == 1
? TextStyle(
color: Colors.white, fontWeight: FontWeight.bold)
: TextStyle(color: Colors.black54),
),
Text(
explore,
style: index == 2
? TextStyle(
color: Colors.white, fontWeight: FontWeight.bold)
: TextStyle(color: Colors.black54),
),
],
),
),
Align(
alignment: Alignment.bottomLeft,
child: Padding(
padding:
const EdgeInsets.only(bottom: sixtyDp, left: tenDp),
child: ListTile(
title: Text(
titles[index],
style: TextStyle(
fontSize: fiftyDp,
fontWeight: FontWeight.bold,
color: Colors.white),
)),
)),
Align(
alignment: Alignment.topLeft,
child: Padding(
padding: const EdgeInsets.only(top: fiftyDp, left: twentyDp),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
index == 0
? ShowIcon(
iconName: 'assets/icons/User.png',
onIconTap: () {},
)
: SizedBox(),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 25),
child: Row(
children: [
Padding(
padding: const EdgeInsets.only(right: fourteenDp),
child: ShowIcon(
iconName: 'assets/icons/MagnifyingGlass.png',
onIconTap: () {},
),
),
Padding(
padding: const EdgeInsets.only(right: fourteenDp),
child: ShowIcon(
iconName: 'assets/icons/BellRinging.png',
onIconTap: () {},
),
),
ShowIcon(
iconName: 'assets/icons/PaperPlane.png',
onIconTap: () {},
),
],
),
)
// Spacer(),
],
),
),
)
],
),
),
),
// body: pages[index],
body: DefaultTabController(
length: pages.length, child: NestedScrollView(headerSliverBuilder: (context, innerBoxIsScrolled) {
return <Widget>[
SliverList(delegate: SliverChildListDelegate([]))
];
}, body: pages[index]),
),
),
);
}
}
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 have a UI layout in my head, essentially the same as the new menu/account chooser as in the Google Maps app. It is a modal dialog that pops up on the press of the profile button and is scrollable. When scrolled, the dialog animates into a full screen dialog, and vice-versa.
I am aiming to use a Material Design compatible way of doing this, and it currently only needs to work on Android.
Some minor changes would be made, but my question is: Is that possible in Flutter? Thanks.
Well, to implement this kind of animation on dialog might be bit complex.
You can use animations plugins for this.
For more details you can see this video.
Chances are that you might not manage to create animations with dialog, so in that case you can use stack and show custom dialog to user.
Author here,
I have created this menu, and the code snippet is below:
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import - ANOTHER PACKAGE -
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';
import 'package:theme_provider/theme_provider.dart';
import '../../services/authManager.dart';
import '../../services/models.dart';
import '../home.dart';
class MainMenu extends StatefulWidget {
const MainMenu({
Key key,
}) : super(key: key);
#override
_MainMenuState createState() => _MainMenuState();
}
class _MainMenuState extends State<MainMenu>
with SingleTickerProviderStateMixin {
#override
Widget build(BuildContext context) {
final mainProps = Provider.of<MainProps>(context);
final authVals = Provider.of<AuthVals>(context);
final userData = Provider.of<CustomUser>(context);
final userDataPrivate = Provider.of<CustomUserPrivate>(context);
final userDataReadOnly = Provider.of<CustomUserReadOnly>(context);
return IgnorePointer(
ignoring: !mainProps.menuOpen,
child: AnimatedOpacity(
opacity: mainProps.menuOpen ? 1 : 0,
duration: Duration(milliseconds: 150),
child: Container(
color: Colors.black.withOpacity(0.75),
child: Stack(
children: [
SafeArea(
child: Container(
width: MediaQuery.of(context).size.width,
margin: EdgeInsets.only(
top: mainProps.menuPadTop + 10,
left: mainProps.menuPadLeft,
right: mainProps.menuPadRight,
),
child: Container(
width: 100.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(mainProps.menuCorners)),
color: Theme.of(context).backgroundColor,
),
padding: EdgeInsets.only(
top: 10,
left: 10,
right: 10,
),
child: NotificationListener<ScrollNotification>(
onNotification: (scrollNotification) {
if (scrollNotification is ScrollEndNotification) {
if (((mainProps.menuScrollCtrl.position.pixels > 100
? 100
: mainProps
.menuScrollCtrl.position.pixels) -
100)
.abs() >=
25) {
WidgetsBinding.instance.addPostFrameCallback((_) {
mainProps.menuScrollCtrl.animateTo(0,
duration: Duration(milliseconds: 150),
curve: Curves.easeInOut);
});
} else if (mainProps.menuScrollCtrl.position.pixels
.abs() >
75 &&
mainProps.menuScrollCtrl.position.pixels.abs() <
100) {
WidgetsBinding.instance.addPostFrameCallback((_) {
mainProps.menuScrollCtrl.animateTo(100,
duration: Duration(milliseconds: 150),
curve: Curves.easeInOut);
});
}
}
return true;
},
child: Container(
height: 155,
child: Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Column(
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.baseline,
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
children: [
(userData.public != 'Local Account'
? CircleAvatar(
radius: 20,
backgroundImage: NetworkImage(
authVals.authUser.photoURL,
),
)
: CircleAvatar(
radius: 20,
child: SvgPicture.network(
userData.photoURL,
color: Theme.of(context)
.primaryColor ==
Color(0xffff9800)
? Colors.black
: Colors.white),
backgroundColor:
Theme.of(context).backgroundColor,
)),
Column(
children: [
Text(
userData.publicExt,
style: TextStyle(
fontWeight: FontWeight.bold),
),
Text(userDataPrivate?.realName ??
'Please Wait...'),
Text(authVals.authUser.email == ''
? 'Anonymous'
: authVals.authUser.email),
Text(userDataReadOnly != null
? userDataReadOnly.joined
.toDate()
.toLocal()
.toString()
: 'Please Wait...'),
],
),
],
),
Spacer(),
Row(
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
children: [
Visibility(
visible: !mainProps.signingOut,
child: OutlineButton(
onPressed: null,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.account_circle),
SizedBox(width: 15),
Text('View Profile'),
],
),
),
),
OutlineButton(
onPressed: () async {
if (!mainProps.signingOut) {
mainProps.signingOut = true;
} else {
await AuthService().signOut();
Navigator.of(context).popAndPushNamed(
-SCREEN-);
}
},
child: AnimatedContainer(
duration: Duration(milliseconds: 250),
constraints: mainProps.signingOut
? BoxConstraints(
maxWidth: MediaQuery.of(context)
.size
.width -
82)
: BoxConstraints(maxWidth: 93),
child: Row(
mainAxisSize: !mainProps.signingOut
? MainAxisSize.min
: MainAxisSize.max,
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Icon(Icons.logout,
color: mainProps.signingOut
? Colors.red
: null),
SizedBox(width: 15),
LimitedBox(
child: Text(
'Sign Out',
style: TextStyle(
color: mainProps.signingOut
? Colors.red
: null),
),
),
],
),
),
),
],
),
Spacer(),
],
),
),
),
),
),
),
),
SafeArea(
child: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
margin: EdgeInsets.only(
top: mainProps.menuPadTop +
(mainProps.menuScrollCtrl.hasClients
? (((mainProps.compassExpanded ? 195 : 195) / 100) *
(100 -
(mainProps.menuScrollCtrl.position.pixels >
100
? 100
: mainProps
.menuScrollCtrl.position.pixels)))
: -mainProps.menuPadTop),
left: mainProps.menuPadLeft,
right: mainProps.menuPadRight,
),
child: Container(
width: 100.0,
height: 100.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(mainProps.menuCorners),
topRight: Radius.circular(mainProps.menuCorners),
),
color: Theme.of(context).backgroundColor,
),
padding: EdgeInsets.only(
top: 10,
left: 10,
right: 10,
),
child: NotificationListener<ScrollNotification>(
onNotification: (scrollNotification) {
if (scrollNotification is ScrollEndNotification) {
if (((mainProps.menuScrollCtrl.position.pixels > 100
? 100
: mainProps
.menuScrollCtrl.position.pixels) -
100)
.abs() >=
25) {
WidgetsBinding.instance.addPostFrameCallback((_) {
mainProps.menuScrollCtrl.animateTo(0,
duration: Duration(milliseconds: 150),
curve: Curves.easeInOut);
});
} else if (mainProps.menuScrollCtrl.position.pixels
.abs() >
75 &&
mainProps.menuScrollCtrl.position.pixels.abs() <
100) {
WidgetsBinding.instance.addPostFrameCallback((_) {
mainProps.menuScrollCtrl.animateTo(100,
duration: Duration(milliseconds: 150),
curve: Curves.easeInOut);
});
}
}
},
child: SingleChildScrollView(
child: const Text(
'hello\n\n\n\na\n\n\n\no\n\n\n\na\n\n\n\no\n\n\n\na\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\n'),
controller: mainProps.menuScrollCtrl,
),
),
),
),
),
SafeArea(
child: Container(
width: MediaQuery.of(context).size.width,
height: mainProps.compassExpanded ? 60 : 52,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(mainProps.menuCorners * 4),
),
),
margin: EdgeInsets.only(
top: mainProps.topMenuPadTop,
left: mainProps.menuPadLeft,
right: mainProps.menuPadRight,
),
child: Material(
borderRadius: BorderRadius.all(
Radius.circular(mainProps.menuCorners * 4),
),
elevation: 4,
color: Theme.of(context).backgroundColor,
child: Row(
children: [
Padding(
padding: const EdgeInsets.only(left: 10.0),
child: IconButton(
icon: Icon(Icons.close),
onPressed: () {
mainProps.menuOpen = false;
mainProps.signingOut = false;
mainProps.menuScrollCtrl.jumpTo(0);
},
),
),
Expanded(
child: Text(
-TEXT-,
style: GoogleFonts.ubuntu(
textStyle: TextStyle(fontSize: 17),
fontWeight: FontWeight.w600,
),
textAlign: TextAlign.center,
),
),
Padding(
padding: const EdgeInsets.only(right: 10.0),
child: Stack(
children: [
Opacity(
opacity: mainProps.menuScrollCtrl.hasClients
? ((mainProps.menuScrollCtrl.position
.pixels >
100
? 0
: 100 -
mainProps.menuScrollCtrl
.position.pixels) /
100)
: 1,
child: IgnorePointer(
ignoring: mainProps.menuScrollCtrl.hasClients
? (mainProps.menuScrollCtrl.position
.pixels >=
100
? -1
: 100 -
mainProps.menuScrollCtrl
.position.pixels) <
0
: false,
child: IconButton(
icon: Icon(Icons.palette),
onPressed: () => showDialog(
context: context,
builder: (_) => ThemeConsumer(
child: ThemeDialog(
title: Row(
children: [
Icon(Icons.palette),
SizedBox(width: 15),
Text('Choose Theme'),
],
),
hasDescription: false,
),
),
),
),
),
),
Opacity(
opacity: 1.0 -
(mainProps.menuScrollCtrl.hasClients
? ((mainProps.menuScrollCtrl.position
.pixels >
100
? 0
: 100 -
mainProps.menuScrollCtrl
.position.pixels) /
100)
: 1),
child: IgnorePointer(
ignoring:
!(mainProps.menuScrollCtrl.hasClients
? (mainProps.menuScrollCtrl.position
.pixels >=
100
? -1
: 100 -
mainProps.menuScrollCtrl
.position.pixels) <
0
: false),
child: IconButton(
icon: Icon(Icons.keyboard_arrow_down),
onPressed: () =>
mainProps.menuScrollCtrl.animateTo(
0,
duration: Duration(milliseconds: 250),
curve: Curves.easeInOut,
),
),
),
),
],
),
),
],
),
),
),
),
],
),
),
),
);
}
}
mainProps is just my state management solution, using Provider. Doing this using setState would be a nightmare and would probably bulk the code considerably. I think the rest of the code is self-explanatory. It has nice animations and some cool features.
You can see it working here: https://photos.app.goo.gl/aH6otb6CkbYbwpsr7
I'm considering creating a package with similar code to the code above, and sharing it on pub.dev. If you think that would help you, please let me know in the comments of this answer.
I am creating a Journal mobile application which would work as a medium to view magazines and daily news updates. This is my first flutter project and I am totally new to flutter. So kindly excuse me if I had said something wrong about something or didnt provide enough information.
I used a code from github for the main page of my application and made few changes to accommodate my needs. Now in my code, the home page consists of a side menu bar and this bar consists of 4 buttons, namely Home, My Profile, Premium and FAQ. The GlobalKeys for the side menu bar is called using a list by the name _keys which is of the type GlobalKey. I tried changing the data type of the list _keys to Widget and then called the corresponding Widgets of the classes. But then two errors popped out.
The getter 'currentContext' isn't defined for the class 'Widget'.
The argument type 'Widget' can't be assigned to the parameter type 'GlobalKey<State>'.
Now I would like the list _keys to be of the type Widget in order for me to call upon it's corresponding widgets of Home, My Profile, Premium and FAQ from each of it's classes in order for me to view the corresponding pages. Or if it is not possible, I would love to know an alternative for it to start working.
Following is the code of my application.
import 'dart:math' as math;
import 'package:flutter/scheduler.dart';
import 'package:google_signin_example/google%20sign%20in/logged_in_widget.dart';
import 'package:google_signin_example/main app/lib/ui_3/TravelBean.dart';
import 'package:google_signin_example/main app/lib/ui_3/magazine/screens/home_screen.dart';
import 'package:google_signin_example/main%20app/lib/ui_3/FAQ/faq.dart';
import 'package:google_signin_example/main%20app/lib/ui_3/Newspaper%20and%20Kiddos/lib_kiddos/main.dart';
import 'package:google_signin_example/main%20app/lib/ui_3/Newspaper%20and%20Kiddos/lib_news/main.dart';
import 'package:google_signin_example/main%20app/lib/ui_3/premium/premium.dart';
import 'package:google_signin_example/widget/sign_up_widget.dart';
import 'detail_page.dart';
class HomePage1 extends StatefulWidget {
#override
_HomePage1State createState() => _HomePage1State();
}
class _HomePage1State extends State<HomePage1> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Container(
child: Row(
children: <Widget>[
LeftWidget(),
Expanded(
child: RightWidget(),
)
],
),
),
);
}
}
class LeftWidget extends StatefulWidget {
#override
_LeftWidgetState createState() => _LeftWidgetState();
}
class _LeftWidgetState extends State<LeftWidget> with TickerProviderStateMixin {
List<String> _list = ["Home", "My profile", "Premium", "FAQ"];
List <Widget> _keys = [
HomePage1(), //These are the widgets from different classes.
LoggedInWidget(),
premium(),
faq(),
/*GlobalKey(), //This was available before I made the changes.
GlobalKey(),
GlobalKey(),
GlobalKey()*/
];
int checkIndex = 0;
Offset checkedPositionOffset = Offset(0, 0);
Offset lastCheckOffset = Offset(0, 0);
Offset animationOffset = Offset(0, 0);
Animation _animation;
AnimationController _animationController;
#override
void initState() {
checkIndex = _list.length - 1;
super.initState();
SchedulerBinding.instance.endOfFrame.then((value) {
calcuteCheckOffset();
addAnimation();
});
}
void calcuteCheckOffset() {
lastCheckOffset = checkedPositionOffset;
RenderBox renderBox = _keys[checkIndex].currentContext.findRenderObject(); //This is where the first error occurs.
Offset widgetOffset = renderBox.localToGlobal(Offset(0, 0));
Size widgetSise = renderBox.size;
checkedPositionOffset = Offset(widgetOffset.dx + widgetSise.width,
widgetOffset.dy + widgetSise.height);
}
#override
Widget build(BuildContext context) {
return Container(
child: Stack(
children: <Widget>[
Container(
width: 50,
decoration: BoxDecoration(
color: Color(0xff000000),
borderRadius: BorderRadius.circular(30),
),
child: Column(
children: _buildList(),
),
),
Positioned(
top: animationOffset.dy,
left: animationOffset.dx,
child: CustomPaint(
painter: CheckPointPainter(Offset(10, 0)),
),
)
],
),
);
}
List<Widget> _buildList() {
List<Widget> _widget_list = [];
_widget_list.add(Padding(
padding: EdgeInsets.only(
top: 50,
),
child: Icon(
Icons.settings,
color: Colors.white,
size: 30,
),
));
for (int i = 0; i < _list.length; i++) {
_widget_list.add(Expanded(
child: GestureDetector(
onTap: () {
indexChecked(i);
},
child: VerticalText(
_list[i],
_keys[i], //This is where the second error occurs.
checkIndex == i &&
(_animationController != null &&
_animationController.isCompleted))),
));
}
_widget_list.add(Padding(
padding: EdgeInsets.only(
top: 50,
bottom: 50,
),
child: Image(image: AssetImage('assets/images/Voix.png')),
));
return _widget_list;
}
void indexChecked(int i) {
if (checkIndex == i) return;
setState(() {
checkIndex = i;
calcuteCheckOffset();
addAnimation();
});
}
void addAnimation() {
_animationController =
AnimationController(duration: Duration(milliseconds: 300), vsync: this)
..addListener(() {
setState(() {
animationOffset =
Offset(checkedPositionOffset.dx, _animation.value);
});
});
_animation = Tween(begin: lastCheckOffset.dy, end: checkedPositionOffset.dy)
.animate(CurvedAnimation(
parent: _animationController, curve: Curves.easeInOutBack));
_animationController.forward();
}
}
class CheckPointPainter extends CustomPainter {
double pointRadius = 5;
double radius = 30;
Offset offset;
CheckPointPainter(this.offset);
#override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()..style = PaintingStyle.fill;
double startAngle = -math.pi / 2;
double sweepAngle = math.pi;
paint.color = Color(0xff000000);
canvas.drawArc(
Rect.fromCircle(center: Offset(offset.dx, offset.dy), radius: radius),
startAngle,
sweepAngle,
false,
paint);
paint.color = Color(0xffffffff);
canvas.drawCircle(
Offset(offset.dx - pointRadius / 2, offset.dy - pointRadius / 2),
pointRadius,
paint);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
class VerticalText extends StatelessWidget {
String name;
bool checked;
GlobalKey globalKey;
VerticalText(this.name, this.globalKey, this.checked);
#override
Widget build(BuildContext context) {
return RotatedBox(
key: globalKey,
quarterTurns: 3,
child: Text(
name,
style: TextStyle(
color: checked ? Color(0xffffffff) : Colors.grey,
fontSize: 16,
),
),
);
}
}
class RightWidget extends StatefulWidget {
#override
_RightWidgetState createState() => _RightWidgetState();
}
class _RightWidgetState extends State<RightWidget>
with TickerProviderStateMixin {
TabController _tabController;
#override
void initState() {
super.initState();
_tabController = TabController(vsync: this, length: 5);
}
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.only(
left: 15,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 50, left: 20),
child: Text(
"Voix Home",
style: TextStyle(
color: Colors.black,
fontSize: 25,
),
),
),
Padding(
padding: const EdgeInsets.only(top: 15, left: 10),
child: SizedBox(
height: 30,
child: TabBar(
isScrollable: true,
unselectedLabelColor: Colors.black,
labelColor: Color(0xffffffff),
controller: _tabController,
indicator: BoxDecoration(
color: Color(0xff9e9e9e),
borderRadius: BorderRadius.only(
topRight: Radius.circular(20),
bottomLeft: Radius.circular(20),
),
),
tabs: <Widget>[
Tab(
text: "Flash",
),
Tab(
text: "Magazine",
),
Tab(
text: "Newspaper",
),
Tab(
text: "Kiddos",
),
Tab(
text: "Editorial",
),
],
),
),
),
Expanded(
child: TabBarView(
controller: _tabController,
children: <Widget>[
TravelWidget(),
HomeScreen(),
News(),
Kiddos(),
RightBody(),
// RightBody(),
],
),
)
],
),
);
}
}
class RightBody extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.only(
left: 15,
),
color: Colors.white,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: EdgeInsets.only(
top: 20,
),
child: Text(
"Flash!",
style: TextStyle(
color: Colors.black,
fontSize: 20,
),
),
),
Expanded(
child: ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
Container(
width: 220,
margin: EdgeInsets.symmetric(
horizontal: 10,
vertical: 10,
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(40),
image: new DecorationImage(
image: new AssetImage('assets/images/bottom1.jpg'),
fit: BoxFit.cover,
),
boxShadow: [
BoxShadow(
spreadRadius: 5,
blurRadius: 5,
offset: Offset(1, 2),
color: Color(0x33757575),
),
],
),
),
Container(
width: 220,
margin: EdgeInsets.symmetric(
horizontal: 10,
vertical: 10,
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(40),
boxShadow: [
BoxShadow(
spreadRadius: 5,
blurRadius: 5,
offset: Offset(1, 2),
color: Color(0x33757575),
),
],
),
),
],
),
),
],
),
);
}
}
class TravelWidget extends StatelessWidget {
List<TravelBean> _list = TravelBean.generateTravelBean();
#override
Widget build(BuildContext context) {
return PageView.builder(
controller: PageController(viewportFraction: 0.9),
itemBuilder: (context, index) {
var bean = _list[index];
return GestureDetector(
onTap: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return DetailPage(bean);
}));
},
child: Hero(
tag: bean.url,
child: Stack(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(bottom: 30, right: 10),
child: ClipRRect(
borderRadius: BorderRadius.circular(5),
child: Image.asset(
bean.url,
width: MediaQuery.of(context).size.width,
fit: BoxFit.cover,
),
),
),
Positioned(
bottom: 80,
left: 15,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Material(
color: Colors.transparent,
child: Text(
bean.location,
style: TextStyle(
color: Colors.black54,
fontSize: 15,
),
),
),
Material(
color: Colors.transparent,
child: Text(
bean.name,
style: TextStyle(
color: Colors.black,
fontSize: 20,
),
),
),
],
),
),
Positioned(
bottom: 0,
right: 30,
child: Container(
width: 60,
height: 60,
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(30),
),
child: Icon(
Icons.arrow_forward,
color: Colors.white,
size: 30,
),
),
)
],
),
),
);
},
itemCount: _list.length,
);
}
}
At the beginning, when I leave the list _keys to be of the type GlobalKey and don't comment out the following 4 GlobalKeys I get the output but the side menu bar won't work.
This is my application with GlobalKeys in place of those Widgets
I want those corresponding pages to display when clicked on. But that render object just switches between the options and the same page is displayed.
So kindly help me out.
PS : As said earlier I'm new to flutter, so kindly don't mistake me if I had something wrong.
I suggest you check about flutter state management, especially Mobx with Provider, it will be kind easier for you.