Flutter PageView not swipeable on web (desktop mode) - flutter

I'm new to flutter.
I implemented flutter PageView with the help of its documents:
/// Flutter code sample for PageView
// Here is an example of [PageView]. It creates a centered [Text] in each of the three pages
// which scroll horizontally.
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
/// This is the main application widget.
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: 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(),
),
);
}
}
/// This is the stateless widget that the main application instantiates.
class MyStatelessWidget extends StatelessWidget {
const MyStatelessWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
final PageController controller = PageController(initialPage: 0);
return PageView(
/// [PageView.scrollDirection] defaults to [Axis.horizontal].
/// Use [Axis.vertical] to scroll vertically.
scrollDirection: Axis.horizontal,
controller: controller,
children: const <Widget>[
Center(
child: Text('First Page'),
),
Center(
child: Text('Second Page'),
),
Center(
child: Text('Third Page'),
)
],
);
}
}
And I run it on Android, it works well.
and It works also in web (mobile mode).
But when I run it on chrome (web|desktop) pages are not swipeable, and there is no way to change pages.
How to enable swipe on web desktop export?
Flutter version is 2.5.2

Thanks to Bigfoot, For support swipe with mouse, we need to change default scroll behavior of app by these steps:
1- Create a class, extend it from MaterialScrollBeavior, and override dragDevices:
class AppScrollBehavior extends MaterialScrollBehavior {
#override
Set<PointerDeviceKind> get dragDevices => {
PointerDeviceKind.touch,
PointerDeviceKind.mouse,
};
}
2- Pass an AppScrollBehavior instance to scrollBehavior property of MaterialApp:
MaterialApp(
scrollBehavior: AppScrollBehavior(),
...
);
After that, we can swipe between pages also with mouse.
Update Flutter 3.3:
From flutter 3.3, trackpad on laptops not working for scroll and swipe actions, if you need to support trackpad too, you need add PointerDeviceKind.trackpad to dragDevices like this:
class AppScrollBehavior extends MaterialScrollBehavior {
#override
Set<PointerDeviceKind> get dragDevices => {
PointerDeviceKind.touch,
PointerDeviceKind.mouse,
PointerDeviceKind.trackpad,
};
}

on flutter 2.5.0 they change the scroll behavior
check this Default drag scrolling devices

Without creating additional classes and other stuff, you can do this:
ScrollConfiguration(
behavior: ScrollConfiguration.of(context).copyWith(
dragDevices: {
PointerDeviceKind.touch,
PointerDeviceKind.mouse,
},
),
child: MyScrollableWidget(...)

I used PageView in my Flutter portfolio website. I noticed that I couldn't swipe to change pages. Later I came to know that this could be done by my Mac's trackpad gestures.
Since the PageView was horizontal, I had to horizontally swipe two fingers on my trackpad. You can try that.

Related

How to show a persistant BottomModalSheet that remains in all tabs

I'm creating an app that requires a bottomModalSheet to stay persistant in all (Bottom) tabs regardless of which one I select.
I've gotten it to work on a single BottomTab, but once I click on the other it loses it's state and the Modal is gone as well.
I'm using GoRouter for routing, modal_bottom_sheet for the modalBottomSheet.
BTW I've added BottomSheet on the Main Scaffold.
Problem is I can't go on any other screen from that bottomSheet(They come behind it rather than on top of it)
You can use bottomSheet property of Scaffold.
class Sample extends StatefulWidget {
const Sample({Key? key}) : super(key: key);
#override
State<Sample> createState() => _SampleState();
}
class _SampleState extends State<Sample> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
bottom: TabBar(tabs: [],),
),
body: TabBarView(children: [],),
// add your bottomModelSheet widget here
bottomSheet: MyCustomWidget(),
);
}
}

Flutter page dragging functionalities

Hello flutter developers,
I am trying to develop a project which has dragging functionalities.
Here is the demo
Here i have three page. On page A when i swipe from left to right page B will appear from left of the screen but the page transition will be like i'm actually dragging the page. And when i swipe right to left page C will appear.
If someone could provide me any idea like how can i achieve that or any documentation be appreciated.
You should try PageView.builder widget. Here is some example code that has three centered text widgets passed as a list to the PageView. You would provide the list of your A, B & C pages.
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Hello World',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyStatelessWidget(),
);
}
}
class MyStatelessWidget extends StatelessWidget {
const MyStatelessWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
final PageController controller = PageController();
return Scaffold(
body: PageView(
/// [PageView.scrollDirection] defaults to [Axis.horizontal].
/// Use [Axis.vertical] to scroll vertically.
// scrollDirection: Axis.vertical,
controller: controller,
children: const <Widget>[
Center(
child: Text('First Page'),
),
Center(
child: Text('Second Page'),
),
Center(
child: Text('Third Page'),
)
],
),
);
}
}
For further reference and to read more about its several properties, you may refer to the official documentation here: Official Flutter PageView Doc or a Medium article here: A bit advanced usage of PageView
You can use page view to achieve this layout
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: 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({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
final PageController controller = PageController();
return PageView(
controller: controller,
children: [
Center(
child: Text('First Page'),
),
Center(
child: Text('Second Page'),
),
Center(
child: Text('Third Page'),
)
],
);
}
}

Process of developing a custom widget in Flutter

