RegularGuy
RegularGuy

Reputation: 3676

Detect if a SingleChildScrollview/Listview can be scrolled

So, i have a widget with infinite width (Row) . To fill the widget with items i'm using a Lisview builder with Axis horizontal. I also can use a SingleChildScrollview with axis horizontal and a Row as the child.

If there is a few items, the width of the screen is not filled, so that's great. However, when there is a lot of items, the Listview becomes "scrollable" , and i can scroll to the right to reveal the items.

I would like to know if the list is scrollable (if it overflows). The purpose is to show a little text saying "Scroll to reveal more>>".

I know i can use maths and calculate the items width with the screen width. However... The Listview already knows this, so i was wondering if there was a way of getting access to that information

Upvotes: 8

Views: 6415

Answers (4)

Dimitri Leurs
Dimitri Leurs

Reputation: 702

bool get isScrollable => scrollController.position.extentInside > 0;

Upvotes: 0

Abel Rodríguez
Abel Rodríguez

Reputation: 652

I created a widget called ScrollCheckerWidget with a controller property to pass the controller of a scrollable widget and check if it is scrollable in the view. The ScrollCheckerWidget widget has a builder callback function where you can return a widget and use the isScrollable boolean from the builder to check if the widget related to the controller is scrollable or not. Here you have the code:

import 'package:flutter/material.dart';

class ScrollCheckerWidget extends StatefulWidget {
  const ScrollCheckerWidget({
    Key? key,
    required this.controller,
    required this.builder,
  }) : super(key: key);

  final ScrollController controller;
  final Widget Function(bool isScrollable) builder;

  @override
  State<ScrollCheckerWidget> createState() => _ScrollCheckerWidgetState();
}

class _ScrollCheckerWidgetState extends State<ScrollCheckerWidget> {
  late final ScrollController _scrollController;
  late bool _isScrollable;

  @override
  void initState() {
    _scrollController = widget.controller;

    _isScrollable = false;

    WidgetsBinding.instance.addPostFrameCallback((_) {
      setState(() {
        _isScrollable = _scrollController.position.maxScrollExtent > 0;
      });
    });

    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return widget.builder.call(_isScrollable);
  }
}

Upvotes: 1

Michael Rodeman
Michael Rodeman

Reputation: 151

I had a similar problem. I found this solution here: Determine Scroll Widget height

Here's my question in case it's helpful: How do you tell if scrolling is not needed in a SingleChildScrollView when the screen is first built?

Solution:

  1. Import the scheduler Flutter library:
import 'package:flutter/scheduler.dart';
  1. Create a boolean flag inside the state object but outside of the build method to track whether build has been called yet:
bool buildCalledYet = false;
  1. Create a boolean isScrollable variable inside the state object but outside of the build method:
bool isScrollable;
  1. Add the following in the beginning of the build method:
if (!firstBuild) {
      firstBuild = true;
      SchedulerBinding.instance.addPostFrameCallback((_) {
        setState(() {
          isScrollable = !(_scrollController.position.maxScrollExtent > 0);
        });
      });
    }

(The purpose of buildCalledYet is to prevent this code from causing build to be called over and over again.)

  1. If isScrollable is true, then show your text.

Upvotes: 6

ahaaman
ahaaman

Reputation: 651

In builder:

return NotificationListener(
            onNotification: (scrollNotification) {
              print("ScrollStartNotification");
              // add your logic here
            },
            child: SingleChildScrollView(...


     

Am trying to detect exact same thing myself, wrapping SingleChildScrollView with NotificationListener at least gave me a point of reference to start working on this.

Upvotes: 0

Related Questions