The way to control the scroll in ExtendedNestedScrollView

107 views Asked by At

I have a page with Extended NestedScrollView but I am unable find a way to perform scroll controller action in the nested page. I know this is an unsupported feature for now, so I am looking for any possible solution.

What I have already tried:

  • I tried get the PrimaryScrollController in context but it still not work (It perform scroll in all tab). This is the code I tried:
PrimaryScrollController.of(context)
        .positions
        .first
        .jumpTo(PrimaryScrollController.of(context)
            .positions
            .first
            .maxScrollExtent);
  • I installed extended_nested_scrollview and pull_to_refresh.

      flutter pub add extended_nested_scroll_view
      flutter pub add  pull_to_refresh
    
import 'dart:math';

import 'package:extended_nested_scroll_view/extended_nested_scroll_view.dart';
import 'package:flutter/material.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
      const MyApp({super.key});
 
      @override
      Widget build(BuildContext context) {
          return const MaterialApp(
          home: Home(),
      );
      }
    }

class Home extends StatefulWidget {
  const Home({super.key});

  @override
  _HomeState createState() => _HomeState();
}

class _HomeState extends State<Home> with SingleTickerProviderStateMixin {
  TabController? _tabController;

  @override
  void initState() {
    super.initState();
    _tabController = TabController(length: 4, vsync: this);
  }

  @override
  void dispose() {
    _tabController?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: ExtendedNestedScrollView(
        onlyOneScrollInBody: true,
        headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
          return <Widget>[
            SliverAppBar(
              title: const Text('Nested Scroll with Tabs'),
              pinned: true,
              floating: true,
              bottom: TabBar(
                controller: _tabController,
                tabs: const [
                  Tab(text: 'Tab 1'),
                  Tab(text: 'Tab 2'),
                  Tab(text: 'Tab 3'),
                  Tab(text: 'Tab 4'),
                ],
              ),
            ),
          ];
        },
        body: TabBarView(
          controller: _tabController,
          children: [
            TabPage(),
            TabPage(),
            TabPage(),
            TabPage(),
          ],
        ),
      ),
    );
  }
}

class TabPage extends StatefulWidget {
  TabPage({super.key});
  @override
  _TabPageState createState() => _TabPageState();
}

class _TabPageState extends State<TabPage> with AutomaticKeepAliveClientMixin {
  late RefreshController refreshController;
  late TextEditingController textEditingController;
  List<String> listItem = [];
  late Color bgColor;

  Random ran = Random();
  @override
  void initState() {
    listItem.addAll(List.generate(30, (index) => 'item $index'));
    bgColor = Colors.primaries[ran.nextInt(Colors.primaries.length)];
    refreshController = RefreshController();
    textEditingController = TextEditingController();
    super.initState();
  }

  @override
  void dispose() {
    refreshController.dispose();
    textEditingController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    super.build(context); // This is required for AutomaticKeepAliveClientMixin.
    return SafeArea(
      top: false,
      child: Column(
        children: [
          Expanded(
            child: Stack(
              children: [
                SmartRefresher(
                  controller: refreshController,
                  onRefresh: () {
                    setState(() {
                      bgColor = Colors
                          .primaries[ran.nextInt(Colors.primaries.length)];
                      refreshController.refreshCompleted();
                    });
                  },
                  onLoading: () {
                    setState(() {
                      refreshController.loadComplete();
                    });
                  },
                  child: ListView.builder(
                    itemCount: listItem.length,
                    controller: PrimaryScrollController.of(context),
                    itemBuilder: (BuildContext context, int index) {
                      return ColoredBox(
                        color: bgColor,
                        child: ListTile(
                          title: Text(listItem[index]),
                        ),
                      );
                    },
                  ),
                ),
                Align(
                  alignment: Alignment.bottomRight,
                  child: Padding(
                    padding: const EdgeInsets.all(18),
                    child: Container(
                      decoration: BoxDecoration(
                        color: Colors.white,
                        borderRadius: BorderRadius.circular(90),
                      ),
                      child: Padding(
                        padding: const EdgeInsets.all(4),
                        child: IconButton(
                          icon: const Icon(Icons.keyboard_arrow_down),
                          color: Colors.blue,
                          onPressed: () {
                            /// unable scroll to end of list
                            PrimaryScrollController.of(context)
                                .positions
                                .first
                                .jumpTo(PrimaryScrollController.of(context)
                                    .positions
                                    .first
                                    .maxScrollExtent);
                            print(
                                'debug>>${PrimaryScrollController.of(context).positions}');
                          },
                        ),
                      ),
                    ),
                  ),
                ),
              ],
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(8),
            child: TextField(
              controller: textEditingController,
              decoration: InputDecoration(
                  border: const OutlineInputBorder(),
                  suffix: IconButton(
                      onPressed: () {
                        setState(() {
                          listItem.add(textEditingController.value.text);
                        });
                      },
                      icon: const Icon(Icons.send))),
            ),
          )
        ],
      ),
    );
  }

  @override
  bool get wantKeepAlive => true;
}

How can I perform scroll control in NestedScrollView body and retain scrolling behavior in NestedScrollView.

0

There are 0 answers