I am learning Android app development using Dart/Flutter and I am trying to understand the general process of developing a custom widget for an app. For example, if I need a widget that has a TextField, an Image, and a checkbox, how do I test that widget individually?
I mean, there is no app to put that widget in as of now, so how do I "execute" it to see if that widget is getting laid out correctly and working properly as expected?
In the Java Swing world, I would just put a main method in my component class. In that main method, I would create a frame or something and add that component to that frame. Then run that class directly. That way, I can basically fine tune the component without worrying about running the actual application, and without having to go through the whole app flow to reach that component and check how it looks.
Is it similar in Flutter app as well? Create a dummy app with the widget as the only "screen" and then execute that dummy app?
There is an excellent online tool called "Dart Pad", the link here should get you started on basic boilerplate code that is the beginnings of your app.
You can then proceed to create a custom widget, I'll try and replicate your example widget below:
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
/// This is the main application widget.
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: 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 Center(
child: MyStatefulWidget(),
),
),
);
}
}
/// This is the stateful widget that the main application instantiates.
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({Key? key}) : super(key: key);
#override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
/// This is the private State class that goes with MyStatefulWidget.
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
bool isChecked = false;
#override
Widget build(BuildContext context) {
Color getColor(Set<MaterialState> states) {
const Set<MaterialState> interactiveStates = <MaterialState>{
MaterialState.pressed,
MaterialState.hovered,
MaterialState.focused,
};
if (states.any(interactiveStates.contains)) {
return Colors.blue;
}
return Colors.red;
}
return Container(
child: Column(
children: [
Image.network("https://icatcare.org/app/uploads/2018/07/Thinking-of-getting-a-cat.png"),
TextField(decoration: InputDecoration(hintText: "Type something")),
Checkbox(
checkColor: Colors.white,
fillColor: MaterialStateProperty.resolveWith(getColor),
value: isChecked,
onChanged: (bool? value) {
setState(
() {
isChecked = value!;
},
);
},
),
],
),
);
}
}

How to re-render the whole Flutter app on some event?

Is there a recommended way how to force the whole Flutter app to re-render during runtime but without losing state?
I need to update the app according to the back-end response, and I can't use the regular approaches (updating the widget state, inherited widget - provider pattern, etc.). More precisely, the data I need to update is shown on the UI via one Flutter package that does not provide the ability to trigger re-rendering in case of change (data is loaded just once on startup).
In other words, is the below-posted solution valid? Are there any known drawbacks of this approach? Can I crash the app forcing re-rendering this way?
import 'package:flutter/material.dart';
main() {
runApp(Wrapper(child: MyApp()));
}
class Wrapper extends StatelessWidget {
final Widget child;
Wrapper({Key? key, required this.child}) : super(key: key);
updateIfNeeded(BuildContext context) {
// faking some API call...
Future.delayed(Duration(seconds: 5), () {
void rebuild(Element el) {
el.markNeedsBuild(); // can something go wrong here?
el.visitChildren(rebuild);
}
(context as Element).visitChildren(rebuild);
});
}
#override
Widget build(BuildContext context) {
updateIfNeeded(context);
return child;
}
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Wrapper(
child: MaterialApp(
title: 'Flutter App',
theme: ThemeData(primarySwatch: Colors.blue),
home: Scaffold(
appBar: AppBar(title: Text('Home Page')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[Text('Some content...')],
),
),
),
),
);
}
}
You can use a global key and assign it to MaterialApp key and change it's value whenever you want to refresh the app

PageView widget in vertical wrapped in Scrollbar Widget

I'm trying to implement a list of image arranged in a column vertically. I used PageView Widget to make use of the PageChange listener to indicate what current page I currently am. However I am implementing this in WebView as well so I need to wrap it in ScrollBar. Although the Scrollbar is showing and moving accordingly, it is not draggable or not automatically scrolling if I used the ScrollBar. Is theres a work around this or a solution?
You have to pass the controller for the Scrollbar widget with the same controller of PageView widget.
Define a PageController
final PageController pageController = PageController(initialPage: 0);
Pass the pageController to the controller property of Scrollbar widget.
return Scrollbar(
controller: pageController,
isAlwaysShown: true, // This forces the scrollbar to be visible always
child: PageView(
scrollDirection: Axis.vertical,
controller: pageController,
You can set other properties like thickness and hoverthickness to addjust the thickness of the scroll bar. Refer this youtube video and documentation for more details.
A working demo. Also available as a dartpad here:
/// Flutter code sample for PageView
// Here is an example of [PageView]. It creates a centered [Text] in each of the three pages
// which scroll horizontally.
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
/// This is the main application widget.
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: 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(),
),
);
}
}
/// This is the stateless widget that the main application instantiates.
class MyStatelessWidget extends StatelessWidget {
const MyStatelessWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
final PageController pageController = PageController(initialPage: 0);
return Scrollbar(
controller: pageController,
isAlwaysShown: true,
thickness: 10,
showTrackOnHover: true,
hoverThickness: 15,
radius: Radius.circular(0),
child: PageView(
scrollDirection: Axis.vertical,
controller: pageController,
children: const <Widget>[
Center(
child: Text('First Page'),
),
Center(
child: Text('Second Page'),
),
Center(
child: Text('Third Page'),
)
],
),
);
}
}