当前位置:网站首页>Les différents modèles imbriqués de listview et Pageview avec les conseils de flutter
Les différents modèles imbriqués de listview et Pageview avec les conseils de flutter
2022-07-04 09:10:00 【Gsytech】
Cette fois Flutter Le truc, c'est que ListView
Et PageView
Un nid de fantaisie,C'est différent. Scrollable
Le problème des conflits imbriqués, je crois que tout le monde n'est pas étranger,Adopté aujourd'hui ListView
Et PageView
Les trois modèles imbriqués vous permettent de récolter des conseils différents.
Nidification normale
La nidification la plus courante devrait être horizontale PageView
Plus longitudinal ListView
Combinaison de,En général, cette combinaison ne pose aucun problème,À moins que tu ne sois sur le point de glisser.
Récemment, j'ai rencontré plusieurs personnes en même temps:“Glissement oblique ListView
Facile à passer à PageView
Glissez” La question de,Comme suit GIF Comme indiqué,Quand l'utilisateur glisse ListView
Heure,Après l'inclinaison de la ceinture d'angle de glissement,Ce qui pourrait faire glisser PageView
Au lieu de ListView
.
Bien que je ne pense pas personnellement que ce soit un problème,Mais si le produit doit être modifié,Dois - je me réécrire PageView
Est - ce que le geste de?
Jetons un coup d'oeil.,Peu importe. PageView
Toujours ListView
Leur effet de glissement provient de Scrollable
,Et Scrollable
Réponse interne dans différentes directions,C'est par RawGestureDetector
Terminé.:
VerticalDragGestureRecognizer
Gérer les gestes verticauxHorizontalDragGestureRecognizer
Manipuler les gestes horizontaux
Donc, regardez simplement la logique de jugement de leur réponse , Vous pouvez voir une façon très intéressante de computeHitSlop
: Selon pointer Le type détermine le plus petit pixel nécessaire pour frapper , Touch default est kTouchSlop (18.0).
Tu as vu ça? :Si nous mettons PageView
De touchSlop Modifié, Est - il possible d'ajuster la sensibilité de sa réponse ? Juste là. computeHitSlop
Méthode,Il peut passer par DeviceGestureSettings
Pour configurer,Et DeviceGestureSettings
De MediaQuery
,Donc le code suivant:
body: MediaQuery( ///Élévation touchSlop À 50 ,Voilà. pageview Le glissement peut avoir un peu d'effet , /// Mais le taux approximatif a résolu le problème du déclenchement par glissement oblique data: MediaQuery.of(context).copyWith( gestureSettings: DeviceGestureSettings( touchSlop: 50, )), child: PageView( scrollDirection: Axis.horizontal, pageSnapping: true, children: [ HandlerListView(), HandlerListView(), ], ),),
Petit conseil 1: En imbriquant un MediaQuery
,Et ajuster gestureSettings
De touchSlop
Pour modifier PageView
La spiritualité de ,Et n'oubliez pas,Il faut aussi ListView
De touchSlop
Basculer par défaut De kTouchSlop
:
class HandlerListView extends StatefulWidget { @override _MyListViewState createState() => _MyListViewState();}class _MyListViewState extends State<HandlerListView> { @override Widget build(BuildContext context) { return MediaQuery( ///Ici. touchSlop Besoin de revenir à la valeur par défaut data: MediaQuery.of(context).copyWith( gestureSettings: DeviceGestureSettings( touchSlop: kTouchSlop, )), child: ListView.separated( itemCount: 15, itemBuilder: (context, index) { return ListTile( title: Text('Item $index'), ); }, separatorBuilder: (context, index) { return const Divider( thickness: 3, ); }, ), ); }}
Enfin, regardons l'effet,Comme suit GIF Comme indiqué, Maintenant, même si tu glisses en diagonale , Ça déclenche aussi PageView
Glissement horizontal de , Déclenché uniquement en mouvement latéral PageView
Un geste.,Bien sûr., S'il y a un problème avec cette écriture grossière , Ça a dû baisser PageView
Sensibilité de la réponse .
Dans la même direction PageView Nidification ListView
Après l'introduction de l'utilisation régulière , Et puis quelque chose de différent , Dans le passage vertical PageView
Imbriqué de rouleaux verticaux ListView
, Avez - vous d'abord l'impression de ne pas être fiable ,Pourquoi y a - t - il une telle scène??
Pour les produits, Ils ne se pencheront pas sur la façon dont vous , Ils se tapaient la tête et disaient que Taobao pouvait , Pourquoi tu ne peux pas , Donc si c'était toi ,Que feriez - vous??
Et à propos de ce besoin , Les résultats des discussions en cours dans la communauté sont les suivants: :Prends ça. PageView
Et ListView
Diapositive désactivée pour ,Et à travers RawGestureDetector
Autogestion.
Si vous n'êtes pas intéressé à réaliser une analyse logique , Vous pouvez regarder directement à la fin de cette section Lien source .
Ne paniquez pas avant de vous voir gérer. , Bien que vous deviez le faire vous - même PageView
Et ListView
La distribution des gestes , Mais il n'y a pas de réécriture nécessaire. PageView
Et ListView
, On peut les réutiliser. Darg
Logique de réponse,Le code ci - dessous:
- Adoption
NeverScrollableScrollPhysics
C'est interdit.PageView
EtListView
L'effet de défilement de - En haut
RawGestureDetector
DeVerticalDragGestureRecognizer
Gérer les événements gestuels par vous - même - Configuration
PageController
EtScrollController
Pour obtenir l'état
body: RawGestureDetector( gestures: <Type, GestureRecognizerFactory>{ VerticalDragGestureRecognizer: GestureRecognizerFactoryWithHandlers< VerticalDragGestureRecognizer>( () => VerticalDragGestureRecognizer(), (VerticalDragGestureRecognizer instance) { instance ..onStart = _handleDragStart ..onUpdate = _handleDragUpdate ..onEnd = _handleDragEnd ..onCancel = _handleDragCancel; }) }, behavior: HitTestBehavior.opaque, child: PageView( controller: _pageController, scrollDirection: Axis.vertical, /// Masque la réponse de glissement par défaut physics: const NeverScrollableScrollPhysics(), children: [ ListView.builder( controller: _listScrollController, /// Masque la réponse de glissement par défaut physics: const NeverScrollableScrollPhysics(), itemBuilder: (context, index) { return ListTile(title: Text('List Item $index')); }, itemCount: 30, ), Container( color: Colors.green, child: Center( child: Text( 'Page View', style: TextStyle(fontSize: 50), ), ), ) ], ),),
Alors regardons _handleDragStart
Réalisation,Le code ci - dessous, En générant des gestes details
Heure, Notre jugement principal :
- Adoption
ScrollController
JugementListView
Visible ou non - Déterminer si la position tactile est
ListIView
Dans le champ d'application - Déterminer par statut
Controller
Pour produireDrag
Objet, Utilisé en réponse à des événements de glissement ultérieurs
void _handleDragStart(DragStartDetails details) { ///Juge d'abord Listview Est visible ou peut être appelé /// Généralement invisible hasClients false ,Parce que PageView Pas du tout. keepAlive if (_listScrollController?.hasClients == true && _listScrollController?.position.context.storageContext != null) { ///Accès ListView De renderBox final RenderBox? renderBox = _listScrollController ?.position.context.storageContext .findRenderObject() as RenderBox; /// Déterminer si la position du toucher est ListView Intérieur /// Ce n'est généralement pas le cas parce que ListView Ça a glissé , Les coordonnées ne correspondent pas à la position tactile if (renderBox?.paintBounds .shift(renderBox.localToGlobal(Offset.zero)) .contains(details.globalPosition) == true) { _activeScrollController = _listScrollController; _drag = _activeScrollController?.position.drag(details, _disposeDrag); return; } } /// C'est le moment de penser PageView Besoin de glisser _activeScrollController = _pageController; _drag = _pageController?.position.drag(details, _disposeDrag); }
Devant nous, on commence surtout par toucher , Lors de la détermination de l'objet à répondre ListView
Toujours PageView
,Et à travers _activeScrollController
Enregistrer l'objet de réponse bien sûr ,Et à travers Controller Générer un Drag
Objet.
En termes simples: Au moment de l'événement de glissement , Par défaut, un
Drag
Utilisé pour gérer les événements de glissement ultérieurs ,Drag
L'événement original sera traité avant d'être donné àScrollPosition
Pour déclencher un effet de glissement ultérieur .
Et puis... _handleDragUpdate
Méthode, Il s'agit principalement de déterminer si la réponse doit passer à PageView
:
- Si ce n'est pas nécessaire, continuez avec ce que vous avez
_drag?.update(details)
RéponseListView
Rouler - Passez si nécessaire
_pageController
Changer de_drag
Objet utilisé pour répondre
void _handleDragUpdate(DragUpdateDetails details) { if (_activeScrollController == _listScrollController && ///Les doigts se déplacent vers le Haut, C'est - à - dire qu'il va bientôt montrer le bas PageView details.primaryDelta! < 0 && /// En bas ,Passer à PageView _activeScrollController?.position.pixels == _activeScrollController?.position.maxScrollExtent) { /// Basculer le Contrôleur approprié _activeScrollController = _pageController; _drag?.cancel(); ///RÉFÉRENCES Scrollable - Oui. /// Parce que c'est le Contrôleur de commutation , C'est - à - dire mettre à jour Drag /// Le processus de glisser - déposer passe à PageView - Oui.,Il faut donc DragStartDetails ///Il faut donc DragUpdateDetails Devenir DragStartDetails ///Extrait PageView À l'intérieur. Drag Correspondant details _drag = _pageController?.position.drag( DragStartDetails( globalPosition: details.globalPosition, localPosition: details.localPosition), _disposeDrag); } _drag?.update(details);}
Voici un petit point de connaissance:Comme indiqué dans le code ci - dessus, On peut passer par
details.primaryDelta
Déterminer si la direction de glissement et le mouvement sont la broche
Enfin: GIF Comme indiqué,Je vois. PageView
Nidification ListView
Le glissement dans la même direction peut fonctionner normalement , Mais il y a encore deux petits problèmes ,Comme le montre l'illustration:
- Après le basculement
ListView
L'emplacement n'a pas été sauvegardé - Le produit doit être retiré
ListView
Effet de débordement de bord de
C'est pourquoi nous devons avoir raison. ListView
Fais - en un. KeepAlive , Et l'enlever d'une manière simple Android Les bords glissent Material Effets:
- Adoption
with AutomaticKeepAliveClientMixin
JeanListView
Maintenir également la position de glissement après la commutation - Adoption
ScrollConfiguration.of(context).copyWith(overscroll: false)
Enlèvement rapide Scrollable Le bord de Material Effets
child: PageView( controller: _pageController, scrollDirection: Axis.vertical, ///Enlevez Android Effet de traînée de bord par défaut sur scrollBehavior: ScrollConfiguration.of(context).copyWith(overscroll: false),///C'est exact. PageView À l'intérieur. ListView Fais - le. KeepAlive Rappelez - vous la position class KeepAliveListView extends StatefulWidget { final ScrollController? listScrollController; final int itemCount; KeepAliveListView({ required this.listScrollController, required this.itemCount, }); @override KeepAliveListViewState createState() => KeepAliveListViewState();}class KeepAliveListViewState extends State<KeepAliveListView> with AutomaticKeepAliveClientMixin { @override Widget build(BuildContext context) { super.build(context); return ListView.builder( controller: widget.listScrollController, /// Masque la réponse de glissement par défaut physics: const NeverScrollableScrollPhysics(), itemBuilder: (context, index) { return ListTile(title: Text('List Item $index')); }, itemCount: widget.itemCount, ); } @override bool get wantKeepAlive => true;}
Donc voici un autre petit truc pour déverrouiller :Adoption ScrollConfiguration.of(context).copyWith(overscroll: false)
Enlèvement rapide Android Glissez sur le bord Material 2Effets,Pourquoi dire Material2, Parce que Material3 Ça a changé. ,Les détails sont visibles: Flutter 3 En bas ThemeExtensions Et Material3 .
Le code source de cette sous - section est visible : https://github.com/CarGuo/gsy_flutter_demo/blob/7838971cefbf19bb53a71041cd100c4c15eb6443/lib/widget/vp_list_demo_page.dart#L75
Dans la même direction ListView Nidification PageView
Y a - t - il quelque chose de plus inhabituel? ?La réponse est oui., Après tout, la petite tête du produit , Comment peut - on imaginer En glissant verticalement ListView
Imbriqué verticalement commuté PageView
Ce besoin.
Avec les idées qui précèdent , En fait, la mise en oeuvre de cette logique est aussi différente :Prends ça. PageView
Et ListView
Diapositive désactivée pour ,Et à travers RawGestureDetector
Autogestion, La différence est la différence dans la distribution des méthodes gestuelles .
RawGestureDetector( gestures: <Type, GestureRecognizerFactory>{ VerticalDragGestureRecognizer: GestureRecognizerFactoryWithHandlers< VerticalDragGestureRecognizer>( () => VerticalDragGestureRecognizer(), (VerticalDragGestureRecognizer instance) { instance ..onStart = _handleDragStart ..onUpdate = _handleDragUpdate ..onEnd = _handleDragEnd ..onCancel = _handleDragCancel; }) }, behavior: HitTestBehavior.opaque, child: ListView.builder( /// Masque la réponse de glissement par défaut physics: NeverScrollableScrollPhysics(), controller: _listScrollController, itemCount: 5, itemBuilder: (context, index) { if (index == 0) { return Container( height: 300, child: KeepAlivePageView( pageController: _pageController, itemCount: itemCount, ), ); } return Container( height: 300, color: Colors.greenAccent, child: Center( child: Text( "Item $index", style: TextStyle(fontSize: 40, color: Colors.blue), ), )); }), )
Encore une fois, _handleDragStart
Méthode, Il faut d'abord juger :
ListView
Si elle a glissé , Ne répondez pas en hautPageView
Les événements de- Si
ListView
Pas de glissement en haut , Déterminer si la position du geste estPageView
- Oui.,Si c'est une réponsePageView
Les événements de
void _handleDragStart(DragStartDetails details) { /// Tant que ce n'est pas le haut ,Pas de réponse PageView Glissement /// Donc ce jugement ne supporte que la verticale PageView In ListView En haut if (_listScrollController.offset > 0) { _activeScrollController = _listScrollController; _drag = _listScrollController.position.drag(details, _disposeDrag); return; } ///En ce moment ListView En haut if (_pageController.hasClients) { ///Accès PageView final RenderBox renderBox = _pageController.position.context.storageContext.findRenderObject() as RenderBox; /// Déterminer si la plage de toucher est PageView final isDragPageView = renderBox.paintBounds .shift(renderBox.localToGlobal(Offset.zero)) .contains(details.globalPosition); ///Si dans PageView Ça passe à PageView if (isDragPageView) { _activeScrollController = _pageController; _drag = _activeScrollController.position.drag(details, _disposeDrag); return; } } ///Non. PageView Li continue à répondre ListView _activeScrollController = _listScrollController; _drag = _listScrollController.position.drag(details, _disposeDrag); }
Et puis... _handleDragUpdate
Méthode,Juge si PageView
A glissé jusqu'à la dernière page , Basculer également l'événement de glissement vers ListView
void _handleDragUpdate(DragUpdateDetails details) { var scrollDirection = _activeScrollController.position.userScrollDirection; /// Déterminer si la réponse est toujours _pageController, C'est la dernière page? if (_activeScrollController == _pageController && scrollDirection == ScrollDirection.reverse && /// C'est la dernière page? , Retour à la dernière page pageController (_pageController.page != null && _pageController.page! >= (itemCount - 1))) { ///Revenir en arrière ListView _activeScrollController = _listScrollController; _drag?.cancel(); _drag = _listScrollController.position.drag( DragStartDetails( globalPosition: details.globalPosition, localPosition: details.localPosition), _disposeDrag); } _drag?.update(details);}
Bien sûr.,Encore une fois. KeepAlive Et supprimer la liste Material Effets de bord ,L'effet final est le suivant GIF Comme indiqué.
Le code source de cette sous - section est visible :https://github.com/CarGuo/gsy_flutter_demo/blob/7838971cefbf19bb53a71041cd100c4c15eb6443/lib/widget/vp_list_demo_page.dart#L262
Un dernier petit conseil. :Si vous avez besoin de Flutter Processus d'impression des jeux de gestes ,Configurable debugPrintGestureArenaDiagnostics = true;
Allez. Flutter Processus de traitement des jeux de gestes de sortie .
import 'package:flutter/gestures.dart';void main() { debugPrintGestureArenaDiagnostics = true; runApp(MyApp());}
Enfin
Pour conclure, Ce chapitre décrit comment passer Darg
Résoudre toutes sortes de conflits de gestes causés par la nidification , Je crois que tout le monde sait comment utiliser Controller
Et Darg
Pour personnaliser rapidement certaines exigences de glissement ,Par exemple ListView
Liaison ListView
L'effet de glissement différentiel de :
///listView Liaison listViewclass ListViewLinkListView extends StatefulWidget { @override _ListViewLinkListViewState createState() => _ListViewLinkListViewState();}class _ListViewLinkListViewState extends State<ListViewLinkListView> { ScrollController _primaryScrollController = ScrollController(); ScrollController _subScrollController = ScrollController(); Drag? _primaryDrag; Drag? _subDrag; @override void initState() { super.initState(); } @override void dispose() { _primaryScrollController.dispose(); _subScrollController.dispose(); super.dispose(); } void _handleDragStart(DragStartDetails details) { _primaryDrag = _primaryScrollController.position.drag(details, _disposePrimaryDrag); _subDrag = _subScrollController.position.drag(details, _disposeSubDrag); } void _handleDragUpdate(DragUpdateDetails details) { _primaryDrag?.update(details); ///Divisé par10 Pour obtenir un effet différentiel _subDrag?.update(DragUpdateDetails( sourceTimeStamp: details.sourceTimeStamp, delta: details.delta / 30, primaryDelta: (details.primaryDelta ?? 0) / 30, globalPosition: details.globalPosition, localPosition: details.localPosition)); } void _handleDragEnd(DragEndDetails details) { _primaryDrag?.end(details); _subDrag?.end(details); } void _handleDragCancel() { _primaryDrag?.cancel(); _subDrag?.cancel(); } void _disposePrimaryDrag() { _primaryDrag = null; } void _disposeSubDrag() { _subDrag = null; } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("ListViewLinkListView"), ), body: RawGestureDetector( gestures: <Type, GestureRecognizerFactory>{ VerticalDragGestureRecognizer: GestureRecognizerFactoryWithHandlers< VerticalDragGestureRecognizer>( () => VerticalDragGestureRecognizer(), (VerticalDragGestureRecognizer instance) { instance ..onStart = _handleDragStart ..onUpdate = _handleDragUpdate ..onEnd = _handleDragEnd ..onCancel = _handleDragCancel; }) }, behavior: HitTestBehavior.opaque, child: ScrollConfiguration( ///Enlevez Android Effet de traînée de bord par défaut sur behavior: ScrollConfiguration.of(context).copyWith(overscroll: false), child: Row( children: [ new Expanded( child: ListView.builder( /// Masque la réponse de glissement par défaut physics: NeverScrollableScrollPhysics(), controller: _primaryScrollController, itemCount: 55, itemBuilder: (context, index) { return Container( height: 300, color: Colors.greenAccent, child: Center( child: Text( "Item $index", style: TextStyle( fontSize: 40, color: Colors.blue), ), )); })), new SizedBox( width: 5, ), new Expanded( child: ListView.builder( /// Masque la réponse de glissement par défaut physics: NeverScrollableScrollPhysics(), controller: _subScrollController, itemCount: 55, itemBuilder: (context, index) { return Container( height: 300, color: Colors.deepOrange, child: Center( child: Text( "Item $index", style: TextStyle(fontSize: 40, color: Colors.white), ), ), ); }), ), ], ), ), )); }}
边栏推荐
- Global and Chinese market of sampler 2022-2028: Research Report on technology, participants, trends, market size and share
- Awk from entry to earth (8) array
- Analysis report on the development status and investment planning of China's modular power supply industry Ⓠ 2022 ~ 2028
- awk从入门到入土(15)awk执行外部命令
- "How to connect the network" reading notes - Web server request and response (4)
- 《网络是怎么样连接的》读书笔记 - 认识网络基础概念(一)
- Awk from entry to earth (15) awk executes external commands
- Langage C - démarrer - base - syntaxe - [opérateur, conversion de type] (vi)
- China electronic grade sulfur trioxide Market Forecast and investment strategy report (2022 Edition)
- Global and Chinese markets for laser assisted liposuction (LAL) devices 2022-2028: Research Report on technology, participants, trends, market size and share
猜你喜欢
After unplugging the network cable, does the original TCP connection still exist?
Sequence model
C语言-入门-基础-语法-[标识符,关键字,分号,空格,注释,输入和输出](三)
Langage C - démarrer - base - syntaxe - [opérateur, conversion de type] (vi)
[untitled] forwarding least square method
Awk from entry to earth (12) awk can also write scripts to replace the shell
System disk expansion in virtual machine
Opencv environment construction (I)
GoLand environment variable configuration
Nurse level JDEC addition, deletion, modification and inspection exercise
随机推荐
What is inner connection and outer connection? What are the uses and benefits
Lauchpad X | 模式
awk从入门到入土(12)awk也可以写脚本,替代shell
Target detection -- intensive reading of yolov3 paper
C语言-入门-基础-语法-[主函数,头文件](二)
Démarrage des microservices: passerelle
In depth research and investment strategy report on China's hydraulic parts industry (2022 Edition)
[C Advanced] file operation (2)
Review of last week's hot spots (6.27-7.3)
Industry depression has the advantages of industry depression
C语言-入门-基础-语法-[变量,常亮,作用域](五)
Global and Chinese market of planar waveguide optical splitter 2022-2028: Research Report on technology, participants, trends, market size and share
awk从入门到入土(14)awk输出重定向
High order phase difference such as smear caused by myopic surgery
Basic discipline formula and unit conversion
《网络是怎么样连接的》读书笔记 - FTTH
Talk about single case mode
Awk from entry to earth (7) conditional statements
If you can quickly generate a dictionary from two lists
Report on research and investment prospect prediction of China's electronic grade sulfuric acid industry (2022 Edition)