How to make floating widget flutter? - flutter

I want to make a floating widget but not floating all the time, when the widget is pulled up from the floating navigation bar it will appear like the picture in the middle
How to make a widget like this middle image?

this sample code of flutter for using showBottomSheet:
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: const MyStatelessWidget(),
),
);
}
}
class MyStatelessWidget extends StatelessWidget {
const MyStatelessWidget({super.key});
#override
Widget build(BuildContext context) {
return Center(
child: ElevatedButton(
child: const Text('showBottomSheet'),
onPressed: () {
Scaffold.of(context).showBottomSheet<void>(
(BuildContext context) {
return Container(
height: 200,
color: Colors.amber,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const Text('BottomSheet'),
ElevatedButton(
child: const Text('Close BottomSheet'),
onPressed: () {
Navigator.pop(context);
},
),
],
),
),
);
},
);
},
),
);
}
}

You can also try using sliding_up_panel to get the same functionality.
It is pretty straight forward to implement and offers plenty customization features as well:
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("SlidingUpPanelExample"),
),
body: Stack(
children: <Widget>[
Center(child: Text("This is the Widget behind the sliding panel"),),
SlidingUpPanel(
panel: Center(child: Text("This is the sliding Widget"),),
)
],
)
);
}
Try the Stack variant so that it doesn't hinder too much with your current code.

Related

How to access variable from different class ? Flutter (I want to change background image onpress)

I'm struggling to find way to access variable from different class. I want to change background image of decorationImage on button click. But because I do not want to rebuild entire state/page just the background I put the code to different class, but I'm not sure how to access _imagepath1 or _imagepath2 from other class.
class CustomMainPageState extends State<SecondRoute> {
Color myColor = Color(0xff5D6592);
String _imagepath1 = "images/image3.jpg";
String _imagepath2 = "images/image4.jpg";
Widget build(BuildContext context) => Container(
//color: Colors.transparent,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(_imagepath1), fit: BoxFit.cover)),
child: Scaffold(
class background extends StatefulWidget {
backgroundG createState() => backgroundG();
}
class backgroundG extends State<background> {
#override
Widget buildbottom() {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
CircleAvatar(
radius: 25,
backgroundColor: Colors.white,
child: IconButton(
icon: Image.asset('images/icon2.png'),
onPressed: () => setState(() {
//_imagefile1 = _imagefile2;
}),
),
),
]);
}
#override
Widget build(BuildContext context) {
return Container(
child: Row(
children: [
SizedBox(height: 100),
buildbottom(),
//SizedBox(height: 10),
//SizedBox(height: 10),//puts empty box to space things out
],
),
);
}
}
Thank you for helping!
For passing one image to different class you can use flutter hero widget,
below is sample code of working with Hero widget check documentation also for more info about hero widget
import 'package:flutter/material.dart';
void main() => runApp(HeroApp());
class HeroApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Transition Demo',
home: MainScreen(),
);
}
}
class MainScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Main Screen'),
),
body: GestureDetector(
child: Hero(
tag: 'imageHero',
child: Image.network(
'https://picsum.photos/250?image=9',
),
),
onTap: () {
Navigator.push(context, MaterialPageRoute(builder: (_) {
return DetailScreen();
}));
},
),
);
}
}
class DetailScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: GestureDetector(
child: Center(
child: Hero(
tag: 'imageHero',
child: Image.network(
'https://picsum.photos/250?image=9',
),
),
),
onTap: () {
Navigator.pop(context);
},
),
);
}
}
for passing data between widgets or class I would suggest you to use InheritedWidget class or any state management like provider, bloc, getx to know more about this check this video and documentation and if you just want to pass single image then refer this blog

I would like to add some of the quotes to a new screen called as Favorites

Please be kind and tell me where do I add the line of code and what logic to follow?
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
final alreadySaved = _savedQuotes.contains(context);
return MaterialApp(
theme: ThemeData(primaryColor: Colors.blue[600]),
home: Scaffold(
appBar: AppBar(title: Text('Quotes')),
body: ListView(
padding: const EdgeInsets.all(8),
children: <Widget>[
),
Container(
height: 50,
color: Colors.blue[200],
child: const Center(
child: Text(
'You only live once, but if you do it right, once is enough.')),
)
],
)));
}
}
I am very poor at Dart ,And just starting
Here is the Scrrenshot of the app
I want to add like icon on the left for each of the quotes that will toggle the Favorite on and off

Flutter returns a black screen after navigating to other route

