J'ai un PageView, comment puis-je désactiver le défilement gauche ou droit. Je sais qu'en utilisant NeverScrollableScrollPhysics, nous pouvons désactiver le défilement mais comment désactiver le défilement dans une direction.
3 Réponses :
Vous pouvez créer votre propre ScrollPhysics
pour autoriser uniquement à aller vers la droite:
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(), body: PageView.builder( itemCount: 4, physics: CustomScrollPhysics(), itemBuilder: (context, index) => Center( child: Text("Item $index"), ), )); }
Usage:
class CustomScrollPhysics extends ScrollPhysics { CustomScrollPhysics({ScrollPhysics parent}) : super(parent: parent); bool isGoingLeft = false; @override CustomScrollPhysics applyTo(ScrollPhysics ancestor) { return CustomScrollPhysics(parent: buildParent(ancestor)); } @override double applyPhysicsToUserOffset(ScrollMetrics position, double offset) { isGoingLeft = 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 (!isGoingLeft) { return value - position.pixels; } return 0.0; } }
Obtenir This class (or a class which this class inherits from) is marked as '@immutable', but one or more of its instance fields are not final: CustomScrollPhysics.isGoingLeft
Des idées? Je suppose que je ne peux pas rendre isGoingLeft final.
Bonjour, comment ajuster le code pour gérer un défilement vertical dans une direction (vers le bas)? Merci
Vous pouvez également utiliser la bibliothèque horizontale_blocked_scroll_physics que j'ai récemment écrite qui vous permettra de bloquer les mouvements gauche et droit.
Est venu avec une approche légèrement meilleure pour cela.
Cette approche ne nécessite pas d'instanciation de nouvelles instances physiques et peut être mise à jour dynamiquement.
Utilisez le paramètre de fonction onAttemptDrag
pour autoriser ou refuser les demandes de balayage. Votre code dans cette fonction devrait être efficace car il sera appelé plusieurs fois par seconde (lors du défilement). En outre, vous souhaiterez peut-être ajouter un indicateur dans cette fonction qui autorise les demandes d'origine programmatique à passer. Par exemple, dans le cas d'un "bouton suivant", cette implémentation physique empêcherait également les fonctions jumpTo(..)
et animateTo
de fonctionner, vous auriez donc besoin d'un indicateur qui renverra temporairement une valeur par défaut true
pour un transition de page si le bouton suivant a été enfoncé. Faites-moi savoir si vous avez des questions ou comment améliorer cela.
class LockingPageScrollPhysics extends ScrollPhysics { /// Requests whether a drag may occur from the page at index "from" /// to the page at index "to". Return true to allow, false to deny. final Function(int from, int to) onAttemptDrag; /// Creates physics for a [PageView]. const LockingPageScrollPhysics( {ScrollPhysics parent, @required this.onAttemptDrag}) : super(parent: parent); @override LockingPageScrollPhysics applyTo(ScrollPhysics ancestor) { return LockingPageScrollPhysics( parent: buildParent(ancestor), onAttemptDrag: onAttemptDrag); } double _getPage(ScrollMetrics position) { if (position is PagePosition) return position.page; return position.pixels / position.viewportDimension; } double _getPixels(ScrollMetrics position, double page) { if (position is PagePosition) return position.getPixelsFromPage(page); return page * position.viewportDimension; } double _getTargetPixels( ScrollMetrics position, Tolerance tolerance, double velocity) { double page = _getPage(position); if (velocity < -tolerance.velocity) page -= 0.5; else if (velocity > tolerance.velocity) page += 0.5; return _getPixels(position, page.roundToDouble()); } @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; }()); /* * Handle the hard boundaries (min and max extents) * (identical to ClampingScrollPhysics) */ if (value < position.pixels && position.pixels <= position.minScrollExtent) // under-scroll return value - position.pixels; if (position.maxScrollExtent <= position.pixels && position.pixels < value) // over-scroll 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; bool left = value < position.pixels; int fromPage, toPage; double overScroll = 0; if (left) { fromPage = position.pixels.ceil() ~/ position.viewportDimension; toPage = value ~/ position.viewportDimension; overScroll = value - fromPage * position.viewportDimension; overScroll = overScroll.clamp(value - position.pixels, 0.0); } else { fromPage = (position.pixels + position.viewportDimension).floor() ~/ position.viewportDimension; toPage = (value + position.viewportDimension) ~/ position.viewportDimension; overScroll = value - fromPage * position.viewportDimension; overScroll = overScroll.clamp(0.0, value - position.pixels); } if (fromPage != toPage && !onAttemptDrag(fromPage, toPage)) { return overScroll; } else { return super.applyBoundaryConditions(position, value); } }
Voici une bibliothèque sur laquelle j'ai travaillé qui utilise ce contrôleur modifié: https://github.com/RobluScouting/FlutterBoardView .