I have 4 modal sheets in flutter, the order is modal-1 -> modal-2 -> modal-3 -> modal-4.
so, one modal goes down and other pops up ! is there any way in which I can stop this going down and poping up of another modal?
I'm using Bloc architecture on stateless widgets.
please help me to achieve any of the following, or suggest some thing else
1 - change data from instead of changing modal itself.
2 - stop modal going down and poping up animation.
I had a similar situation and used IndexedStack inside of the modal. So in essence, the actual content widgets (not the entire modal) from Sheet 1-4 become child widgets of the IndexedStack which actually is inside the modal.
import 'package:flutter/material.dart';
class ParentModalContent extends StatefulWidget {
ParentModal({Key? key}) : super(key: key);
#override
_ParentModalContentState createState() => _ParentModalContentState();
}
class _ParentModalContentState extends State<ParentModalContent> {
int currentIndex = 0;
#override
Widget build(BuildContext context) {
return IndexedStack(
children: [
Child1(
onNext: () {
setState(() {
currentIndex = currentIndex + 1;
});
},
),
// more widgets
],
);
}
}
class Child1 extends StatelessWidget {
final Function onNext;
const Child1({Key? key, required this.onNext}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
// content
);
}
}
Wrap the ParentModalContent inside of the function that shows your modal.
Related
TLDR; I added a custom page transition, sliding to the left. It works perfectly for every page in the App except the Welcome screen which contains only a video player. After the video ends, I get transferred to the desired page but the normal 'transition animation' happens instead of my custom one.
More info: I use Navigator.pushNamed(context, '/pagename') for my page travels. I created a custom transition, CustomPageRoute, which did not support named navigation. After a few searches I made it work and now supports both the cleanness of named navigation plus the transition animations plus the data transferring from page to page. All expect the welcome screen which just plays a video then after 3 seconds it pushes the Login page. Here is the code of the Welcome Page:
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';
class WelcomePage extends StatefulWidget {
const WelcomePage({Key? key}) : super(key: key);
#override
State<WelcomePage> createState() => _WelcomePageState();
}
class _WelcomePageState extends State<WelcomePage> {
late VideoPlayerController _controller;
#override
void initState() {
super.initState();
_controller = VideoPlayerController.asset('assets/welcome_vid.mp4')
..initialize().then((_) {
setState(() {});
})
..setVolume(0.0);
_playVideo();
}
void _playVideo() async {
_controller.play();
await Future.delayed(const Duration(seconds: 3))
.then((_) => Navigator.pushNamed(context, '/login'));
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Center(
child: _controller.value.isInitialized
? AspectRatio(
aspectRatio: _controller.value.aspectRatio,
child: VideoPlayer(
_controller,
),
)
: Container(),
));
}
}
Also, here is a sample of the named routes I use in main.dart:
static Route onGenerateRoute(RouteSettings settings) {
switch (settings.name) {
case '/login':
return CustomPageRoute(child: LoginPage(), settings: settings);
Also, Flutter Doctor detected no problems, everything is up to date and I don't think any libraries overlap another. I even tried to change the destination if maybe somehow that affected anything but no.
Why doesn't it work?
When I use Share.share using Flutter share_plus package the app bar disappears and the content of the screen moves up...and it doesn't look very nice.
Simple example:
import 'package:flutter/material.dart';
import 'package:share_plus/share_plus.dart';
class Example extends StatelessWidget {
const Example({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () async {
await Share.share('Some text');
},
child: const Text('Press me'),
);
}
}
Anyone knows why that happens?
Try SafeArea around Scaffold widget.
Try this out It works fine for me
final RenderBox box = context.findRenderObject() as RenderBox;
Share.share(shareURL,
subject: title,
sharePositionOrigin: box.localToGlobal(Offset.zero) & box.size);
I am trying to create an app. I want to change an attribute in a parent class (so it can display a Visibility item, SlidingUpPanel) after submitting a query in the child class (which is a search bar).
I have tried using a callback function and followed How can I pass the callback to another StatefulWidget? but it doesn't seem to do anything when I submit my query in the search bar. Previously, I have also tried to use Navigator.push to call SlidingUpPanel directly but it resulted in a black screen with only SlidingUpPanel.
Parent class (Map):
class MapPage extends StatefulWidget {
const MapPage({Key? key}) : super(key: key);
#override
_MapPageState createState() => _MapPageState();
}
class _MapPageState extends State<MapPage> {
bool IsVisible = false;
void callbackFunction() {
setState(() {
IsVisible = true;
});
}
...
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
body: Stack(
children: [
...
Visibility(
visible: IsVisible,
child: SlidingUpPanel()),
SearchPage(callbackFunction),
]),
);
}
}
Child class (Search Bar):
class SearchPage extends StatefulWidget {
final Function callback;
SearchPage(this.callback);
#override
_SearchPageState createState() => _SearchPageState();
}
class _SearchPageState extends State<SearchPage> {
...
#override
Widget build(BuildContext context) {
return FloatingSearchBar(
...
onSubmitted: (query) {
// callback here, but doesn't seem to do anything
widget.callback;
controller.close();
},
...
);
}
}
To actually call a function (execute it) you must use ().
Try calling the callback function like this:
onSubmitted: (query) {
// use () to actually call the function
widget.callback();
controller.close();
},
I made it possible to toggle the heart icon in the post like Instagram.
And I implemented it so that user information is uploaded to the firestore when I toggle the icon.
There is no problem with the 'Like' and 'Unlike' function of 'Like Icon', but there is one other problem.
There is a problem that the color of the icon does not change immediately when toggling the icon in the post. I can check that this icon has changed when I go to a different screen and come back in.
The following is the code for this icon. (I edited this code)
class LikeToggleIcon extends StatefulWidget {
final String postKey;
final PostModel postModel;
const LikeToggleIcon(
{Key key,
this.postKey,
this.postModel,
this.fromSearch,
this.searchResults})
: super(key: key);
#override
State<LikeToggleIcon> createState() => _LikeToggleIconState();
}
class _LikeToggleIconState extends State<LikeToggleIcon> {
// bool _isLiked = false;
#override
Widget build(BuildContext context) {
//get userModel
UserModel userModel =
Provider.of<UserModelState>(context, listen: false).userModel;
return IconButton(
onPressed: () {
// setState(() {
postNetworkRepo.toggleLike(
widget.postModel.postKey, userModel.userKey);
// });
},
icon: Icon(
widget.postModel.numOfLikes.contains(userModel.userKey)
? Icons.favorite_outlined
: Icons.favorite_border_outlined,
size: 27,
color: Colors.redAccent,
),
);
//toggle method
class PostNetworkRepo with Transformers {
Future<void> toggleLike(String postKey, String userKey) async {
final DocumentReference postRef =
Firestore.instance.collection(COLLECTION_POSTS).document(postKey);
final DocumentSnapshot postSnapshot = await postRef.get();
//check Post collection
if (postSnapshot.exists) {
//check already contain userKey
//if no contain upload userKey, else delete userKey (toggle Like/Unlike)
if (postSnapshot.data[KEY_NUMOFLIKES].contains(userKey)) {
postRef.updateData({
KEY_NUMOFLIKES: FieldValue.arrayRemove([userKey])
});
} else {
postRef.updateData({
KEY_NUMOFLIKES: FieldValue.arrayUnion([userKey])
});
}
}
}
}
PostNetworkRepo postNetworkRepo = PostNetworkRepo();
//This is the part of detail post screen.
class DetailScreen extends StatefulWidget {
#override
_DetailScreenState createState() => _DetailScreenState();
}
class _DetailScreenState extends State<DetailScreen> {
#override
Widget build(BuildContext context) {
//get userModel
UserModel userModel =
Provider.of<UserModelState>(context, listen: false).userModel;
return Scaffold(
appBar: AppBar(
title: _postUser(),
actions: [
//toggle likeIcon
LikeToggleIcon(
postKey: widget.postKey,
postModel: widget.postModel,
),
],
),
I tried using setState() on the IconButton(), but the problem was not solved.
can I get help with this problem?
I believe you are using setState() to change value of variable that's inside the Widget and NOT the State of that widget.
You need to have variables that changes the Widget inside the state for it to be updated. Keeping it inside Widget won't change the Icon, unless the whole widget is recreated (like when you change the screen).
(correct me if I'm wrong. Providing full code of the widget could be more useful)
I have a setting page displaying a list view and each list tile displays the name of a user and a percentage which can be edited. By tapping on a list tile the user can change the percentage using a dialog.
I would like to update the state of a single list tile when the user saves the new value instead of building the entire page again (should be better for perfomance too). Is this possible?
I have already tried to export the list tile as a stateful widget (it must be stateful) and using it in my setting page but the setState() method does not work on the single tile at all. I don't know if it would somehow work with a notifier.
Here is how the page looks like (showing the dialog to set the new percentage):
enter image description here
Thanks in advance!
Edit: I added some code.
setting_page.dart
// this widget is called in a ListView.builder to bild the list tile.
// before creating the UserListTile widget I used to return the ListTile in
// _buildRow and call setState() but then everything is re-built again, which is what I don't want to
Widget _buildRow(User user) {
return UserListTile(
user: user, userDAO: _userDAO, myPercentage: _myPercentage);
}
user_list_tile.dart
import 'package:flutter/material.dart';
import 'package:myapp/classes/user.dart';
import 'package:myapp/database/user_dao.dart';
import 'package:numberpicker/numberpicker.dart';
class UserListTile extends StatefulWidget {
const UserListTile(
{Key? key,
required this.user,
required this.userDAO,
required this.myPercentage})
: super(key: key);
final User user;
final UserDAO userDAO;
final ValueNotifier<double> myPercentage;
#override
_UserListTileState createState() => _UserListTileState();
}
class _UserListTileState extends State<UserListTile> {
final TextStyle _biggerFont = const TextStyle(fontSize: 18);
double _currentDoubleValue = 10.0;
double? trailing;
#override
Widget build(BuildContext context) {
trailing = widget.user.percentage;
return ListTile(
title: Text(
widget.user.name,
style: _biggerFont,
),
trailing: Text('${trailing} %'),
onTap: () => _showDoubleDialog(widget.user).then((value) {
if (value != false && value != null) {
// some code to set the new percentage
User _updatedUser = User(
name: widget.user.name,
id: widget.user.id,
percentage: _newPercentage);
widget.userDAO.updateData(_updatedUser);
setState(() {}); // <- this setState does not update the single tile
}
}),
);
}
Future _showDoubleDialog(User user) {
_currentDoubleValue = user.percentage;
return showDialog(
// code to shod the dialog to edit the percentage
);
}
}