I'm writing a very simple coupon app, however I have a problem with navigating to different pages. I have two buttons, each of them is used to navigate to a different page, but Flutter is returning a black screen instead.
Here's the error: "There are multiple heroes that share the same tag within a subtree.".
Here's the video: https://streamable.com/id4nf2
Here's the code:
Hamburger
import 'package:flutter/cupertino.dart';
import 'package:makdolan_flutter/shared/home_screen_items.dart';
class Hamburger extends StatelessWidget {
#override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: Text('Hamburger'),
),
child: SafeArea(
child: HomeScreenItems(
imagePath: 'lib/assets/images/coupon_hamburger.png',
onClassicCouponPressed: () {
Navigator.pushNamed(context, '/classic-coupon');
},
onMailCouponPressed: () {},
),
),
);
}
}
Home Screen Items
import 'package:flutter/cupertino.dart';
double _sizedBoxHeight = 16.0;
double _paddingHorizontal = 8.0;
class HomeScreenItems extends StatelessWidget {
final String imagePath;
final VoidCallback onClassicCouponPressed;
final VoidCallback onMailCouponPressed;
HomeScreenItems({#required this.imagePath, this.onClassicCouponPressed, this.onMailCouponPressed});
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.asset(imagePath),
SizedBox(height: _sizedBoxHeight),
Padding(
padding: EdgeInsets.symmetric(horizontal: _paddingHorizontal),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
CupertinoButton(
child: Text('KLASYCZNY KUPON'),
color: CupertinoColors.activeBlue,
onPressed: onClassicCouponPressed,
),
SizedBox(height: _sizedBoxHeight),
CupertinoButton(
child: Text('KUPON Z MAILA'),
color: CupertinoColors.activeOrange,
onPressed: onMailCouponPressed,
)
],
),
)
],
);
}
}
Classic Coupon
import 'package:flutter/cupertino.dart';
class ClassicCoupon extends StatelessWidget {
#override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
child: Text('Test'),
);
}
}
I don't know the code you use to change the screen with the BottomNavigationBar but if you're preserving them with a CupertinoTabBar or PageView or anything and each page has its own CupertinoNavigationBar then by default they use a heroTag for animate from one route to another when using Nagivation.pop/push/etc
Try give them a hero tag to each one
class Hamburger extends StatelessWidget {
#override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: Text('Hamburger'),
heroTag: 'HamburgerTag' //give them a different heroTag to each one
),
child: SafeArea(
child: HomeScreenItems(
imagePath: 'lib/assets/images/coupon_hamburger.png',
onClassicCouponPressed: () {
Navigator.pushNamed(context, '/classic-coupon');
},
onMailCouponPressed: () {},
),
),
);
}
}
class ClassicCoupon extends StatelessWidget {
#override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(heroTag: 'HamburgerTag') //Give the same name so it makes the transition animation
child: Text('Test'),
);
}
}
Do the same to the other 2 pages (Jak and Lody).
class Jak extends StatelessWidget {
#override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: Text('Jak'),
heroTag: 'JakTag' //give them a different heroTag to each one
),
child: ...
);
}
}
class Lody extends StatelessWidget {
#override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: Text('Lody'),
heroTag: 'LodyTag' //give them a different heroTag to each one
),
child: ...
);
}
}
When the Navigator try to move to a new route it checks all the heroTags from the previous and the next route and start doing the animations (it cheks the one with the same name to start animating), if you don't define the tags it will use a _defaultHeroTag, and if there are 2 tags with the same value the error There are multiple heroes that share the same tag within a subtree. happens
You need to use Scaffold () for any page where you don't want black screen while navigation.
Its should be like return Scaffold (body: Column())
EDITED
Hero widget tag needs to be unique.
void main() {
runApp(
CupertinoApp(
routes: {
"Screen1": (context) => Screen1(),
"Screen2": (context) => Screen2(),
},
home: Screen1(),
),
);
}
class Screen1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Hero(
tag: "Screen2",
child: GestureDetector(
onTap: () {
Navigator.pushNamed(context, "Screen2");
},
child: Image.asset("assets/images/banane.jpg")),
),
RaisedButton(
color: Colors.blue,
child: Text("go to screen2"),
onPressed: () => Navigator.of(context).pushNamed("Screen2"),
),
],
),
);
}
}
class Screen2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(),
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Hero(
tag: "Screen2", child: Image.asset("assets/images/banane.jpg")),
Center(
child: RaisedButton(
color: Colors.red,
child: Text("go to screen1"),
onPressed: () => Navigator.of(context).pop(),
),
),
],
),
),
);
}
}
result click me
good luck buddy

Flutter navigation by route name in statefull widget

