我在flutter选项卡栏中有4个选项卡。我使用的是银应用程序栏,选项卡栏位于银色应用程序栏的底部属性中。我在SingleChilScrollView中有4个不同大小的容器。单击每个选项卡时,屏幕滚动到特定容器。我有3个问题:
1.第一个是当我点击标签的时候,它会滚动容器,比我想要的要多一点。2我想要在屏幕上显示容器顶部(里面有文本)。
1.第二个问题(也是最重要的一个)是,当我单击选项卡时,它会将屏幕滚动到特定容器,但选项卡的活动颜色表现不正常(有时它会显示活动选项卡,有时则不会)。
1.当我调整网页屏幕大小时,选项卡没有滚动到准确的容器位置。
让我们假设一种情况,当用户点击第3个选项卡时,预期结果将是该选项卡将通过显示蓝线而激活,并且屏幕将滚动到第3个容器。获得的结果是屏幕滚动到第3个容器,但选项卡活动颜色(蓝色)无法正常工作。
预期的结果是:expected result
得到的结果是:gained result
可以运行的代码如下:
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
class ScrollContainerPage extends StatefulWidget {
@override
State<ScrollContainerPage> createState() => _ScrollContainerPageState();
}
class _ScrollContainerPageState extends State<ScrollContainerPage> {
ScrollController _scrollController = ScrollController();
List<GlobalKey> _globalKey = List.empty(growable: true);
late final secondContainerPosition;
late final thirdContainerPosition;
late final fourthContainerPosition;
bool initilized = false;
@override
void initState() {
for (int i = 0; i < 4; i++) {
_globalKey.add(GlobalKey());
}
super.initState();
}
getPosition() {
RenderBox box2 =
_globalKey[1].currentContext!.findRenderObject()! as RenderBox;
Offset position2 = box2.localToGlobal(Offset.zero);
if (!initilized) {
secondContainerPosition = position2.dy;
}
RenderBox box3 =
_globalKey[2].currentContext!.findRenderObject()! as RenderBox;
Offset position3 = box3.localToGlobal(Offset.zero);
if (!initilized) {
thirdContainerPosition = position3.dy;
}
RenderBox box4 =
_globalKey[3].currentContext!.findRenderObject()! as RenderBox;
Offset position4 = box4.localToGlobal(Offset.zero);
if (!initilized) {
fourthContainerPosition = position4.dy;
}
initilized = true;
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: DefaultTabController(
length: 4,
child: NestedScrollView(
floatHeaderSlivers: false,
headerSliverBuilder:
(BuildContext context, bool innerBoxIsScrolled) {
return [
SliverAppBar(
leadingWidth: 200,
centerTitle: true,
//titleSpacing: 0,
//expandedHeight: 200.0,
backgroundColor: Colors.white,
leading: const Icon(Icons.arrow_back_ios,color: Colors.black,),
title: !kIsWeb? const Text("About us",
style: TextStyle(
color: Colors.black,
fontSize: 16.0,
),
):
SizedBox(
height: 40,
width: MediaQuery.of(context).size.width*0.5,
child: Center(
child: TextField(
cursorColor: const Color.fromRGBO(0, 79, 224, 1),
//maxLines: 5,
decoration: InputDecoration(
contentPadding: const EdgeInsets.symmetric(horizontal: 20),
prefixIcon: const Icon(Icons.search),
prefixIconColor: Colors.red,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20),
borderSide: const BorderSide(color: Color.fromRGBO(118, 118, 128, 1), width: 2),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(20),
borderSide: const BorderSide(color: Color.fromRGBO(118, 118, 128, 1), width: 1.5),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(20),
borderSide: const BorderSide(color: Color.fromRGBO(0, 79, 224, 1), width: 1.5),
),
),
),
),
),
actions: kIsWeb?[
Container(
margin: const EdgeInsets.fromLTRB(12,12,80,12),
padding: const EdgeInsets.symmetric(vertical: 5,horizontal: 30),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
border: Border.all(color: const Color.fromRGBO(4, 80, 225, 1)),
),
child: InkWell(
onTap: (){
},
child: Row(
children: const [
Icon(Icons.person_outline,
color: Color.fromRGBO(4, 80, 225, 1),
),
SizedBox(width: 10,),
Text('Sign in',
style: TextStyle(
color: Color.fromRGBO(4, 80, 225, 1),
fontSize: 14.0,
// fontWeight: FontWeight.w600,
),
),
],
),
),
),
]:null,
floating: !kIsWeb?true: false,
pinned: true,
snap: !kIsWeb?true: false,
bottom: TabBar(
indicatorColor: const Color.fromRGBO(0, 79, 224, 1),
tabs: [
Tab(icon: GestureDetector(
onTap: (){
setState(() {
getPosition();
_scrollController.animateTo(
_scrollController.position.minScrollExtent,
duration: const Duration(milliseconds: 500),
curve: Curves.ease);
});
},
child: const Text('scroll to red container', style: TextStyle(color: Colors.black),)),),
Tab(icon: GestureDetector(
onTap: (){
setState(() {
getPosition();
_scrollController.animateTo(secondContainerPosition,
// !kIsWeb ? 1140 : 1000,
duration: const Duration(milliseconds: 500),
curve: Curves.ease);
});
},
child: const Text('scroll to yellow container', style: TextStyle(color: Colors.black),)),),
Tab(icon: GestureDetector(
onTap: (){
setState(() {
getPosition();
_scrollController.animateTo(thirdContainerPosition,
// !kIsWeb ? 3380 : 2000,
duration: const Duration(milliseconds: 500),
curve: Curves.ease);
});
},
child: const Text('scroll to pink container', style: TextStyle(color: Colors.black),)),),
Tab(icon: GestureDetector(
onTap: (){
setState(() {
getPosition();
_scrollController.animateTo(fourthContainerPosition,
// _scrollController.position.maxScrollExtent,
duration: const Duration(milliseconds: 500),
curve: Curves.ease);
});
},
child: const Text('scroll to orange container', style: TextStyle(color: Colors.black),)),),
]
),
),
];
},
body:
SingleChildScrollView(
controller: _scrollController,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
key: _globalKey[0],
height: 1000,
color: Colors.red,
child: const Text('red container')
),
const SizedBox(
height: 30,
),
Container(
key: _globalKey[1],
height: 1700,
color: Colors.yellow,
child: Text('yellow Container')
),
const SizedBox(
height: 30,
),
Container(
key: _globalKey[2],
height: 3000,
color: Colors.pink,
child: Text('pink Container')
),
const SizedBox(
height: 30,
),
Container(
key: _globalKey[3],
height: 500,
color: Colors.orange,
child: Text('orange Container'),
),
const SizedBox(
height: 30,
),
],
),
),
),
),
);
}
}
1条答案
按热度按时间g52tjvyc1#
这里我已经解决了您的问题,您将
GestureDetector
添加到所有单独的选项卡中,这阻碍了实际TabBar
上的点击区域,您需要做的是使用TabBar
本身的onTap
方法: