Giter VIP home page Giter VIP logo

simonwang9610 / indexed_scroll_observer Goto Github PK

View Code? Open in Web Editor NEW
7.0 2.0 0.0 15.65 MB

An elegant scroll observer for observing scrollable widgets in Flutter applications.

Home Page: https://pub.dev/packages/positioned_scroll_observer

License: MIT License

Java 0.34% Kotlin 0.08% Swift 0.80% Objective-C 0.39% Dart 68.80% CMake 12.42% C++ 14.13% C 1.25% HTML 1.13% Shell 0.66%
flutter flutter-ui scrollview-component slivergrid sliverlist

indexed_scroll_observer's People

Contributors

simonwang9610 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

indexed_scroll_observer's Issues

Estimation for GridView infinitely

Since the current estimation for GridView does not consider the cross count when using jumpToIndex and animateToIndex, it would try estimating the scroll offset infinitely when jumping or animating.

iShot_2023-03-16_11.10.21.mp4

The main reason is that each estimation for index cannot hit the exact scroll offset, and consequently, jumping or animating would estimate forever.

[PR]: `ListWheelScrollView` and `SingleChildScrollView` support (break change)

Currently, all kinds of observers only support scroll views that have a RenderSlvier between items and RenderAbstractViewport, e.g., SliverList, SliverGrid, ListView ad GridView. Therefore, it would require tracking up to find the closest RenderSliver ancestor for observation.

However, such usages do not work on ListWheelScrollView and SingleChildScrollView that do not have a RenderSliver between the viewport and items. So this package should provide a better way to support such kinds of scroll views that do not depend on RenderSliver.

In order to differentiate the two kinds of scroll views (one relying on RenderSliver, while the other does not rely on RenderSliver), this package could create two kinds of observers to support them respectively. For example:

  1. SliverScrollObserver for observing scroll views that rely on RenderSliver.
  2. BoxScrollObserver for observing scroll views that have no RenderSliver between items and its viewport.

Besides, PositionScrollController may make it a little bit complicated to manage multiple observers, so it would be removed directly. Developers should care about creating and managing observers manually, instead of delegating to PositionedScrollController centrally.

To summarize:

  • break changes

    1. PositionedScrollController is removed, and developers should create and manage different observers manually.
    2. Two kinds of observers: SliverScrollObserver and BoxScrollObserver are provided. In contrast, ScrollObserver would be changed into the observer factory that allows developers to create different observers conveniently.
    3. ListWheelScrollView and SingleChildScrollView are supported by using BoxScrollObserver. Developers could find examples at example/.
  • improvements

  1. better estimation for jumping/animating to a specific index. Particularly, items have a fixed item extent.

getVisibleItems question

Can getVisibleItems be added to check whether the display is complete?
Because now if an item is not fully displayed, it will still be recognized by the getVisibleItems method

ListView.separated is not supported

ListView.separated is not supported

Expanded(
child: ListView.separated(
controller: _controller,
physics: const BouncingScrollPhysics(),
itemBuilder: (context, index) => _items[index],
itemCount: _itemCount,
separatorBuilder: (BuildContext context, int index) {
return const VerticalDivider(color: Colors.yellow,width: 10,);
},
),
)

PositionRetainedScrollPhysics have a bug When item heights vary

this is code

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

  @override
  State<OfficialListExample> createState() => _OfficialListExampleState();
}

class _OfficialListExampleState extends State<OfficialListExample> {
  int _itemCount = 100;

  final ScrollController _controller = ScrollController();

  late final SliverScrollObserver _observer =
      MultiChildSliverObserver(itemCount: _itemCount);

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
  }

  late final List<Widget> _items = List.generate(_itemCount, (index) => index)
      .map(
        (index) => ObserverProxy(
          observer: _observer,
          child: ListTile(
            leading: const CircleAvatar(
              child: Text("L"),
            ),
            title: Column(
              mainAxisSize: MainAxisSize.min,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text("Positioned List Example $index"),
                SizedBox(
                  height: index.toDouble(),
                )
              ],
            ),
          ),
        ),
      )
      .toList();

  @override
  void dispose() {
    _controller.dispose();
    _observer.clear();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        centerTitle: true,
        title: const Text("List View Example"),
      ),
      body: Column(
        children: [
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              OutlinedButton(
                onPressed: () {
                  _observer.showInViewport(
                    _controller.position,
                    alignment: 0.0,
                  );
                },
                child: const Text("Go to start"),
              ),
              OutlinedButton(
                onPressed: () {
                  _observer.showInViewport(
                    _controller.position,
                    alignment: 0.5,
                  );
                },
                child: const Text("Go to middle"),
              ),
              OutlinedButton(
                onPressed: () {
                  _observer.showInViewport(
                    _controller.position,
                    alignment: 1.0,
                  );
                },
                child: const Text("Go to end"),
              ),
            ],
          ),
          SliverJumpWidget(
            label: "without animation",
            onJump: (index) {
              _observer.jumpToIndex(
                index,
                position: _controller.position,
              );
            },
          ),
          SliverJumpWidget(
            label: "animation",
            onJump: (index) {
              _observer.animateToIndex(
                index,
                position: _controller.position,
                duration: const Duration(milliseconds: 1000),
                curve: Curves.fastLinearToSlowEaseIn,
              );
            },
          ),
          Expanded(
            child: ListView.builder(
              controller: _controller,
              reverse: true,
              physics: const PositionRetainedScrollPhysics(),
              itemBuilder: (context, index) => _items[index],
              itemCount: _itemCount,
            ),
          )
        ],
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          _addItem();
          // _observer.getVisibleItems(
          //   scrollExtent: ScrollExtent.fromPosition(_controller.position),
          // );
          // print(_observer.visibleRatioInViewport(
          //     ScrollExtent.fromPosition(_controller.position)));
        },
        child: const Icon(Icons.visibility_off_rounded),
      ),
    );
  }

  void _goStart() {
    _observer.showInViewport(_controller.position);
  }

  void _addItem() {
    _itemCount++;
    _observer.itemCount = _itemCount;
    _items.insert(
      0,
      ObserverProxy(
        observer: _observer,
        child: ListTile(
          leading: const CircleAvatar(
            child: Text("L"),
          ),
          title: Column(
            children: [
              Text("Positioned List Example $_itemCount"),
              SizedBox(
                height: _itemCount.toDouble(),
              )
            ],
          ),
        ),
      ),
    );

    setState(() {});
  }

  void _deleteItem() {
    _itemCount = max(--_itemCount, 0);
    _observer.itemCount = _itemCount;

    _items.removeLast();

    setState(() {});
  }
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.