switch between pages in the flutter using the Smooth Page Indicator - flutter

I want to make a steamer to the next page using the Smooth Page Indicator widget. I added this widget to the page but I don't know how to add the pages I want to go to. I will be grateful for your help
My code :
final controller = PageController(viewportFraction: 0.8, keepPage: true);
#override
Widget build(BuildContext context) {
return Scaffold(
body:
Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
SizedBox(height: 35.0),
Container(
child: SmoothPageIndicator(
controller: controller,
count: 2,
effect: JumpingDotEffect(
dotHeight: 16,
dotWidth: 16,
jumpScale: .7,
verticalOffset: 15,
),
),
),
]),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
_scanQR();
});
},
child: const Icon(Icons.qr_code),
backgroundColor: Colors.pink,
),
);
}
the name of my page to which I want to go Page2, and this Page1

I think you might be looking for the PageView widget : https://api.flutter.dev/flutter/widgets/PageView-class.html
By passing the same PageController to both, the PageView and the SmoothPageIndicator widgets you should be able to swipe left and right AND see the dots move along. That simple.

Related

Display multiple pages at the same time

I have an app with two features, that have routes such as:
/feature1
/feature1/a
/feature2
/feature2/a
/feature2/a/b
/feature2/c
I can use GoRouter and its ShellRoute to switch between these one at a time using context.goNamed('feature2'), which would replace the entire screen with feature 2 (when tapping a tab in a tab bar for example). Here's a diagram of just the top level routes using tabs:
However, I would like to have an overview style menu which displays multiple destinations at once, so the user can see where they will be going before they go there (for example the preview page tabs in a mobile web browser). Here's a diagram:
and then tapping on either of the two pages would make them full screen:
Pressing the menu button at the bottom would return you to the overview menu page.
One way I have thought about solving this would be to make static preview images out of the routes when the menu button is tapped, and just display the previews. But these won't be live, and I would like a more elegant approach that actually displays the live contents of the route if possible.
Another way I have thought about solving this would be to use a top level GoRouter and then two descendant GoRouters each containing just one branch of the routes. I'm not sure if multiple GoRouters would lead to problems with things like if I wanted to context.go() to another branch.
If the ShellRoute.builder gave me access to all of the child page's widgets, I could display them however I wanted, but it just provides a single child.
I have not worked with 'go_router' or 'ShellRoute.builder', but I like to make custom animated widgets like this for apps. It's also hard to explain how it would work in your app, but here is my take on this.
Try copy pasting this in an empty page. I have written some notes in code comments that might help explain things a little bit. And, this is not perfect but with more polishing according to the needs it could work.
class CustomPageView extends StatefulWidget {
const CustomPageView({Key? key}) : super(key: key);
#override
State<CustomPageView> createState() => _CustomPageViewState();
}
class _CustomPageViewState extends State<CustomPageView> {
// Scroll Controller required to control scroll via code.
// When user taps on the navigation buttons, we will use this controller
// to scroll to the next/previous page.
final ScrollController _scrollController = ScrollController();
// Saving screen width and height to use it for the page size and page offset.
double _screenWidth = 0;
double _screenHeight = 0;
// A bool to toggle between full screen mode and normal mode.
bool _viewFull = false;
#override
void initState() {
super.initState();
// Get the screen width and height.
// This will be used to set the page size and page offset.
// As of now, this only works when page loads, not when orientation changes
// or page is resized. That requires a bit more work.
WidgetsBinding.instance.addPostFrameCallback((_) {
setState(() {
_screenWidth = MediaQuery.of(context).size.width;
_screenHeight = MediaQuery.of(context).size.height;
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
// 'Column' to wrap the 'Body' and 'BottomNavigationBar'
body: Column(
children: [
// 'Expanded' to take up the remaining space after the 'BottomNavigationBar'
Expanded(
// A 'Container' to wrap the overall 'Body' and aligned to center.
// So when it resizes, it will be centered.
child: Container(
alignment: Alignment.center,
// 'AnimatedContainer' to animate the overall height of the 'Body'
// when user taps on the 'Full Screen' button.
child: AnimatedContainer(
duration: const Duration(milliseconds: 500),
height: _viewFull ? 200 : _screenHeight,
// A 'ListView' to display the pages.
// 'ListView' is used here because we want to scroll horizontally.
// It also enables us to use 'PageView' like functionality, but
// requires a bit more work, to make the pages snap after scrolling.
child: ListView(
controller: _scrollController,
scrollDirection: Axis.horizontal,
children: [
// A 'Container' to display the first page.
AnimatedContainer(
duration: const Duration(milliseconds: 500),
width: _viewFull ? (_screenWidth / 2) - 24 : _screenWidth,
margin: _viewFull ? const EdgeInsets.all(12) : const EdgeInsets.all(0),
color: Colors.blue,
),
// A 'Container' to display the second page.
AnimatedContainer(
duration: const Duration(milliseconds: 500),
width: _viewFull ? (_screenWidth / 2) - 24 : _screenWidth,
margin: _viewFull ? const EdgeInsets.all(12) : const EdgeInsets.all(0),
color: Colors.yellow,
),
],
),
),
),
),
// 'BottomNavigationBar' to show the navigation buttons
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
// 'Feature 1' button
GestureDetector(
onTap: () {
// Scroll to the first page
_scrollController.animateTo(
0,
duration: const Duration(milliseconds: 500),
curve: Curves.easeInOut,
);
},
child: Container(
height: 60,
alignment: Alignment.center,
color: Colors.red,
padding: const EdgeInsets.all(12),
child: const Text('Feature 1'),
),
),
// 'Feature 2' button
GestureDetector(
onTap: () {
// Scroll to the second page
_scrollController.animateTo(
_screenWidth,
duration: const Duration(milliseconds: 500),
curve: Curves.easeInOut,
);
},
child: Container(
height: 60,
alignment: Alignment.center,
color: Colors.green,
padding: const EdgeInsets.all(12),
child: const Text('Feature 2'),
),
),
// 'Full Screen' button
GestureDetector(
onTap: () {
// Toggle between full screen mode and normal mode
setState(() {
_viewFull = !_viewFull;
});
},
child: Container(
height: 60,
alignment: Alignment.center,
color: Colors.purple,
padding: const EdgeInsets.all(12),
child: const Text('View Full'),
),
),
],
),
],
),
);
}
}

How to display a snackBar in scaffold is body is composed of Stack?

I am trying to display a snack bar on my screen. But the snack bar is covering the whole screen instead of just being displayed at the bottom. Here is my code.
Scaffold(
key: _scaffoldKey ,
backgroundColor: Colors.pink,
body: Stack(
children: <Widget>[
Text('Display Scaffold'),
Positioned(
top: 110,
child: Container(
child: FlatButton(
onpressed: (){
final snackBar = SnackBar(duration: Duration(seconds: 4),
content: Center(child: Text('Welcome')),
) ;
_scaffoldKey.currentState.showSnackBar(snackBar);
}
),
),
),
),
);
Remove Center widget. This makes the widget as big as the parent allows.
If you need to center your text, just use textAlign: TextAlign.center property in Text widget.
Have you try this ?
Scaffold.of(context).showSnackBar(snackBar);
instead of
_scaffoldKey.currentState.showSnackBar(snackBar);
It may be the solution.
I hope it could help you !

Flutter - Screen focus on a certain widget

I need help to do the following: when I press List 1, the screen focuses on List 1; I need the same for the rest of the options
This is the code for the example:
code
This behavior already exists in web pages but I haven't found this same behavior at the mobile app level. Thank you
Here is a small code snippet of something similar which might help you achieve you desired results.
By clicking the fab icon it will scroll down to item 35 within the ListView.
class MyHomePage extends StatelessWidget {
final _scrollController = ScrollController();
final _cardHeight = 200.0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.orange,
onPressed: () => _animateToIndex(35),
child: Icon(Icons.add),
),
body: ListView.builder(
controller: _scrollController,
itemCount: 100,
itemBuilder: (_, i) => Container(
height: _cardHeight,
child: Card(
color: Colors.lightBlue,
child: Center(
child: Text("Scroll Item $i", style: TextStyle(fontSize: 28.0),),
),
),
),
),
);
}
_animateToIndex(index) {
_scrollController.animateTo(_cardHeight * index,
duration: Duration(seconds: 1), curve: Curves.fastOutSlowIn);
}
}
You'll need to have a scrollable Widget (like ListView, SingleScrollableWidget) instead of a Column in ListSecondPage.
Then add a ScrollController to it and ListSecondPage should receive which button was tapped. Based on that selection you can scroll to the desired location with the ScrollController

Color of a widget inside a Stack is always slightly transparent

I display a custom-made bottom app bar in a Stack because of keyboard padding reasons. The custom widget is fully opaque as it should be until it's a child of a Stack in which case, the content behind it starts to be visible since the color's opacity somehow changes.
As you can see, it's only the "main" color that's transparent. Icons remain opaque.
This is the build method of my custom BottomBar widget which is then just regularly put into a Stack. I have tried using a Material and even a simple Container in place of the BottomAppBar widget but the results are the same.
#override
Widget build(BuildContext context) {
return BottomAppBar(
color: Colors.blue.withOpacity(1),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
IconButton(
icon: Icon(MdiIcons.plusBoxOutline),
onPressed: () {},
),
Text('Edited 11:57'),
IconButton(
icon: Icon(MdiIcons.dotsVertical),
onPressed: () {},
),
],
),
);
}
Can you interact with the BottomAppBar ? It looks like an order problem. Try to put the BottomAppBar as last in the Stack children.
Note that BottomAppBar doesn't have a constant size, if you did not add it to Scaffold bottomNavigationBar named parameter has a size if this is not null. Below is peace of code in Scaffold dart file:
double bottomNavigationBarTop;
if (hasChild(_ScaffoldSlot.bottomNavigationBar)) {
final double bottomNavigationBarHeight = layoutChild(_ScaffoldSlot.bottomNavigationBar, fullWidthConstraints).height;
bottomWidgetsHeight += bottomNavigationBarHeight;
bottomNavigationBarTop = math.max(0.0, bottom - bottomWidgetsHeight);
positionChild(_ScaffoldSlot.bottomNavigationBar, Offset(0.0, bottomNavigationBarTop));
}
You can even develop your own Widget without BottomAppBar but if you want things like centerDocked and things like circular notched, you will have to do more stuff (anyway you have flexibility to custom design the way you want).
Here is a simple example to do that(one way to do that):
import 'package:flutter/material.dart';
class CustomBottomBar extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: <Widget>[
Container(
margin: EdgeInsets.only(bottom: 50),
color: Colors.greenAccent, // if you want this color under bottom bar add the margin to list view
child: ListView.builder(
itemCount: 100,
itemBuilder: (_, int index) => Text("Text $index"),
),
),
Positioned(
bottom: 0,
child: Container(
color: Colors.amber.withOpacity(.5),
width: MediaQuery.of(context).size.width,
height: 50,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: List.generate(4, (int index) => Text("Text $index")), // you can make these clickable by wrapping with InkWell or any gesture widget
),
),
),
],
),
);
}
}

Flutter navigator Question ! how to through a Button(in a page ) go to another navigative page?

what I want to do
I want to use a search button like on the top, go to another navigation page, and keep the navigativeBar,
I try the navigator.push(), but it will go to a new page without the navigativeBar,
What can I do?
Here is some of my code :
return Scaffold(
drawer: _buildDrawer(context),
body: IndexedStack(
index: pageIx,
children: <Widget>[
_buildBody(), Guanzhu(),
Tansuo(),
//Disan(list),
Setting(), Dier()
],
),
bottomNavigationBar: AnimatedBottomBar(
onBarTap: (index) => setState(() => pageIx = index),
barItems: widget.barItems,
animationDuration: const Duration(milliseconds: 150),
barStyle: BarStyle(fontSize: 20.0, iconSize: 30.0),
),
);