简体   繁体   中英

I want a flutter tab bar to make screen scroll to a specific location when a user click on the tab

I have 4 tabs in a flutter tab bar. I am using a silver App bar and the tab bar is inside the bottom property of the silver app bar. I have 4 containers of different sizes inside SingleChilScrollView.

The functionality I want to achieve is when a user clicks on the first tab the screen scrolls to the first container and when a user clicks on the 4th tab the screen scrolls to the 4th container and again when a user clicks on the 1st tab the screen scroll back to the first container. I will be implementing this functionality for the flutter web version.

the code is below, but the screen doesn't scroll when user clicks the tabs.

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 pink container', style: TextStyle(color: Colors.black),)),),
                          ]
                      ),

              ),
            ];
          },
          body:
              SingleChildScrollView(
                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('orangeContainer'),
                    ),
                    const SizedBox(
                      height: 30,
                    ),

                  ],
                ),
              ),


        ),
      ),
    );

  }
}

You need to add your _scrollController to your SingleChildScrollView widget to make it work.

body : SingleChildScrollView(
            controller: _scrollController, //just add this line
            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('orangeContainer'),
                ),
                const SizedBox(
                  height: 30,
                ),
              ],
            ),
          ),

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM