Flutter NestedScrollView header bounce with TabBar and TabbarView
Flutter NestedScrollView header bounce with TabBar and TabbarView
- header pull to refresh可以在我想拖上去的时候拉上去
- 标签栏置顶。
- ListView 可以滑动到另一个页面。
100% 自定义小部件。它支持更改header值并且支持滑动操作。
它实际上不是 TabBar 小部件,但它的工作方式完全一样
import 'package:flutter/material.dart';
import 'dart:math';
class NestedScrolls extends StatefulWidget {
static const listHeader = ['Pakistan', 'China','Iran','Turkey'];
@override
_NestedScrollsState createState() => _NestedScrollsState();
}
class _NestedScrollsState extends State<NestedScrolls> {
var position=0;
var topHeader;
Widget? applyWidget() {
switch(position){
case 0:
setState(() {
topHeader = NestedScrolls.listHeader[0];
});
// return widget if user click over pakistan in tab bar
return grid();
case 1:
setState(() {
topHeader = NestedScrolls.listHeader[1];
});
return list();
case 2:
setState(() {
topHeader = NestedScrolls.listHeader[2];
});
return Container(color: Colors.blue,
child: Center(child: Text(topHeader),),);
case 3:
setState(() {
topHeader = NestedScrolls.listHeader[3];
});
return Container(color: Colors.orange,
child: Center(child: Text(topHeader),),);
}
}
@override
void initState() {
// TODO: implement initState
super.initState();
//initial header name when activity start first time
topHeader = NestedScrolls.listHeader[0];
}
@override
Widget build(BuildContext context) {
topHeader = topHeader;
return Scaffold(
// Persistent AppBar that never scrolls
appBar: AppBar(
title: Text('AppBar'),
elevation: 0.0,
),
body:
Column(
children: <Widget>[
///header
Container(
alignment: Alignment.center,
color: Colors.blueGrey,
height: 90,
child: Text(NestedScrolls.listHeader[position]),
),
/// tabBar
Container(
height: 60,
width: MediaQuery.of(context).size.width,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: NestedScrolls.listHeader.length,
itemBuilder: (con, index) {
return GestureDetector(
onTap: () => setState(() {
position=index;
topHeader = NestedScrolls.listHeader[index];
}),
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 2.0, horizontal: 10),
child: Container(alignment: Alignment.center,
width: 100,
color: topHeader==NestedScrolls.listHeader[index]?Colors.black26:Colors.transparent,
child: Text(NestedScrolls.listHeader[index])),
),
);
}),
),
///Widget
Expanded(
child: GestureDetector(
// onHorizontalDragStart: (left){
// print('left : ${left.localPosition.direction}');
// // left.globalPosition.dx
//
// },
onHorizontalDragEnd: (start){
print('start : ${start.velocity.pixelsPerSecond.dx}');
if((start.velocity.pixelsPerSecond.dx)<-700){
if(position<NestedScrolls.listHeader.length-1 && position>=0)
setState(() {
position=position+1;
});
}else{}
if((start.velocity.pixelsPerSecond.dx)>900){
if(position<=NestedScrolls.listHeader.length-1 && position>0)
setState(() {
position=position-1;
});
}
print(position);
},
child: applyWidget()),
),
],
),
);
}
list() {
return SingleChildScrollView(scrollDirection: Axis.vertical,
child: Container(
child: Column(children: [
for(var color in Colors.primaries)
Container(color: color, height: 100.0)
],),
),
);
}
grid() {
return GridView.count(
padding: EdgeInsets.zero,
crossAxisCount: 3,
children: Colors.primaries.map((color) {
return Container(color: color, height: 100.0);
}).toList(),
);
}
}
- header pull to refresh可以在我想拖上去的时候拉上去
- 标签栏置顶。
- ListView 可以滑动到另一个页面。
100% 自定义小部件。它支持更改header值并且支持滑动操作。
它实际上不是 TabBar 小部件,但它的工作方式完全一样
import 'package:flutter/material.dart';
import 'dart:math';
class NestedScrolls extends StatefulWidget {
static const listHeader = ['Pakistan', 'China','Iran','Turkey'];
@override
_NestedScrollsState createState() => _NestedScrollsState();
}
class _NestedScrollsState extends State<NestedScrolls> {
var position=0;
var topHeader;
Widget? applyWidget() {
switch(position){
case 0:
setState(() {
topHeader = NestedScrolls.listHeader[0];
});
// return widget if user click over pakistan in tab bar
return grid();
case 1:
setState(() {
topHeader = NestedScrolls.listHeader[1];
});
return list();
case 2:
setState(() {
topHeader = NestedScrolls.listHeader[2];
});
return Container(color: Colors.blue,
child: Center(child: Text(topHeader),),);
case 3:
setState(() {
topHeader = NestedScrolls.listHeader[3];
});
return Container(color: Colors.orange,
child: Center(child: Text(topHeader),),);
}
}
@override
void initState() {
// TODO: implement initState
super.initState();
//initial header name when activity start first time
topHeader = NestedScrolls.listHeader[0];
}
@override
Widget build(BuildContext context) {
topHeader = topHeader;
return Scaffold(
// Persistent AppBar that never scrolls
appBar: AppBar(
title: Text('AppBar'),
elevation: 0.0,
),
body:
Column(
children: <Widget>[
///header
Container(
alignment: Alignment.center,
color: Colors.blueGrey,
height: 90,
child: Text(NestedScrolls.listHeader[position]),
),
/// tabBar
Container(
height: 60,
width: MediaQuery.of(context).size.width,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: NestedScrolls.listHeader.length,
itemBuilder: (con, index) {
return GestureDetector(
onTap: () => setState(() {
position=index;
topHeader = NestedScrolls.listHeader[index];
}),
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 2.0, horizontal: 10),
child: Container(alignment: Alignment.center,
width: 100,
color: topHeader==NestedScrolls.listHeader[index]?Colors.black26:Colors.transparent,
child: Text(NestedScrolls.listHeader[index])),
),
);
}),
),
///Widget
Expanded(
child: GestureDetector(
// onHorizontalDragStart: (left){
// print('left : ${left.localPosition.direction}');
// // left.globalPosition.dx
//
// },
onHorizontalDragEnd: (start){
print('start : ${start.velocity.pixelsPerSecond.dx}');
if((start.velocity.pixelsPerSecond.dx)<-700){
if(position<NestedScrolls.listHeader.length-1 && position>=0)
setState(() {
position=position+1;
});
}else{}
if((start.velocity.pixelsPerSecond.dx)>900){
if(position<=NestedScrolls.listHeader.length-1 && position>0)
setState(() {
position=position-1;
});
}
print(position);
},
child: applyWidget()),
),
],
),
);
}
list() {
return SingleChildScrollView(scrollDirection: Axis.vertical,
child: Container(
child: Column(children: [
for(var color in Colors.primaries)
Container(color: color, height: 100.0)
],),
),
);
}
grid() {
return GridView.count(
padding: EdgeInsets.zero,
crossAxisCount: 3,
children: Colors.primaries.map((color) {
return Container(color: color, height: 100.0);
}).toList(),
);
}
}