Dart/Flutter not changing page with Inkwell and Gesture detector - flutter

I am trying to use Inkwell or Gesture detector to navigate to page 2, but it is saying "Undefined name 'context'". Hope someone can help! :))
It is a google maps stack container and other group of containers on the top. When click on the containers on top, it redirects to the 2page.
Main.dart:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:geolocator/geolocator.dart';
import 'woocommerce/woocommerce_api.dart';
void main() {
runApp(Page1());
}
class Page1 extends StatelessWidget {
//********************************** GOOGLE MAPS *****************************************
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: MapView(),
);
}
}
class MapView extends StatefulWidget {
#override
_MapViewState createState() => _MapViewState();
}
class _MapViewState extends State<MapView> {
CameraPosition _initialLocation = CameraPosition(target: LatLng(0.0, 0.0));
GoogleMapController mapController;
final Geolocator _geolocator = Geolocator();
Position _currentPosition;
#override
void initState() {
super.initState();
_getCurrentLocation();
}
_getCurrentLocation() async {
await _geolocator
.getCurrentPosition(desiredAccuracy: LocationAccuracy.high)
.then((Position position) async {
setState(() {
// Store the position in the variable
_currentPosition = position;
print('CURRENT POS: $_currentPosition');
// For moving the camera to current location
mapController.animateCamera(
CameraUpdate.newCameraPosition(
CameraPosition(
target: LatLng(position.latitude, position.longitude),
zoom: 13.0,
),
),
);
});
}).catchError((e) {
print(e);
});
}
#override
Widget build(BuildContext context) {
// Determining the screen width & height
var height = MediaQuery.of(context).size.height;
var width = MediaQuery.of(context).size.width;
//********************************** GOOGLE MAPS SCREEN **********************************
return Container(
height: height,
width: width,
child: Scaffold(
body: Stack(
children: <Widget>[
GoogleMap(
initialCameraPosition: _initialLocation,
myLocationEnabled: true,
myLocationButtonEnabled: false,
mapType: MapType.normal,
zoomGesturesEnabled: true,
zoomControlsEnabled: false,
onMapCreated: (GoogleMapController controller) {
mapController = controller;
},
),
ClipOval(
child: Material(
color: Color(0xffeb5c68), // button color
child: InkWell(
splashColor: Color(0xffda1b2b), // inkwell color
child: SizedBox(
width: 56,
height: 56,
child: Icon(Icons.my_location),
),
onTap: () {
mapController.animateCamera(
CameraUpdate.newCameraPosition(
CameraPosition(
target: LatLng(
_currentPosition.latitude,
_currentPosition.longitude,
),
zoom: 13.0,
),
),
);
},
),
),
),
//********************************** ORDERS **********************************
Container(
padding: EdgeInsets.only(top: 550, bottom: 50),
child: ListView(
padding: EdgeInsets.only(left: 20),
children: getTechniciansInArea(),
scrollDirection: Axis.horizontal,
),
),
],
)
),
);
}
List<Technician> getTechies() {
List<Technician> techies = [];
//For esting...
// for (int i = 0; i < 10; i++) {
//Technician myTechy = Technician(name:'Apotheken', phoneNum: 'Address store');
Technician myTechy = Technician("Store name test", "Address store ", "Address costumer", 529.3, 4, "Available", "fdfd");
techies.add(myTechy);
//}
return techies;
}
List<Widget> getTechniciansInArea() {
List<Technician> techies2 = getTechies();
List<Widget> cards = [];
for (Technician techy in techies2) {
cards.add(technicianCard(techy));
}
return cards;
}
}
Widget technicianCard(Technician technician) {
return
InkWell( // when click...
child:
Container(
padding: EdgeInsets.all(10),
margin: EdgeInsets.only(right: 20),
width: 180,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(20)),
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.grey,
blurRadius: 0.5,
),],
),
child:
Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(height: 5,),
Text(technician.name, style: TextStyle(fontSize: 19,fontWeight: FontWeight.bold), textAlign: TextAlign.center),
SizedBox(height: 10,),
Text("AS: " + technician.phoneNum, style: TextStyle(fontSize: 15)),
SizedBox(height: 10,),
Text("AC: " + technician.address, style: TextStyle(fontSize: 15)),
SizedBox(height: 30,),
],
),
GestureDetector(
child:
Container(
alignment: Alignment.bottomCenter,
width: 120.0,
height: 40.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(10)),
color: Color(0xffeb5c68),
),
child:
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("REQUEST", textAlign: TextAlign.center,style: TextStyle(color: Colors.white),),
]
)
),
onLongPress: (){
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Page2()),
);
},
)
]
)
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Page2()),
);
}
);
}
//********************************** PAGE 2 **********************************
class Page2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Your orders"),
),
);
}
Woocommerce_api.dart:
class Technician {
String name;
String phoneNum;
String address;
double rate;
String status;
int rating;
String occupation;
Technician(this.name, this.phoneNum, this.address, this.rate, this.rating, this.status, this.occupation);
//Technician({this.name, this.phoneNum, this.address, this.rate, this.rating, this.status, this.occupation});
}

You need to send BuildContexti to function. does not see the correct context. likewise, you need to add it to the top. Set the context no matter where you called.
Widget technicianCard(Technician technician, BuildContext context)//add here
{
.....
...
..
}

Related

Audio composing dashboard with flutter

I m trying to create the following view on my app, other area are done but now comes to the core feature of the app, which allows people to record the audio and stack other audio on top of the one that has been recorded, before going on the hard parts of recording and margin or trim the audios, I am stuck on the view, plz anyone who can shade a light on this will be appreciated. spare the bottom navigation bar, that one has no issue, only the timeline board.
here the view that I just prototyped.
Here some code that I've tried to play with but failed.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class Studio extends StatefulWidget {
const Studio({Key? key}) : super(key: key);
#override
_Studio createState() => _Studio();
}
class _Studio extends State<Studio> with SingleTickerProviderStateMixin {
late AnimationController _controller;
double _time = 0.0, _scale = 1.0;
int _minutes = 0;
int _seconds = 0;
#override
void initState() {
super.initState();
_controller =
AnimationController(vsync: this, duration: Duration(seconds: 60));
_controller.addListener(() {
setState(() {
_time = _controller.value;
_minutes = (_time * 60).floor();
_seconds = ((_time * 60) % 1 * 60).floor();
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Timeline'),
),
body: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: 12,
itemBuilder: (context, index) {
return Container(
width: 50,
height: 50,
margin: EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(8),
),
child: Center(
child: Text('$index'),
),
);
},
),
),
Container(
padding: EdgeInsets.all(8),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('$_minutes'),
Text(':'),
Text('$_seconds'),
],
),
),
ElevatedButton(
onPressed: () {
if (_controller.isAnimating) {
_controller.stop();
} else {
_controller.forward();
}
},
child: Text(_controller.isAnimating ? 'Stop' : 'Start'),
),
],
),
);
}
void _onScaleStart(ScaleStartDetails details) {
print(details);
setState(() {
//_scale = details.focalPoint;
});
}
void _onScaleUpdate(ScaleUpdateDetails details) {
setState(() {
_scale = details.scale;
});
}
Widget _buildTimeline() {
return Container(
height: 40,
child: Row(
children: <Widget>[
_buildTimelineMinute(0),
_buildTimelineMinute(5),
_buildTimelineMinute(10),
],
),
);
}
Widget _buildTimelineHour(int hour) {
return Container(
width: 10,
color: Colors.green,
child: Center(
child: Text(
"$hour:00",
style: TextStyle(color: Colors.black, fontSize: 12),
),
),
);
}
Widget _buildTimelineMinute(int minute) {
return Container(
width: 10,
color: Colors.green,
child: Center(
child: Text(
"$minute",
style: TextStyle(color: Colors.black, fontSize: 12),
),
),
);
}
}
Thank you

How to change opacity of text and angle of icon while using slider button in flutter

I want that as I move my slider button towards right, the opacity of text decreases and arrow icon rotates exactly oppposite, i.e. it strts rotating and at last last it should point backwards. I want to use opacity and Transform.rotate widgets, but how do I keep updating the value of dx ,so I can divide it with total width of container and use the fraction for calculation.
If there is another way, please do tell me.
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:passenger_flutter_app/utils/colors.dart';
import 'package:passenger_flutter_app/widgets/custom_sliding_button.dart';
class CommonSwipeButton extends StatelessWidget {
final String? buttonText1;
final String buttonText2;
final VoidCallback buttonCallBack2;
final bool isInfo;
final VoidCallback? buttonCallBack1;
final Widget itemWidget;
CommonSwipeButton(
{this.buttonCallBack1,
required this.buttonCallBack2,
this.isInfo = false,
this.buttonText1,
required this.buttonText2,
required this.itemWidget});
#override
Widget build(BuildContext context) {
return Container(
child: Column(
//crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Padding(padding: const EdgeInsets.only(left: 16.0, right: 16.0, bottom: 16.0, top: 16), child: itemWidget),
Padding(
padding:
const EdgeInsets.only(bottom: 16.0, left: 16.0, right: 16.0),
child: Align(
alignment: Alignment.center,
child: SizedBox(
width: MediaQuery.of(context).size.width,
height: 44,
child: CustomSlidingButton(
//text: buttonText2,
),
),
),
)
],
),
);
}
}
/*
class SwipeButton extends StatefulWidget {
final ValueChanged<double>? valueChanged;
final String? text;
final Function? callBack;
SwipeButton({this.valueChanged, this.text, this.callBack});
#override
SwipeButtonState createState() {
return new SwipeButtonState();
}
}
class SwipeButtonState extends State<SwipeButton> {
ValueNotifier<double> valueListener = ValueNotifier(.0);
GlobalKey swipeKey = GlobalKey();
ValueNotifier<double> x=ValueNotifier<double>(0);
ValueNotifier<bool> isVisible = ValueNotifier<bool>(true);
#override
void initState() {
valueListener.addListener(notifyParent);
super.initState();
}
void notifyParent() {
if (widget.valueChanged != null) {
widget.valueChanged!(valueListener.value);
}
}
void getPos(double totalSize) {
RenderBox box = swipeKey.currentContext?.findRenderObject() as RenderBox;
Offset position = box.localToGlobal(Offset.zero); //this is global position
x.value = position.dx;
print(x);
if(x.value>355) {
print("Reached");
isVisible.value=false;
}
}
#override
Widget build(BuildContext context) {
return Container(
color: colorPrimary,
height: 40.0,
padding: EdgeInsets.symmetric(horizontal: 10.0),
child: Stack(
children: [
Center(
child: Padding(
padding: const EdgeInsets.only(left: 10.0),
child: Text(
"${widget.text}",
style: TextStyle(
color: Colors.white,
fontSize: 17,
),
),
),
),
Builder(
builder: (context) {
final handle = GestureDetector(
onHorizontalDragUpdate: (details) {
valueListener.value = (valueListener.value +
details.delta.dx / context.size!.width)
.clamp(.0, 1.0);
getPos(context.size!.width-5);
print(context.size?.width);
},
child: ValueListenableBuilder(
valueListenable: isVisible,
builder: (BuildContext context, bool val, Widget? child) {
return Container(
key: swipeKey,
height: 25.0,
width: 25.0,
color: val ? Colors.white : colorPrimary,
child: Center(
child: ValueListenableBuilder(
valueListenable: x,
builder: (BuildContext context, double d, Widget? child) {
return Transform.rotate(
angle: -pi*(d/350),
child: Icon(
Icons.arrow_forward,
color: Colors.orange,
size: 12,
),
);
},
),
),
);
},
),
);
return AnimatedBuilder(
animation: valueListener,
builder: (context, child) {
return Align(
alignment: Alignment(valueListener.value * 2 - 1, 0),
child: child,
);
},
child: handle,
);
},
),
],
),
);
}
}*/
You can use Slider widget from Flutter framework and update a local variable in the onChange function:
Slider(
value: _currentSliderValue,
max: 100, //or any max value you need
onChanged: (double value) {
setState(() {
_value = value;
});
},
);
And the _value variable you will use in Opacity and Transform widgets.

Flutter replace widget with SlideTransition

I want to slide out my first widget from right and slide in second from left of screen.
I'm trying to use AnimatedSwitcher with SlideTransition
my current code bug is that first widget doesn't slide out and just vanishes
here is my complete code snippet.
Any help would be appriciated
class LoginPage extends StatefulWidget {
LoginPage({Key? key}) : super(key: key);
#override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage>
with SingleTickerProviderStateMixin {
static const int PIN_CODE_LENGTH = 4;
final TextEditingController _mobileController = TextEditingController();
final TextEditingController _pinController = TextEditingController();
final UniqueKey _mobileKey = UniqueKey();
final UniqueKey _pinKey = UniqueKey();
bool _submittable = false;
bool _isLoginStepOne = true;
String _buttonText = Strings.next;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Directionality(
textDirection: TextDirection.rtl,
child: SingleChildScrollView(
child: SizedBox(
height: SizePercentConfig.screenHeight,
child: Column(
children: [
_buildHeader(),
Expanded(
child: _buildForm(),
),
],
),
),
),
),
);
}
Widget _buildHeader() {
return Container(
height: SizePercentConfig.safeBlockVertical * 60,
child: Stack(
children: [
Positioned(
bottom: 0,
right: SizePercentConfig.blockSizeHorizontal * 30,
left: SizePercentConfig.blockSizeHorizontal * 30,
child: Image.asset(
Assets.logo,
fit: BoxFit.fitWidth,
),
),
Container(
height: SizePercentConfig.safeBlockVertical * 50,
child: Stack(
children: [
Positioned(
bottom: 0,
child: Image.asset(
Assets.loginHeader,
width: SizePercentConfig.screenWidth,
fit: BoxFit.fitWidth,
),
),
],
),
),
],
),
);
}
Widget _buildForm() {
return Form(
onChanged: _validate,
child: Padding(
padding: const EdgeInsets.all(Dimens.unitX2),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
AnimatedSwitcher(
duration: const Duration(seconds: 1),
transitionBuilder: (Widget child, Animation<double> animation) {
final inAnimation = Tween<Offset>(
begin: Offset(1.0, 0.0), end: Offset(0.0, 0.0))
.animate(animation);
final outAnimation = Tween<Offset>(
begin: Offset(-1.0, 0.0), end: Offset(0.0, 0.0))
.animate(animation);
print('** child key: ${child.key}');
print('** mobile key: $_mobileKey');
print('** pin key: $_pinKey');
if (child.key == _mobileKey) {
// in animation
print('>>>>>>> first statement');
return ClipRect(
child: SlideTransition(
position: inAnimation,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: child,
),
),
);
} else {
// out animation
print('>>>>>>> second statement');
return ClipRect(
child: SlideTransition(
position: outAnimation,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: child,
),
),
);
}
},
layoutBuilder:
(Widget? currentChild, List<Widget> previousChildren) {
return currentChild!;
},
child: _isLoginStepOne
? AppTextField(
key: _mobileKey,
controller: _mobileController,
hint: Strings.mobileNumber,
textInputType: TextInputType.phone,
)
: _buildPinCode()),
SizedBox(height: Dimens.unitX2),
AppSolidButton(
onPressed: _buttonAction,
text: _buttonText,
width: SizePercentConfig.screenWidth,
enabled: _submittable,
),
SizedBox(height: Dimens.unitX2),
],
),
),
);
}
void _validate() {
if (_isLoginStepOne) {
if (Regex.mobileRegex.hasMatch(_mobileController.value.text) !=
_submittable)
setState(() {
print('--> setState called in _validate');
_submittable = !_submittable;
});
} else {
if ((_pinController.value.text.length == 4) != _submittable)
setState(() {
print('--> setState called in _validate');
_submittable = !_submittable;
});
}
}
void _buttonAction() {
if (_submittable) {
setState(() {
print('--> setState called in _buttonPressed');
_isLoginStepOne = false;
_submittable = false;
_buttonText = Strings.login;
});
} else {}
}
Widget _buildPinCode() {
return Directionality(
textDirection: TextDirection.ltr,
child: PinCodeTextField(
key: _pinKey,
controller: _pinController,
appContext: context,
length: PIN_CODE_LENGTH,
onChanged: (_) {},
enablePinAutofill: true,
enableActiveFill: true,
textStyle: TextStyle(color: Palette.scorpion),
pinTheme: PinTheme(
shape: PinCodeFieldShape.circle,
fieldHeight: SizePercentConfig.safeBlockHorizontal * 20,
fieldWidth: SizePercentConfig.safeBlockHorizontal * 20,
activeFillColor: Palette.concrete,
inactiveFillColor: Palette.concrete,
selectedFillColor: Palette.roseBud,
activeColor: Palette.concrete,
disabledColor: Palette.concrete,
inactiveColor: Palette.concrete,
selectedColor: Palette.roseBud,
),
cursorColor: Palette.transparent,
keyboardType: TextInputType.number,
),
);
}
}
Give your ClipRect widgets unique keys:
If the "new" child is the same widget type and key as the "old" child, but with different parameters, then AnimatedSwitcher will not do a transition between them, since as far as the framework is concerned, they are the same widget and the existing widget can be updated with the new parameters. To force the transition to occur, set a Key on each child widget that you wish to be considered unique (typically a ValueKey on the widget data that distinguishes this child from the others).

Overlay pinched image above everything

I'm trying to overlay an image during max scaling (I'm using the class InteractiveViewer) on top of other objects (also the status bar). Basically like on Instagram. I couldn't find anything reading the docs. A hint on how to proceed?
child: InteractiveViewer(
transformationController: controller,
maxScale: 2.0,
minScale: 2.0,
child: imageBig,
fit: BoxFit.fitWidth,
),
According to this issue on flutter repository:
https://github.com/flutter/flutter/issues/66111
You can achive that by using OverlayEntry Class, which will handle the rendering of your InteractiveViewer child widget over the other widgets.
Also, you can find here a code snippet for InteractiveViewerOverlay widget, that you can use directly inside your project.
https://gist.github.com/zzterrozz/623531eef065a31470e85175c744c986
created by:
https://github.com/PixelToast
https://github.com/zzterrozz
Edited:
Here is an example for the InteractiveViewerOverlay widget and how to use it.
First, the InteractiveViewerOverlay widget
class InteractiveViewerOverlay extends StatefulWidget {
final Widget child;
final double maxScale;
const InteractiveViewerOverlay({
Key key,
#required this.child,
this.maxScale,
}) : super(key: key);
#override
_InteractiveViewerOverlayState createState() =>
_InteractiveViewerOverlayState();
}
class _InteractiveViewerOverlayState extends State<InteractiveViewerOverlay>
with SingleTickerProviderStateMixin {
var viewerKey = GlobalKey();
Rect placeholder;
OverlayEntry entry;
var controller = TransformationController();
Matrix4Tween snapTween;
AnimationController snap;
#override
void initState() {
super.initState();
snap = AnimationController(vsync: this);
snap.addListener(() {
if (snapTween == null) return;
controller.value = snapTween.evaluate(snap);
if (snap.isCompleted) {
entry.remove();
entry = null;
setState(() {
placeholder = null;
});
}
});
}
#override
void dispose() {
snap.dispose();
super.dispose();
}
Widget buildViewer(BuildContext context) {
return InteractiveViewer(
key: viewerKey,
transformationController: controller,
panEnabled: false,
maxScale: widget.maxScale ?? 2.5,
child: widget.child,
onInteractionStart: (details) {
if (placeholder != null) return;
setState(() {
var renderObject =
viewerKey.currentContext.findRenderObject() as RenderBox;
placeholder = Rect.fromPoints(
renderObject.localToGlobal(Offset.zero),
renderObject
.localToGlobal(renderObject.size.bottomRight(Offset.zero)),
);
});
entry = OverlayEntry(
builder: (context) {
return Positioned.fromRect(
rect: placeholder,
child: buildViewer(context),
);
},
);
Overlay.of(context).insert(entry);
},
onInteractionEnd: (details) {
snapTween = Matrix4Tween(
begin: controller.value,
end: Matrix4.identity(),
);
snap.value = 0;
snap.animateTo(
1,
duration: Duration(milliseconds: 250),
curve: Curves.ease,
);
});
}
#override
Widget build(BuildContext context) {
var viewer = placeholder != null
? SizedBox.fromSize(size: placeholder.size)
: buildViewer(context);
return Container(
child: viewer,
);
}
}
Next, An example of implementing the InteractiveViewerOverlay widget.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(),
body: ListView(children: [
Column(
children: [
Container(
decoration: BoxDecoration(
color: Colors.white,
border:
Border(bottom: BorderSide(color: Colors.green))),
width: double.infinity,
height: 60,
child: Column(children: [
Text('Abdelazeem Kuratem',
style: TextStyle(color: Colors.black)),
Text('5 min', style: TextStyle(color: Colors.black)),
])),
InteractiveViewerOverlay(
child: Image.network(
"https://upload.wikimedia.org/wikipedia/commons/6/6a/Mona_Lisa.jpg",
fit: BoxFit.contain,
),
),
Container(
decoration: BoxDecoration(
color: Colors.grey[50],
border: Border(top: BorderSide(color: Colors.green))),
child: Stack(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
_createBottomButton(
text: 'Like',
icon: Icons.thumb_up,
onPressed: () {}),
_createBottomButton(
text: 'Comment',
icon: Icons.comment,
onPressed: () {}),
_createBottomButton(
text: 'Share',
icon: Icons.share,
onPressed: () {}),
],
),
],
),
),
],
),
])),
);
}
Widget _createBottomButton({
String text,
IconData icon,
Null Function() onPressed,
}) {
return FlatButton.icon(
onPressed: onPressed,
icon: Icon(
icon,
color: Colors.green,
size: 21,
),
label: Text(
text,
style: TextStyle(color: Colors.green, fontSize: 14),
),
);
}
}

Flutter TabBarView and BottomNavigationBar pages are not refreshing with SetState

I have the following Flutter BottomNavigationBar, I have 3 children page widgets. As soon as the user writes a review and press the submit button, I am calling the void _clear() which resets the values in the textfield widgets. This method is inside and called from the WriteReview widget but is not working, the screen is not refreshing. The data it self is being reset but the UI has not be refreshed. I tried with and without setState(){ _clear()}; but no results.
I have similar issue with the TabBarView. What I would expect as a result would be the selected widget page to be refreshed.
I assume is something different on how the widgets are being handled in the TabBarView and BottomNavigationBar that I am missing.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class HomeView extends StatefulWidget {
#override
_HomeViewState createState() => _HomeViewState();
}
class _HomeViewState extends State<HomeView> {
final String _writeReviewLabel = 'Write review';
final String _searchLabel = 'Search';
final String _accountLabel = 'Account';
var _currentIndex = 0;
final List<Widget> _bottomBarItems = [
WriteReviewView(),
SearchView(),
UserAccountView()
];
#override
Widget build(BuildContext context) {
final accentColor = Theme.of(context).accentColor;
final primaryColor = Theme.of(context).primaryColor;
return BaseView<HomePresenter>(
createPresenter: () => HomePresenter(),
onInitialize: (presenter) {
_currentIndex = ModalRoute.of(context).settings.arguments;
},
builder: (context, child, presenter) => Scaffold(
bottomNavigationBar: BottomNavigationBar(
backgroundColor: primaryColor,
selectedItemColor: accentColor,
unselectedItemColor: Colors.white,
elevation: 0,
currentIndex: _currentIndex,
onTap: (index) {
onTabTapped(index, presenter);
},
items: [
BottomNavigationBarItem(
activeIcon: Icon(Icons.rate_review),
icon: Icon(Icons.rate_review),
title: Text(_writeReviewLabel),
),
BottomNavigationBarItem(
activeIcon: Icon(Icons.search),
icon: Icon(Icons.search),
title: Text(_searchLabel),
),
BottomNavigationBarItem(
activeIcon: Icon(Icons.person),
icon: Icon(Icons.person),
title: Text(_accountLabel)),
],
),
body: _bottomBarItems[_currentIndex]),
);
}
void onTabTapped(int index, HomePresenter presenter) {
if (index == _currentIndex) {
return;
}
if (presenter.isAuthenticated) {
setState(() {
_currentIndex = index;
});
} else {
presenter.pushNamed(context, Routes.login, arguments: () {
if (presenter.isAuthenticated) {
Future.delayed(const Duration(microseconds: 500), () {
setState(() {
_currentIndex = index;
});
});
}
});
}
}
}
Write Review View
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'base/BaseView.dart';
class WriteReviewView extends StatefulWidget {
#override
_WriteReviewViewState createState() => _WriteReviewViewState();
}
class _WriteReviewViewState extends State<WriteReviewView> {
final String _locationLabel = 'Location';
final String _reviewLabel = 'Review';
#override
Widget build(BuildContext context) {
return BaseView<WriteReviewPresenter>(
createPresenter: () => WriteReviewPresenter(),
onInitialize: (presenter) {
presenter.init();
},
builder: (context, child, presenter) => Container(
color: Theme.of(context).backgroundColor,
child: _body(presenter),
));
}
Widget _body(WriteReviewPresenter presenter) {
final height = MediaQuery.of(context).size.height;
return LayoutBuilder(builder: (context, constraint) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(minHeight: constraint.maxHeight),
child: IntrinsicHeight(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Card(
margin: EdgeInsets.fromLTRB(4.0, 4.0, 4.0, 8.0),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 10, bottom: 20),
child: Row(
children: [
Icon(Icons.location_on,
color: Theme.of(context).cursorColor),
SectionTitle(_locationLabel),
],
),
),
ChooseAddressButton(presenter.addressContainer.address, () {
presenter.navigateNewAddress(context);
}),
SizedBoxes.medium,
],
),
),
),
Card(
margin: EdgeInsets.fromLTRB(4.0, 4.0, 4.0, 8.0),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Column(
children: [
Padding(
padding: EdgeInsets.only(top: 10),
child: Row(
children: [
Icon(Icons.star, color: Theme.of(context).indicatorColor),
SectionTitle(_reviewLabel),
],
),
),
SizedBoxes.medium,
CustomTextFormField(
data: presenter.reviewContainer.review,
showMinimum: true,
characterLimit: 50,
maxLines: 4,
height: 100),
ModifyRatingBar(50.0, presenter.reviewContainer.rating, false),
Padding(
padding: EdgeInsets.symmetric(vertical: 5),
child: Divider(indent: 40, endIndent: 40)),
],
),
),
),
Padding(
padding: EdgeInsets.symmetric(horizontal: 10),
child: Card(
color: Theme.of(context).accentColor,
child: FlatButton(
onPressed: () {
_submit(context, presenter);
},
child: Text('Submit',style:TextStyle(fontWeight: FontWeight.bold,fontSize: 18,color: Colors.white)),
),
),
),
],
),
),
),
);
});
}
void _submit(BuildContext context, WriteReviewPresenter presenter) async {
LoadingPopup.show(context);
final status = await presenter.submit(context);
LoadingPopup.hide(context);
if (status == ReviewStatus.successful) {
PostCompletePopup.show(context);
setState(() {
presenter.clear();
});
} else {
presenter.showError(context, status);
}
}
}
setState() only refreshes the widget that called it, and all the widgets under it.
When calling setState()from WriteReview widget, it will not update the HomeView widget. Try moving the setState()call to the HomeView widget using some sort of callback.