Is there any way to scroll parent listview when the child listview reached end in flutter?
Asked Answered
C

2

6

Let's say that i have a scrollable page and inside this page i have another scrollable listview(vertical), so i want when child listview reached end, the scrollable page start moving to it's end. Also when child listview reached top, scrollable page start moving to it's top. how can do that?

here's my codes

 Widget FreshProductsShow(double pageHeight, double pageWidth) {
    return Container(
      height: pageHeight / 1.3,
      width: pageWidth,
      child: ListView.builder(
        itemCount: 10,
        itemBuilder: (context, index) {
          return Card(
            child: Container(
              width: pageWidth,
              // height: pageHeight / 7,
              decoration: BoxDecoration(
                  color: Colors.white, borderRadius: BorderRadius.circular(10)),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                textDirection: TextDirection.rtl,
                children: [
                  Image.asset(
                    "images/peper.png",
                    width: pageWidth / 4,
                    height: pageHeight / 8,
                  ),
                  Padding(
                    padding: EdgeInsets.only(left: pageWidth / 6.3),
                    child: Column(
                      children: [
                        Padding(
                          padding: EdgeInsets.only(
                              left: pageWidth / 10, top: pageHeight / 45),
                          child: AutoSizeText(
                            "peper",
                            style: TextStyle(
                                fontSize: pageHeight / 48,
                                fontWeight: FontWeight.bold,
                                color: Color(0xff54595F)),
                          ),
                        ),

                      ],
                    ),
                  )
                ],
              ),
              alignment: Alignment.centerRight,
            ),
            elevation: 5,
          );
        },
        scrollDirection: Axis.vertical,
      ),
    );
  }
Carroty answered 13/11, 2021 at 7:15 Comment(3)
Can you include the code-snippet that you've tried so far?Triturable
@YeasinSheikh Sure, i edited my question. If i want to scroll all page i have to tap and scroll somewhere outside of this container. and idk how to fix it.Carroty
use primary : false in ListView.builderEardrum
G
1

To find the scroll position you have to use the Scroll Notification Listener NotificationListener, and using a ScrollController we can control the scroll position for each Scrollable Widget.

Here is your function converted to a StatefulWidget, and the logic implemented if I got it correctly:

class FreshProductsShow extends StatefulWidget {
  const FreshProductsShow(
      {Key? key, required this.pageHeight, required this.pageWidth})
      : super(key: key);
  final double? pageHeight;
  final double? pageWidth;
  @override
  _FreshProductsShowState createState() => _FreshProductsShowState();
}

class _FreshProductsShowState extends State<FreshProductsShow> {
  ScrollController _childScrollController = ScrollController();
  ScrollController _parentScrollController = ScrollController();

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      controller: _parentScrollController,
      child: Column(
        children: [
          Container(
            color: Colors.red,
            height: 300,
          ),
          Container(
            height: widget.pageHeight! / 1.3,
            width: widget.pageWidth,
            child: NotificationListener(
              onNotification: (ScrollNotification notification) {
                if (notification is ScrollUpdateNotification) {
                  if (notification.metrics.pixels ==
                      notification.metrics.maxScrollExtent) {
                    debugPrint('Reached the bottom');
                    _parentScrollController.animateTo(
                        _parentScrollController.position.maxScrollExtent,
                        duration: Duration(seconds: 1),
                        curve: Curves.easeIn);
                  } else if (notification.metrics.pixels ==
                      notification.metrics.minScrollExtent) {
                    debugPrint('Reached the top');
                    _parentScrollController.animateTo(
                        _parentScrollController.position.minScrollExtent,
                        duration: Duration(seconds: 1),
                        curve: Curves.easeIn);
                  }
                }
                return true;
              },
              child: ListView.builder(
                controller: _childScrollController,
                itemCount: 10,
                itemBuilder: (context, index) {
                  return Card(
                    child: Container(
                      width: widget.pageWidth,
                      // height: pageHeight / 7,
                      decoration: BoxDecoration(
                          color: Colors.white,
                          borderRadius: BorderRadius.circular(10)),
                      child: Row(
                        mainAxisAlignment: MainAxisAlignment.spaceBetween,
                        textDirection: TextDirection.rtl,
                        children: [
                          Image.asset(
                            "images/peper.png",
                            width: widget.pageWidth! / 4,
                            height: widget.pageHeight! / 8,
                          ),
                          Padding(
                            padding:
                                EdgeInsets.only(left: widget.pageWidth! / 6.3),
                            child: Column(
                              children: [
                                Padding(
                                  padding: EdgeInsets.only(
                                      left: widget.pageWidth! / 10,
                                      top: widget.pageHeight! / 45),
                                  child: Text(
                                    "peper",
                                    style: TextStyle(
                                        fontSize: widget.pageHeight! / 48,
                                        fontWeight: FontWeight.bold,
                                        color: Color(0xff54595F)),
                                  ),
                                ),
                              ],
                            ),
                          )
                        ],
                      ),
                      alignment: Alignment.centerRight,
                    ),
                    elevation: 5,
                  );
                },
                scrollDirection: Axis.vertical,
              ),
            ),
          ),
          Container(
            color: Colors.red,
            height: 300,
          ),
        ],
      ),
    );
  }
}
Glazed answered 13/11, 2021 at 8:18 Comment(2)
Dast xosh kak Hooshyar. It was true.Carroty
This really helped me. On my use case, NestedScrollView and customScrollView couldn't solve the problemShooter
M
1
Yes, there is way to scroll parent widget if child widget is either on top or bottom by using Simulation

**Here is sample code to create custom physics -** 

    import 'package:flutter/material.dart';
    
    class CustomScrollPhysics extends ClampingScrollPhysics {
      final Function outerController;
      bool isMinCheck = false;
      CustomScrollPhysics({required this.outerController,  ScrollPhysics? parent}): super(parent: parent);
    
      @override
      CustomScrollPhysics applyTo(ScrollPhysics? ancestor) {
        return CustomScrollPhysics(outerController: outerController,  parent: buildParent(ancestor)!);
      }
    
      @override
      Simulation? createBallisticSimulation(ScrollMetrics position, double velocity) {
        if (position.pixels >= position.maxScrollExtent && velocity >= 0.0) {
          outerController(velocity,false);
        }else if(position.pixels == position.minScrollExtent && isMinCheck){
          outerController(velocity, true);
        }else{
          isMinCheck = true;
        }
        return super.createBallisticSimulation(position, velocity);
      }
    } 



**Below is sample code to implement in parent widget -**
 

import 'package:flutter/material.dart';
import 'package:lurnify/ui/widgets/custom_scroll.dart';

class CustomScrolling extends StatefulWidget{

  @override
  State<StatefulWidget> createState() {
    return _CustomState();
  }
}

class _CustomState extends State<CustomScrolling> with TickerProviderStateMixin{

  final outerPhysics = ClampingScrollPhysics();
  ScrollController innerControllers = ScrollController();
  ScrollController outerController = ScrollController();

  void innerListener(double velocity, ScrollController outerController) {
    final sim = outerPhysics.createBallisticSimulation(outerController.position, velocity);
    if(sim!=null){
      ScrollActivity _test = BallisticScrollActivity(outerController.position.activity!.delegate,sim,this);
      outerController.position.beginActivity(_test);
    }
  }

  @override
  Widget build(BuildContext context) {
     return Scaffold(
       appBar: AppBar(),
       body: SafeArea(
         child: body(),
       ),
     );
  }

  Widget body(){
    return SingleChildScrollView(
      controller: outerController,
      physics: outerPhysics,
      child: Column(
        children: [
          Container(
            width: double.infinity,
            height: 200,
            color: Colors.brown,
          ),
          Container(
            width: double.infinity,
            height: 500,
            color: Colors.red,
            child: ListView.builder(
              shrinkWrap: true,
              itemCount: 40,
              physics: CustomScroll(outerController: (velocity, isMin) => innerListener(velocity, outerController)),
              itemBuilder: (context, index) {
                return Container(
                  child: Text("index $index"),
                );
              },
            ),
          ),
          Container(
            color: Colors.grey,
            width: double.infinity,
            height: 400,
          ),
        ],
      ),
    );
  }

}
Manteau answered 10/6, 2022 at 9:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.