Created
December 18, 2022 10:15
-
-
Save takenoto/236ec359fe7bf2008a9e81c7cc6f3853 to your computer and use it in GitHub Desktop.
flutter_web horizontal scroll @ SingleChildScrollView, ListView
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/gestures.dart'; | |
import 'package:flutter/material.dart'; | |
void main() => runApp(MyApp()); | |
// Essa primeira mudança é pra permitir o scroll | |
// ref1: https://docs.flutter.dev/release/breaking-changes/default-scroll-behavior-drag | |
// ref2: https://stackoverflow.com/questions/69232764/flutter-web-cannot-scroll-with-mouse-down-drag-flutter-2-5 | |
// Basicamente nas versões anteriores do Flutter ele suportava normalmente que a lista fosse arrastada com o mouse. | |
// Ou seja, é um detalhe específico do Flutter, e diz respeito ao uso de mouse, não a ser web ou mobile. | |
// Na documentação diz que fizeram a mudança porque se a pessoa quisesse por exemplo permitir a seleção de texto | |
// em um card em uma lista horizontal, era impossível. | |
// O que vai ser feito aqui é dar um override global nas listas para que elas possam ser scrolladas clicando e arrastando com | |
// o mouse. Caso vc queira implementar isso em apenas algumas listas específicas, vai precisar dar um override local. | |
// tanto no stackoverflow quanto na doc (refs 2 e 1) tem exemplos disso sendo feito. | |
// É útil quando por exemplo vc só quiser que as listas horizontais sejam scrollaveis com o clique, o resto | |
// pode ser com a roda do mouse mesmo. | |
// Copiado da doc [ref1]: | |
class MyCustomScrollBehavior extends MaterialScrollBehavior { | |
// Override behavior methods and getters like dragDevices | |
@override | |
Set<PointerDeviceKind> get dragDevices => { | |
PointerDeviceKind.touch, | |
PointerDeviceKind.mouse, | |
// etc. | |
}; | |
} | |
class MyApp extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp( | |
title: 'Flutter Demo', | |
debugShowCheckedModeBanner: false, | |
//-------------------------- | |
// É aqui a mudança que falei | |
// Você tá dando override no ScrollBehavior DA APLICAÇÃO INTEIRA!!! | |
scrollBehavior: MyCustomScrollBehavior(), | |
home: const MyHomePage(), | |
); | |
} | |
} | |
class MyHomePage extends StatefulWidget { | |
const MyHomePage({ | |
Key? key, | |
}) : super(key: key); | |
@override | |
State<MyHomePage> createState() => _MyHomePageState(); | |
} | |
class _MyHomePageState extends State<MyHomePage> { | |
// Essa primeira parte é apenas pra fornecer tanto uma ListView.builder quanto um SingleChildScrollView | |
// pra vc ver a diferença. | |
// No geral a performance do ListView.builder é melhor por poder renderizar apenas os itens que estão na tela, | |
// enquanto o SingleChildScrollView vai renderizar tudo e deixar vc scrollar tudo duma vez também. | |
// Então quanto mais itens menos vale à pena o SingleChildScrollView. | |
// Index para dizer se vai ser SingleChildScrollView ou ListView | |
int scrollerChildIndex = 0; | |
String scrollerChildDescriptionText() => scrollerChildIndex==0?"SingleChildScrollView preserva o tamanho no eixo oposto ao da rolagem":"ListView.builder obriga a preencher todo o espaço do crossAxis (eixo oposto ao da rolagem). Se quiser manter o tamanho normal vc pode colocar dentro de um Center por exemplo."; | |
final _scrollerChildrenOptions = [ | |
SingleChildScrollView( | |
scrollDirection: Axis.horizontal, | |
child: Row( | |
children: [ | |
// Cria 5 FilterTags | |
for(int i=0; i<16; i++) FilterTag('tag nº $i'), | |
] | |
) | |
), | |
ListView.builder( | |
scrollDirection: Axis.horizontal, | |
itemBuilder: (context, i) => FilterTag('tag nº ${i+1}'), | |
itemCount:15, | |
) | |
]; | |
// Função para alternar entre os dois tipos de scroller que falei | |
void _swapScroller(){ | |
if(scrollerChildIndex == 0){ | |
scrollerChildIndex=1; | |
} else if(scrollerChildIndex == 1){ | |
scrollerChildIndex=0; | |
} | |
setState((){}); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: AppBar( | |
title: const Text('Teste scroll'), | |
), | |
body: Column( | |
children:[ | |
Container( | |
padding: const EdgeInsets.all(16), | |
color: Colors.yellow[200], | |
child:Center( | |
child: Text(scrollerChildDescriptionText(), | |
), | |
), | |
), | |
Expanded( | |
child: _scrollerChildrenOptions[scrollerChildIndex] | |
), | |
Container( | |
padding: const EdgeInsets.all(32), | |
color: Colors.purple[200], | |
child: const Center( | |
child: Text('Seção inferior da tela') , | |
), | |
), | |
], | |
), | |
floatingActionButton: FloatingActionButton( | |
onPressed: _swapScroller, | |
tooltip: 'Increment', | |
child: const Text('Change'), | |
), | |
); | |
} | |
} | |
// Classe FilterTag para simular a sua | |
class FilterTag extends StatelessWidget{ | |
final String tagText; | |
const FilterTag(this.tagText); | |
@override | |
Widget build(BuildContext context){ | |
return Container( | |
padding: const EdgeInsets.all(8), | |
color: Colors.green[300], | |
child: Text(tagText) | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment