I added a pageview (with a snap) to the body of a scaffold. I'd like users to scroll pages down only, not up. Can you please help? Thanks
Asked
Active
Viewed 353 times
2 Answers
1
By making custom scroll physics extends from ScrollPhysics, you can like below.
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
void initState() {
super.initState();
}
emailAuthSheet(BuildContext context) {
return showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (context) {
return Container(
child: Wrap(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 150.0),
child: Divider(
thickness: 4.0,
),
),
Container(height: 450, color: Colors.blue[100]),
// Provider.of<LandingService>(context,listen: false).passwordLessSignIn(context),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
MaterialButton(
child: Text(
'Log in',
style: TextStyle(
fontSize: 18.0, fontWeight: FontWeight.bold),
),
onPressed: () {}),
MaterialButton(
child: Text(
'Sign in',
style: TextStyle(
fontSize: 18.0, fontWeight: FontWeight.bold),
),
onPressed: () {})
],
),
],
),
);
},
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: _buildBody(),
floatingActionButton: FloatingActionButton(
onPressed: () {
emailAuthSheet(context);
},
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
Widget _buildBody() {
return PageView(
scrollDirection: Axis.vertical,
physics: CustomScrollPhysics(),
children: [
Container(
height: 500,
color: Colors.red,
child: Center(
child: Text(
'Page index : 0',
style: TextStyle(fontSize: 20),
),
),
),
Container(
height: 500,
color: Colors.yellow,
child: Center(
child: Text(
'Page index : 1',
style: TextStyle(fontSize: 20),
),
),
),
Container(
height: 500,
color: Colors.red,
child: Center(
child: Text(
'Page index : 2',
style: TextStyle(fontSize: 20),
),
),
),
Container(
height: 500,
color: Colors.yellow,
child: Center(
child: Text(
'Page index : 3',
style: TextStyle(fontSize: 20),
),
),
),
],
);
}
}
class CustomScrollPhysics extends ScrollPhysics {
CustomScrollPhysics({ScrollPhysics parent}) : super(parent: parent);
bool isUp = false;
@override
CustomScrollPhysics applyTo(ScrollPhysics ancestor) {
return CustomScrollPhysics(parent: buildParent(ancestor));
}
@override
double applyPhysicsToUserOffset(ScrollMetrics position, double offset) {
isUp = offset.sign < 0;
return offset;
}
@override
double applyBoundaryConditions(ScrollMetrics position, double value) {
assert(() {
if (value == position.pixels) {
throw FlutterError(
'$runtimeType.applyBoundaryConditions() was called redundantly.\n'
'The proposed new position, $value, is exactly equal to the current position of the '
'given ${position.runtimeType}, ${position.pixels}.\n'
'The applyBoundaryConditions method should only be called when the value is '
'going to actually change the pixels, otherwise it is redundant.\n'
'The physics object in question was:\n'
' $this\n'
'The position object in question was:\n'
' $position\n');
}
return true;
}());
if (value < position.pixels && position.pixels <= position.minScrollExtent)
return value - position.pixels;
if (position.maxScrollExtent <= position.pixels && position.pixels < value)
return value - position.pixels;
if (value < position.minScrollExtent &&
position.minScrollExtent < position.pixels)
return value - position.minScrollExtent;
if (position.pixels < position.maxScrollExtent &&
position.maxScrollExtent < value)
return value - position.maxScrollExtent;
if (!isUp) {
return value - position.pixels;
}
return 0.0;
}
}

KuKu
- 6,654
- 1
- 13
- 25
-
your solution worked for me too but Ruchit replied first therefore I accepted their answer. Thanks – jennie788 Aug 23 '21 at 05:25
-
Sure~ No problem. Before I upload solution after I made a sample code, I found same solution. – KuKu Aug 23 '21 at 05:40
0
you can easily do it with custom scroll physics as shown below,
add CustomScrollPhysics()
as physics of your PageView()
,
PageView(
scrollDirection: Axis.vertical,
physics: CustomScrollPhysics(), <--- here!!
controller: controller,
children: <Widget>[
//childrens
],
);
create CustomScrollPhysycs()
that only scroll down,
class CustomScrollPhysics extends ScrollPhysics {
CustomScrollPhysics({ScrollPhysics parent}) : super(parent: parent);
bool isGoingDown = false;
@override
CustomScrollPhysics applyTo(ScrollPhysics ancestor) {
return CustomScrollPhysics(parent: buildParent(ancestor));
}
@override
double applyPhysicsToUserOffset(ScrollMetrics position, double offset) {
isGoingDown = offset.sign < 0;
return offset;
}
@override
double applyBoundaryConditions(ScrollMetrics position, double value) {
//print("applyBoundaryConditions");
assert(() {
if (value == position.pixels) {
throw FlutterError(
'$runtimeType.applyBoundaryConditions() was called redundantly.\n'
'The proposed new position, $value, is exactly equal to the current position of the '
'given ${position.runtimeType}, ${position.pixels}.\n'
'The applyBoundaryConditions method should only be called when the value is '
'going to actually change the pixels, otherwise it is redundant.\n'
'The physics object in question was:\n'
' $this\n'
'The position object in question was:\n'
' $position\n');
}
return true;
}());
if (value < position.pixels && position.pixels <= position.minScrollExtent)
return value - position.pixels;
if (position.maxScrollExtent <= position.pixels && position.pixels < value)
// overscroll
return value - position.pixels;
if (value < position.minScrollExtent &&
position.minScrollExtent < position.pixels) // hit top edge
return value - position.minScrollExtent;
if (position.pixels < position.maxScrollExtent &&
position.maxScrollExtent < value) // hit bottom edge
return value - position.maxScrollExtent;
if (!isGoingDown) {
return value - position.pixels;
}
return 0.0;
}
}

Ruchit
- 2,137
- 1
- 9
- 24