i am trying to go on another page using navigation, but i am getting error;
Navigator operation requested with a context that does not include a
Navigator.
i am just trying to move on next page, i followed flutter documentations for this stateless widget but how to do with state full widget.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
State createState() => new MyApp1();
}
class MyApp1 extends State<MyApp> {
List<Widget> _listSection = [];
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Share IDEASS',
initialRoute: '/',
routes: {
'/second': (context) => SecondScreen(),
},
home: Scaffold(
appBar: AppBar(
title: Text('IDEAS'),
),
body: Container(
child: Stack(
children: [
floatingButton(),
],
),
),
),
);
}
Widget floatingButton() {
return Container(
padding: const EdgeInsets.all(30),
alignment: Alignment.bottomRight,
child: FloatingActionButton(
onPressed: () {
Navigator.pushNamed(context, "/SecondScreen");
},
child: Text("+"),
backgroundColor: Colors.blue,
),
);
}
}
class SecondScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Route"),
),
body: Center(
child: RaisedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Go back!'),
),
),
);
}
}
You should use the named route you created.
Widget floatingButton(BuildContext context) { // added context as a parameter
return Container(
padding: const EdgeInsets.all(30),
alignment: Alignment.bottomRight,
child: FloatingActionButton(
onPressed: () {
Navigator.pushNamed(context, "/second"); // Changed this to use the named route
},
child: Text("+"),
backgroundColor: Colors.blue,
),
);
}
}
then use the following
body: Container(
child: Stack(
children: [
floatingButton(context),
],
),
),
The situation here is that the floatingButton() uses a context with the navigator to push the given page route. But the context used is provided in the parent Widget(MaterialApp) it self, which doesn't include a Navigator, hence the error.
So, Try this approach:
Separate the Home widget from the MaterialApp, like below:
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Share IDEASS',
initialRoute: '/',
routes: {
'/second': (context) => SecondScreen(),
},
home: HomePage(),
);
Create a stateless widget containing the Scaffold:
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('IDEAS'),
),
body: Container(
child: Stack(
children: [
floatingButton(),
],
),
),
);
}
}
Hope it helps. Let me know if this doesn't work.
You have made two mistakes because of which your code is not working:
You have used wrong route name. Replace /SecondScreen with /second
You have used wrong context. You can get Navigator only if your widget has MaterialApp as it's parent and here you are using context of MyApp1 so it is not working.
Following is a working code for your reference.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
State createState() => new MyApp1();
}
class MyApp1 extends State<MyApp> {
List<Widget> _listSection = [];
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Share IDEASS',
initialRoute: '/',
routes: {
'/second': (context) => SecondScreen(),
},
home: AppContent(),
);
}
}
class AppContent extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('IDEAS'),
),
body: Container(
child: Stack(
children: [
floatingButton(context),
],
),
),
);
}
Widget floatingButton(BuildContext context) {
return Container(
padding: const EdgeInsets.all(30),
alignment: Alignment.bottomRight,
child: FloatingActionButton(
onPressed: () {
Navigator.pushNamed(context, "/second");
},
child: Text("+"),
backgroundColor: Colors.blue,
),
);
}
}
class SecondScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Route"),
),
body: Center(
child: RaisedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Go back!'),
),
),
);
}
}

How to remove the second appbar in Flutter

I am trying to build a demo chat app with Flutter. After my main screen, I am using Navigator.push to go to the details screen.
Screenshot of problem:
build method of 1st screen:
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Chat Thread App"),
actions: <Widget>[
IconButton(
icon: Icon(Icons.settings),
onPressed: () {
Navigator.pushNamed(context, '/settings');
},
)
],
),
body: isLoading
? Center(
child: CircularProgressIndicator(),
)
: new ChatThreadListCard(messageThreads: _messageThreadLists, user: _user,),
);
}
code of Navigator.push method:
Navigator.push(context, MaterialPageRoute(
builder: (context) => ChatDetailsScreen(threadModel: new ThreadModel(
user.id,
user.fullName,
user.pic,
"otherId",
"otherName",
"otherPic",
post.threadId
)
),
),);
build method of 2nd screen, where the problem is produced:
return Scaffold(
appBar: AppBar(
title: Text("Chat demo"),
),
body: WillPopScope(
child: isLoading
? Center(
child: CircularProgressIndicator(),
)
: Stack(
alignment: AlignmentDirectional.bottomCenter,
children: <Widget>[
SizedBox(
width: 300,
height: 300,
),
Column(
children: <Widget>[
buildChat(),
buildInput(),
],
)
],
),
onWillPop: onBackPress,
),
);
the problem turns out to be, i was creating a MaterialApp widget in scaffold's body. so, when the onTap method was called, the new screen was replaced insdie the MaterialApp's area. didnt replace the whole screen.
the trick was to remove the return new MaterialApp().
thanks everyone.
I'm guessing something isn't working right with where you're setting up the Material App?
app.dart:
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage());
}
}
home_page and second_page
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
#override
State createState() => HomePageState();
}
class HomePageState extends State<HomePage> with TickerProviderStateMixin {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('First Page'),
),
body: Container(
child: Center(child: RaisedButton(child: Text('Forward'), onPressed: () async {
await Navigator.push(context, MaterialPageRoute(builder: (context) => SecondPage()));
},)),
));
}
}
class SecondPage extends StatefulWidget {
#override
State createState() => SecondPageState();
}
class SecondPageState extends State<SecondPage> with TickerProviderStateMixin {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Second Page'),
),
body: Container(
child: Center(child: RaisedButton(child: Text('Backward'), onPressed: () {
Navigator.of(context).pop();
},)),
));
}
}
Which produces: