Coder Social home page Coder Social logo

fluttercandies / flutter_scrollview_observer Goto Github PK

View Code? Open in Web Editor NEW
406.0 6.0 41.0 5.87 MB

A widget for observing data related to the child widgets being displayed in a ScrollView. Maintainer: @LinXunFeng

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

License: MIT License

Kotlin 0.03% Ruby 0.57% Swift 0.27% Objective-C 0.01% Dart 92.50% HTML 0.84% CMake 1.92% C++ 3.63% C 0.22%
dart flutter observer scrollview scrollview-observer gridview listview nestedscrollview slivergrid sliverlist

flutter_scrollview_observer's Introduction

Flutter ScrollView Observer

author pub stars

Language: English | 中文

This is a library of widget that can be used to listen for child widgets those are being displayed in the scroll view.

☕ Support me

ko-fi wechat

Chat: Join WeChat group

📖 Article

🔨 Feature

You do not need to change the view you are currently using, just wrap a ViewObserver around the view to achieve the following features.

  • Observing child widgets those are being displayed in ScrollView
  • Support for scrolling to a specific item in ScrollView
  • Quickly implement the chat session page effect
  • Support for keeping IM message position when inserting or updating messages, avoiding jitter.

🎀 Support

  • ListView
  • SliverList
  • GridView
  • SliverGrid
  • Mixing usage of SliverPersistentHeader, SliverList and SliverGrid
  • NestedScrollView
  • ScrollView built by third-party package.

🕹 Preview

📦 Installing

Add scrollview_observer to your pubspec.yaml file:

dependencies:
  scrollview_observer: latest_version

Import scrollview_observer in files that it will be used:

import 'package:scrollview_observer/scrollview_observer.dart';

📚 Wiki

🖨 About Me

flutter_scrollview_observer's People

Contributors

alexv525 avatar linxunfeng avatar liudongcai avatar percival888 avatar qiangjindong avatar zeqinjie avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

flutter_scrollview_observer's Issues

不支持上拉加载

您好,使用该组件实现chat效果时,发现几个问题。1、数据量大的时候很卡,2、好像不支持第三方的上拉加载,比如pull_to_refresh。

import 'package:easy_refresh/easy_refresh.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:scrollview_observer/scrollview_observer.dart';

import '../controller/doctor_chat_controller.dart';

class ChartListWidget extends StatefulWidget {
  const ChartListWidget({
    Key? key,
    required this.itemBuilder,
    required this.itemCount,
    this.scrollController,
  }) : super(key: key);
  final IndexedWidgetBuilder itemBuilder;
  final int itemCount;
  final ScrollController? scrollController;
  @override
  State<ChartListWidget> createState() => _ChartListWidgetState();
}

class _ChartListWidgetState extends State<ChartListWidget> {
  final EasyRefreshController _refreshController = EasyRefreshController(
    controlFinishRefresh: true,
    controlFinishLoad: true,
  );

  late ListObserverController observerController;
  late ChatScrollObserver chatObserver;
  late ScrollController _scrollController;
  final DoctorChatController _controller = Get.find<DoctorChatController>();
  @override
  void initState() {
    _scrollController = widget.scrollController ?? ScrollController();
    observerController = ListObserverController(controller: _scrollController)
      ..cacheJumpIndexOffset = false;

    chatObserver = ChatScrollObserver(observerController)
      ..fixedPositionOffset = 5
      ..toRebuildScrollViewCallback = () {
        setState(() {});
      }
      ..onHandlePositionCallback = (type) {};

    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return _buildListView();
  }

  Widget _buildListView() {
    Widget resultWidget = EasyRefresh(
      onRefresh: () async {
        await _controller.onRefresh();
        _refreshController.finishRefresh();
      },
      onLoad: () async {
        await _controller.onLoad();
        _refreshController.finishLoad();
      },
      header: const CupertinoHeader(),
      footer: const CupertinoFooter(),
      child: ListView.builder(
        physics: ChatObserverBouncingScrollPhysics(observer: chatObserver),
        padding:
            const EdgeInsets.only(left: 10, right: 10, top: 15, bottom: 15),
        shrinkWrap: chatObserver.isShrinkWrap,
        reverse: true,
        controller: _scrollController,
        itemBuilder: widget.itemBuilder,
        itemCount: widget.itemCount,
      ),
    );

    resultWidget = ListViewObserver(
      controller: observerController,
      child: resultWidget,
    );
    resultWidget = Align(
      alignment: Alignment.topCenter,
      child: resultWidget,
    );
    return resultWidget;
  }
}

第三方横向滚动失效,不知道啥原因

以前关联的问题: #18
复现代码: https://github.com/mdddj/ops_bug_demo

也可能我的用法不对

import 'package:flutter/material.dart';
import 'package:loading_more_list_fast/loading_more_list_fast.dart';
import 'package:scrollview_observer/scrollview_observer.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final _s = ScrollController();
  late final _ss = ListObserverController(controller: _s);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(),
        body: SingleChildScrollView(
          child: Column(
            children: [
              SizedBox(
                height: 100,
                width: MediaQuery.of(context).size.width,
                child: ListViewObserver(
                  controller: _ss,
                  customTargetRenderSliverType: (p0) => true,
                  child: LoadingMoreList<String>(ListConfig(
                      itemBuilder: (context, item, index) {
                        return Container(
                          margin: const EdgeInsets.all(12),
                          width: 100,
                          height: double.infinity,
                          color: Colors.grey,
                          child: Text(item),
                        );
                      },
                      sourceList: _SourceRepository(),
                      scrollDirection: Axis.horizontal,
                      controller: _s)),
                ),
              ),
              ElevatedButton(
                  onPressed: () {
                    _ss.jumpTo(index: 40);
                  },
                  child: const Text('滚动到 40'))
            ],
          ),
        ),
      ),
    );
  }
}

class _SourceRepository extends LoadingModel<String> {
  @override
  Future<bool> loadData([bool isLoadMoreAction = false]) async {
    addAll(List.generate(100, (index) => "$index"));
    return true;
  }
}

依赖

  loading_more_list_fast: ^7.0.2
  loading_more_list_library_fast: ^4.0.2
  scrollview_observer: ^1.16.5

截图如下
image

点击按钮没有响应

SliverPersistentHeader遮挡

我的应用有 SliverAppBar,SliverPersistentHeader 我看示例有关于offset偏移SliverAppBar的 ,那么请问SliverPersistentHeader的有吗

请问配合上SliverStickyHeader该如何使用?

现在有一个CustomScrollView长这样

[
  SliverAppBar
  SliverPersistentHeader
  ...List.generate(**, (index){
    return SliverStickyHeader(
      header: ***,
      sliver: SliverList(
        delegate: SliverChildBuilderDelegate((context, index) {
           _sliverListCtx ??= context;
           return ***;
         }, childCount: ***,
       ),
      ),
    );
  })
]

假设我第一个SliverStickyHeader底下的list长度为4,第二个SliverStickyHeader底下的list长度为3,我这样给_sliverListCtx赋值后,我使用sliverObserverController.animateTo,它的index最多就只能是3,大于3就会失效。请问有什么办法可以解决吗?由于一些依赖问题,我现在用的还是3.10.5,升不了3.13,用不了SliverMainAxisGroup..

[Feature request]

Platforms

dart

Description

I'm using SuperSliverList from super_sliver_list package. can you add support for this? cause you are checking the type of sliver in the package codebase:

if (_obj is RenderSliverList || _obj is RenderSliverFixedExtentList) {}

Why

super_sliver_list solves performance issues, especially when you wanna use the Scrollbar

聊天如何设置数据不满一屏时,顶部显示所有聊天数据

body: Column(
          children: [
            Expanded(
                child: ListViewObserver(
              controller: observerController,
              child: ListView.builder(
                shrinkWrap: false,
                reverse: true,
                physics:
                    ChatObserverBouncingScrollPhysics(observer: chatObserver),
                controller: scrollController,
                itemBuilder: (ctx, index) {
                  return Container(
                    height: 100,
                    color: Colors.primaries[index % Colors.primaries.length],
                  );
                },
                itemCount: 5,
              ),
              onObserve: (resultModel) {
                print('onObserve: $resultModel');
              },
            )),
            TextField(
              decoration: InputDecoration(
                hintText: 'Enter a search term',
              ),
              onChanged: (value) {
                // controller.notify();
              },
            )
          ],
        )

作者你好,求问一下我这样设置的,我希望是reverse=true,这样键盘打开的时候,页面就能往上顶了,但是此时聊天数据不满一屏如
何置顶显示呢
以及这种方式,如果最后一个元素中文字在增加的时候,如果键盘是打开的,能否自动往上顶

Chat room feature

Hi,

I have tried to create a chat room with your library but I am failed to make it works (e.g. keep current position) , is there anything wrong in my coding?

Thanks a lot

class _MessageScreen2State extends State<MessageScreen2>  {
  var scaffoldKey = GlobalKey<ScaffoldState>();
  final ScrollController _scrollController = ScrollController();
  late ListObserverController observerController;
  late ChatScrollObserver chatObserver;

  final List<String> _messages = <String>[];

  @override
  void initState() {
    super.initState();
    _scrollController.addListener(scrollControllerListener);
    observerController = ListObserverController(controller: _scrollController)
      ..cacheJumpIndexOffset = false;
    chatObserver = ChatScrollObserver(observerController)
      ..fixedPositionOffset = 5
      ..toRebuildScrollViewCallback = () {
        setState(() {});
      };

    for (int i = 0; i < 20; i++) {
      _messages.add(i.toString());
    }
  }

  @override
  void dispose() {
    observerController.controller?.dispose();
    _scrollController.dispose();
    super.dispose();
  }

  scrollControllerListener() {}

  add() {
    chatObserver.standby();
    setState(() {
      for (int i = 0; i < 20; i++) {
        _messages.insert(0, (int.parse(_messages.first)-1).toString());
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key:scaffoldKey,
      appBar: AppBar(
        leading: Padding(
          padding: const EdgeInsets.fromLTRB(6, 14, 0, 14),
          child: GestureDetector(
            child: Image.asset(assetImagePath("back.png")),
            onTap: () {
              Navigator.of(context).pop();
            },
          ),
        ),
      ),
      body: Column(
        children: [
          Expanded(
            child: _buildListView(),
          ),
          SafeArea(
            top: false,
            child: GestureDetector(
              child: Image.asset(GlobalFunc().assetImagePath("send.png"),
                  width: 28),
              onTap: () {
                add();
              },
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildListView() {
    Widget resultWidget = ListView.builder(
      physics: ChatObserverClampingScrollPhysics(observer: chatObserver),
      padding: const EdgeInsets.only(left: 10, right: 10, top: 15, bottom: 15),
      shrinkWrap: chatObserver.isShrinkWrap,
      reverse: true,
      controller: _scrollController,
      itemBuilder: ((context, index) {
        return SizedBox(height: 50, child: Text(_messages.elementAt(index)));
      }),
      itemCount: _messages.length,
    );

    resultWidget = ListViewObserver(
      controller: observerController,
      child: resultWidget,
    );
    resultWidget = Align(
      child: resultWidget,
      alignment: Alignment.topCenter,
    );
    return resultWidget;
  }
}

type '_ExtendedNestedScrollPosition' is not a subtype of type 'ScrollPositionWithSingleContext' in type cast

一个需求需要用到ExtendedNestedScrollView,然而_ExtendedNestedScrollPosition不是ScrollPositionWithSingleContext类型

======== Exception caught by gesture ===============================================================
The following _CastError was thrown while handling a gesture:
type '_ExtendedNestedScrollPosition' is not a subtype of type 'ScrollPositionWithSingleContext' in type cast

When the exception was thrown, this was the stack: 
#0      MixViewObserverState.handleObserveViewport (package:scrollview_observer/src/sliver/sliver_observer_view.dart:159:26)
#1      MixViewObserverState.handleContexts (package:scrollview_observer/src/sliver/sliver_observer_view.dart:82:35)
#2      ObserverWidgetState.build.<anonymous closure> (package:scrollview_observer/src/common/observer_widget.dart:164:15)
#3      _NotificationElement.onNotification (package:flutter/src/widgets/notification_listener.dart:130:38)
#4      _NotificationNode.dispatchNotification (package:flutter/src/widgets/framework.dart:3170:18)
#5      _NotificationNode.dispatchNotification (package:flutter/src/widgets/framework.dart:3173:13)
#6      Element.dispatchNotification (package:flutter/src/widgets/framework.dart:4534:24)
#7      Notification.dispatch (package:flutter/src/widgets/notification_listener.dart:60:13)
#8      DragScrollActivity.dispatchScrollEndNotification (package:flutter/src/widgets/scroll_activity.dart:485:7)
#9      ScrollPosition.didEndScroll (package:flutter/src/widgets/scroll_position.dart:919:15)
#10     ScrollPosition.beginActivity (package:flutter/src/widgets/scroll_position.dart:885:9)
#11     _NestedScrollCoordinator.beginActivity 
====================================================================================================

带上偏移量会出现的若干问题

感谢大佬的插件,但是在结合我的业务需求使用时发现了一些问题,我的页面是一个stack,第一个子组件是ListViewObserver,叠加在顶部的是一个随滑动从透明变不透明的tabbar。
出现的问题是:
1.tabbar里的 observerController.animateTo()如果添加了offset

onTap: (value) {
                  observerController.animateTo(
                    index: value,
                    duration: const Duration(milliseconds: 250),
                    curve: Curves.ease,
                    offset: (offset) {
                      return TAB_HEIGHT;
                    },
                  );
                },

listviewObserver里同时添加onObserver,在点击tab时大概率会出现tab切换错误,tab会在切换到目标tab之后跳到目标tab的上一个位置,并且offset好像并没有生效,还是有tabbar height的偏移错误

onObserve: (resultModel) {
            _tabController.index = ObserverUtils.calcAnchorTabIndex(
              observeModel: resultModel,
              tabIndexs: tabIndexs,
              currentTabIndex: _tabController.index,
            );
          },

2.在我去掉onObserver后,点击tab偏移量基本正常,但是在第一个标签和最后一个标签来回切换的时候,第一次能准确定位到最后一个标签,之后定位就会定位错误(但是一个个标签点过去就不会出错)

下面附上demo

查看代码
  
/*
 * @Author: LinXunFeng [email protected]
 * @Repo: https://github.com/LinXunFeng/flutter_scrollview_observer
 * @Date: 2022-08-08 00:20:03
 */
import 'package:flutter/material.dart';
import 'package:scrollview_observer/scrollview_observer.dart';

class AnchorListPage extends StatefulWidget {
const AnchorListPage({Key? key}) : super(key: key);

@override
State createState() => _AnchorListPageState();
}

class _AnchorListPageState extends State
with SingleTickerProviderStateMixin {
ScrollController scrollController = ScrollController();

late ListObserverController observerController;
late TabController _tabController;
List tabs = ["0", "1", "2", "3", "4"];
List tabIndexs = [0, 1, 2, 3, 4];
double TAB_HEIGHT = 48;
double opacity = 0.0;
GlobalKey tabbarKey = GlobalKey();
List containerHeight = [310, 210, 400, 270, 1000];

@override
void initState() {
super.initState();
observerController = ListObserverController(controller: scrollController);
_tabController = TabController(length: tabs.length, vsync: this);
scrollController.addListener(() => _onScrollChanged());
}

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

/// 滑动事件
void _onScrollChanged() {
/// 滑动显示tabbar的触发距离
double showTabBarOffset = 350;

// 滑动距离大于触发距离时显示tabbar
if (scrollController.offset >= showTabBarOffset) {
  setState(() {
    opacity = 1;
  });
} else {
  // 滑动距离小于触发距离显示动态透明度
  setState(() {
    opacity = scrollController.offset / showTabBarOffset;
    if (opacity < 0) {
      opacity = 0;
    }
  });
}

}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('demo')),
body: Stack(children: [
ListViewObserver(
controller: observerController,
child: _buildListView(),
// onObserve: (resultModel) {
// _tabController.index = ObserverUtils.calcAnchorTabIndex(
// observeModel: resultModel,
// tabIndexs: tabIndexs,
// currentTabIndex: _tabController.index,
// );
// },
),
Positioned(
top: 0,
height: TAB_HEIGHT,
child: Opacity(
opacity: opacity,
key: tabbarKey,
child: Container(
color: Colors.white,
width: MediaQuery.of(context).size.width,
height: TAB_HEIGHT,
child: TabBar(
controller: _tabController,
tabs: tabs.map((e) => Tab(text: e)).toList(),
labelColor: Colors.black,
onTap: (value) {
observerController.animateTo(
index: value,
duration: const Duration(milliseconds: 250),
curve: Curves.ease,
offset: (offset) {
// return ObserverUtils.calcPersistentHeaderExtent(
// key: tabbarKey,
// offset: offset,
// );
return TAB_HEIGHT;
},
);
},
),
),
),
),
]),
);
}

ListView _buildListView() {
return ListView.separated(
controller: scrollController,
itemBuilder: (ctx, index) {
return _buildListItemView(index);
},
separatorBuilder: (ctx, index) {
return _buildSeparatorView();
},
itemCount: tabIndexs.length,
);
}

Widget _buildListItemView(int index) {
Widget item = Container();

switch (index) {
  case 0:
    item = Container(
      height: 565,
      color: Colors.red,
      child: Center(
        child: Text('index -- $index'),
      ),
    );

    break;
  case 1:
    item = Container(
      height: 207,
      color: Colors.red,
      child: Center(
        child: Text('index -- $index'),
      ),
    );
    break;
  case 2:
    item = Container(
      height: 262,
      color: Colors.red,
      child: Center(
        child: Text('index -- $index'),
      ),
    );
    break;
  case 3:
    item = Container(
      height: 400,
      color: Colors.red,
      child: Center(
        child: Text('index -- $index'),
      ),
    );
    break;
  case 4:
    item = Container(
      height: 1000,
      color: Colors.red,
      child: Center(
        child: Text('index -- $index'),
      ),
    );
    break;
}

return item;

}

Container _buildSeparatorView() {
return Container(
color: Colors.white,
height: 5,
);
}
}

展示消息时间时,无法保留当前滚动位置的问题

大佬,我这边聊天列表会展示消息时间,具体规则是 如果两条消息的发送时间的分钟数一样,则第二条消息不展示时间。
用这个组件在插入新的消息时, standy方法没有效果,还是会出现抖动的情况。
在您的demo里面类似加上以下代码,就会复现:
image

聊天场景效果

怎么做到现在像微信聊天那样,有新消息,有个新消息出现的过度效果?

关于ReorderableListView的定位问题

您好,请问现在支持ReorderableListView这个组件的定位么
我的页面是有一个switch按钮可以切换显示的列表,一个是listview.builder,一个是ReorderableListView,当我单独在listview.builder中使用时,时正常的,但时加上ReorderableListView的就会失效并且滚动列表的时候会报错。错误如下

======== Exception caught by gesture ===============================================================
The following assertion was thrown while handling a gesture:
Cannot get renderObject of inactive element.

In order for an element to have a valid renderObject, it must be active, which means it is part of the tree.
Instead, this element is in the _ElementLifecycle.defunct state.
If you called this method from a State object, consider guarding it with State.mounted.
The findRenderObject() method was called for the following element: SliverMultiBoxAdaptorElement#006f4(DEFUNCT)
no widget
When the exception was thrown, this was the stack:
#0 Element.findRenderObject. (package:flutter/src/widgets/framework.dart:4006:9)
#1 Element.findRenderObject (package:flutter/src/widgets/framework.dart:4019:6)
#2 ListObserverMix.handleListObserve (package:scrollview_observer/src/listview/list_observer_mix.dart:23:22)
#3 ListViewObserverState.handleObserve (package:scrollview_observer/src/listview/list_observer_view.dart:63:12)
#4 ObserverWidgetState._handleContexts (package:scrollview_observer/src/common/observer_widget.dart:163:34)
#5 ObserverWidgetState.build. (package:scrollview_observer/src/common/observer_widget.dart:93:11)
#6 NotificationListener._dispatch (package:flutter/src/widgets/notification_listener.dart:151:42)
#7 Notification.visitAncestor (package:flutter/src/widgets/notification_listener.dart:67:20)
#8 ViewportNotificationMixin.visitAncestor (package:flutter/src/widgets/scroll_notification.dart:31:18)
#9 Element.visitAncestorElements (package:flutter/src/widgets/framework.dart:4254:39)
#10 Notification.dispatch (package:flutter/src/widgets/notification_listener.dart:83:13)
#11 DragScrollActivity.dispatchScrollStartNotification (package:flutter/src/widgets/scroll_activity.dart:458:111)
#12 ScrollPosition.didStartScroll (package:flutter/src/widgets/scroll_position.dart:895:15)
#13 ScrollPosition.beginActivity (package:flutter/src/widgets/scroll_position.dart:887:7)
#14 ScrollPositionWithSingleContext.beginActivity (package:flutter/src/widgets/scroll_position_with_single_context.dart:114:11)
#15 ScrollPositionWithSingleContext.drag (package:flutter/src/widgets/scroll_position_with_single_context.dart:264:5)
#16 ScrollableState._handleDragStart (package:flutter/src/widgets/scrollable.dart:638:22)
#17 DragGestureRecognizer._checkStart. (package:flutter/src/gestures/monodrag.dart:429:53)
#18 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:198:24)
#19 DragGestureRecognizer._checkStart (package:flutter/src/gestures/monodrag.dart:429:7)
#20 DragGestureRecognizer.acceptGesture (package:flutter/src/gestures/monodrag.dart:349:7)
#21 GestureArenaManager._resolveInFavorOf (package:flutter/src/gestures/arena.dart:264:12)
#22 GestureArenaManager._resolve (package:flutter/src/gestures/arena.dart:223:9)
#23 GestureArenaEntry.resolve (package:flutter/src/gestures/arena.dart:53:12)
#24 OneSequenceGestureRecognizer.resolve (package:flutter/src/gestures/recognizer.dart:306:13)
#25 DragGestureRecognizer.handleEvent (package:flutter/src/gestures/monodrag.dart:317:11)
#26 PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:94:12)
#27 PointerRouter._dispatchEventToRoutes. (package:flutter/src/gestures/pointer_router.dart:139:9)
#28 _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:539:8)
#29 PointerRouter._dispatchEventToRoutes (package:flutter/src/gestures/pointer_router.dart:137:18)
#30 PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:123:7)
#31 GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:439:19)
#32 GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:419:22)
#33 RendererBinding.dispatchEvent (package:flutter/src/rendering/binding.dart:322:11)
#34 GestureBinding._handlePointerEventImmediately (package:flutter/src/gestures/binding.dart:374:7)
#35 GestureBinding.handlePointerEvent (package:flutter/src/gestures/binding.dart:338:5)
#36 GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:296:7)
#37 GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:279:7)
#41 _invoke1 (dart:ui/hooks.dart:170:10)
#42 PlatformDispatcher._dispatchPointerDataPacket (dart:ui/platform_dispatcher.dart:331:7)
#43 _dispatchPointerDataPacket (dart:ui/hooks.dart:94:31)
(elided 3 frames from dart:async)
Handler: "onStart"
Recognizer: VerticalDragGestureRecognizer#c6d11
start behavior: start

Error after upgrade Flutter 3.13.0

Hello LinXunFeng, after I upgraded my project to Flutter 3.13.0. I get an error like this:

/Users/karakol/.pub-cache/hosted/pub.dev/scrollview_observer-1.16.0/lib/src/utils/src/observer_utils.dart:195:32: Error: A value of type 'RenderObject?' can't be assigned to a variable of type 'AbstractNode?'.
 - 'RenderObject' is from 'package:flutter/src/rendering/object.dart' ('../../apps/flutter/packages/flutter/lib/src/rendering/object.dart').
 - 'AbstractNode' is from 'package:flutter/src/foundation/node.dart' ('../../apps/flutter/packages/flutter/lib/src/foundation/node.dart').
    AbstractNode? parent = obj.parent;
                               ^
/Users/karakol/.pub-cache/hosted/pub.dev/scrollview_observer-1.16.0/lib/src/utils/src/observer_utils.dart:198:16: Error: A value of type 'AbstractNode' can't be returned from a function with return type 'RenderViewportBase<ContainerParentDataMixin<RenderSliver>>?'.
 - 'AbstractNode' is from 'package:flutter/src/foundation/node.dart' ('../../apps/flutter/packages/flutter/lib/src/foundation/node.dart').
 - 'RenderViewportBase' is from 'package:flutter/src/rendering/viewport.dart' ('../../apps/flutter/packages/flutter/lib/src/rendering/viewport.dart').
 - 'ContainerParentDataMixin' is from 'package:flutter/src/rendering/object.dart' ('../../apps/flutter/packages/flutter/lib/src/rendering/object.dart').
 - 'RenderSliver' is from 'package:flutter/src/rendering/sliver.dart' ('../../apps/flutter/packages/flutter/lib/src/rendering/sliver.dart').
        return parent;
               ^
Failed to compile application.

Thank you,

监听滚动状态

我想监听ListViewObserver执行的滚动状态例如,observerController.animateTo点击后提供
滚动开始、滚动进行中、滚动即将结束(不知道好不好实现)、滚动结束 @LinXunFeng

聊天页面滚动跳动

image
在开发聊天页面的时候,Listview 的 reverse 设置为 true,即将展示的 item 有图片的时候滚动页面会跳动。请问有解决办法吗

1.14.0版本:异常报告

大佬,帮忙看下这个异常 是否有修复
Non-fatal Exception: Null check operator used on a null value
0 ??? 0x0 State-context + 954 (framework.dart:954)
1 ??? 0x0 ObserverWidgetState-fetchTargetSliverContexts + 201 (observer_widget.dart:201)
2 ??? 0x0 ObserverWidgetState-_setupSliverController. + 175 (observer_widget.dart:175)
3 ??? 0x0 SchedulerBinding-_invokeFrameCallback + 1289 (binding.dart:1289)
4 ??? 0x0 SchedulerBinding-handleDrawFrame + 1227 (binding.dart:1227)
5 ??? 0x0 SchedulerBinding-_handleDrawFrame + 1076 (binding.dart:1076)

scrolling fast on web show bad index item

Hi i try your example and when i scroll fast with mouse on web i see different item on screen and different values are printing on observer update

this is screen
image

and this is last print on console
firstChild.index -- 14
displaying -- [14]
item - 14 - -20 - 456
visible -- true
firstChild.index -- 24
displaying -- [24]
item - 24 - -20 - 456

any idea what is wrong?

是否支持flutter_staggered_grid_view 第三方库

我尝试把custom_scrollview_demo_page里面的SliverGrid替换成flutter_staggered_grid_view里的SliverMasonryGrid,没起作用。

    return SliverMasonryGrid(
      gridDelegate: const SliverSimpleGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 2, //Grid按两列显示
      ),
      delegate: SliverChildBuilderDelegate(
            (BuildContext context, int index) {
          _sliverGridCtx ??= context;
          return Container(
            color: (_hitIndexsForGrid.contains(index))
                ? Colors.green
                : Colors.blue[100],
            child: Center(
              child: Text('index -- $index'),
            ),
          );
        },
        childCount: 150,
      ),
    );
  }
  // Widget _buildSliverGridView() {
  //   return SliverGrid(
  //     gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
  //       crossAxisCount: 2, //Grid按两列显示
  //       mainAxisSpacing: 10.0,
  //       crossAxisSpacing: 10.0,
  //       childAspectRatio: 2.0,
  //     ),
  //     delegate: SliverChildBuilderDelegate(
  //       (BuildContext context, int index) {
  //         _sliverGridCtx ??= context;
  //         return Container(
  //           color: (_hitIndexsForGrid.contains(index))
  //               ? Colors.green
  //               : Colors.blue[100],
  //           child: Center(
  //             child: Text('index -- $index'),
  //           ),
  //         );
  //       },
  //       childCount: 150,
  //     ),
  //   );
  // }```

jumpTo() dose not work

hi.
when i renew elements of a listView.builder() , jumpTo() dose not work. it dose not jump.
consider a listView by 100 elements. when i change element counts to 150, jumpTo() dose not work.
can you help me please?

setState in onObserve stop to work after Flutter version 3.7.7

Hi, I am using the package for my book reading app.
I add the Widget to my seperated list;

Screen Shot 2023-03-13 at 12 16 51

After updating flutter version, the scrolling stop to work.

When I remove the setState, it works fine but I need to use setState.

Have you any idea how can I deal with this?

Have a nice day.
Thanks.

操作列表最后一个数据时会报错

RenderBox.size accessed beyond the scope of resize, layout, or permitted parent access. RenderBox can always access its own size, otherwise, the only object that is allowed to read RenderBox.size is its parent, if they have said they will. It you hit this assert trying to access a child's size, pass "parentUsesSize: true" to that child's layout().
'package:flutter/src/rendering/box.dart':
Failed assertion: line 1937 pos 13: 'debugDoingThisResize || debugDoingThisLayout || _computingThisDryLayout ||
(RenderObject.debugActiveLayout == parent && _size._canBeUsedByParent)'

列表中插入大于15条数据,列表会自己跳动

demo中chat_page.dart中按钮事件调用_addMessage方法,当数量大于15,插入数据后,offset异常,导致列表跳转。
我排查了一下,在observer_controller.dart中,通过findChildInfo获取targetChild存在问题,无法正确获取到targetChild导致列表变化

'controller != null': is not true

I've implemented the package properly, but when I try go to a spesific index, got this error.

I did:
listObserverController.jumpTo(index: 20);

Error:

_AssertionError ('package:scrollview_observer/src/common/observer_controller.dart': Failed assertion: line 88 pos 12: 'controller != null': is not true.)

瀑布流与tap同步滚动

用的库 waterfall_flow: ^3.0.2

我看了一下代码ListViewObserver 可以通过 onObserve ObserverUtils.calcAnchorTabIndex进行跳转
SliverViewObserver 这个是否可以通过类似方式快速同步滚动呢

我知道可以自己写监听事件来进行更新但不知道是否有更方便的方式

瀑布流代码
Widget _nobuildGridView() {
return WaterfallFlow.builder(
controller: scrollController,
itemCount:50,
gridDelegate: const SliverWaterfallFlowDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 15,
crossAxisSpacing: 10,
),
itemBuilder: (BuildContext context, int index) {
return Container(
width: 190,
height: 305,
decoration: BoxDecoration(
borderRadius: BorderRadius.all( Radius.circular(10)),
color: Colors.white
),
);
},
);
}

求教复杂效果实现

楼主,请问下有没有实现过在CustomScrollView中嵌套GrdiView并且滚动置顶Tab标签数据,然后点击Tab标签数据GridView也会滚动到想关联的位置的这种效果么?类似demo中Anchor ListView页面中的效果,只是上面的Tab是在CustomScrollView中,并且可以滚动置顶,然后点击“News”,“History”标签底部数据也会滚动相应数据位置。

[Desktop]Can not get onObserve callback

Env: Flutter 3.3.6
This is my code:

  Widget getContinuousThumbnailItem(WidgetRef ref) {
    Widget builder = ListView.builder(
        itemExtent: ctWidth,
        controller: scrollController,
        scrollDirection: Axis.horizontal,
        itemCount: getCTDisplayCount(ref),
        itemBuilder: (context, i) {
          return ContinuousThumbnailItem(
            width: ctWidth,
            height: ctHeight,
            index: i,
          );
        });
    builder = ListViewObserver(
      child: builder,
      onObserve: (resultModel) {
        print('firstChild.index -- ${resultModel.firstChild?.index}');
        print('displaying -- ${resultModel.displayingChildIndexList}');
      },
    );

    return builder;
  }

It seems that onObserve is not callback

[Bug report]

Version

1.16.5

Platforms

dart

Device Model

all phones

flutter info

[✓] Flutter (Channel stable, 3.13.7, on macOS 14.0 23A344 darwin-x64, locale en-TR)
    • Flutter version 3.13.7 on channel stable at /Users/mirzali/development/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 2f708eb839 (13 days ago), 2023-10-09 09:58:08 -0500
    • Engine revision a794cf2681
    • Dart version 3.1.3
    • DevTools version 2.25.0

[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.1)
    • Android SDK at /Users/mirzali/Library/Android/sdk
    • Platform android-33, build-tools 33.0.1
    • Java binary at: /Applications/Android Studio.app/Contents/jre/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.12+0-b1504.28-7817840)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 15.0)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 15A240d
    • CocoaPods version 1.13.0

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2021.2)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.12+0-b1504.28-7817840)

[✓] VS Code (version 1.83.1)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.74.0
[✓] Network resources
    • All expected network resources are available.

• No issues found!

How to reproduce?

alignemnt property not working as excepted in jump or animateTo

alignment: 0.5, I except the widget will be in the center.

observerController.animateTo(
                  sliverContext: _sliverListCtx,
                  index: 10,
                  duration: const Duration(milliseconds: 300),
                  curve: Curves.easeInOut,
                   alignment: 0.5,
                );
import 'package:flutter/material.dart';
import 'package:scrollview_observer/scrollview_observer.dart';
import 'package:scrollview_observer_example/typedefs.dart';

class CustomScrollViewDemoPage extends StatefulWidget {
  const CustomScrollViewDemoPage({Key? key}) : super(key: key);

  @override
  State<CustomScrollViewDemoPage> createState() => _CustomScrollViewDemoPageState();
}

class _CustomScrollViewDemoPageState extends State<CustomScrollViewDemoPage> {
  BuildContext? _sliverListCtx;

  int _hitIndexForCtx1 = 0;

  ScrollController scrollController = ScrollController();

  late SliverObserverController observerController;

  @override
  void initState() {
    super.initState();

    observerController = SliverObserverController(controller: scrollController);

    // Trigger an observation manually
    ambiguate(WidgetsBinding.instance)?.addPostFrameCallback((timeStamp) {
      observerController.dispatchOnceObserve(
        sliverContext: _sliverListCtx!,
      );
    });

    Future.microtask(() {
      observerController.jumpTo(
        index: 20,
        alignment: 0.5,
      );
    });
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("CustomScrollView")),
      body: SliverViewObserver(
        controller: observerController,
        child: CustomScrollView(
          controller: scrollController,
          slivers: [
            SliverList(
              delegate: SliverChildBuilderDelegate(
                (ctx, index) {
                  _sliverListCtx ??= ctx;
                  return Container(
                    height: 300,
                    color: _hitIndexForCtx1 == index ? Colors.red : Colors.black12,
                    child: Center(
                      child: Text(
                        "index -- $index",
                        style: TextStyle(
                          color: _hitIndexForCtx1 == index ? Colors.white : Colors.black,
                        ),
                      ),
                    ),
                  );
                },
                childCount: 30,
              ),
            ),
          ],
        ),
        sliverContexts: () {
          return [
            if (_sliverListCtx != null) _sliverListCtx!,
          ];
        },
      ),
      floatingActionButton: Padding(
        padding: const EdgeInsets.all(15.0),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.end,
          children: [
            IconButton(
              onPressed: () {
                observerController.animateTo(
                  sliverContext: _sliverListCtx,
                  index: 27,
                  duration: const Duration(milliseconds: 300),
                  curve: Curves.easeInOut,
                  alignment: 0.5,
                );
              },
              icon: const Icon(Icons.ac_unit_outlined),
            ),
          ],
        ),
      ),
    );
  }
}

聊天列表场景问题

根据案例代码编写,正常情况下没问题。
但是案例代码中是直接点击按钮插入的消息,少了一种情况。当主动发消息时,是需要键盘弹起的,这个时候滑动视图的最大高度和展示高度都发生了改变。发完消息就会发生错误。
standby方法中的observeSwitchShrinkWrap方法发生错误被捕捉,插件版本1.6.2-67行。报错如下
image
这个报错倒是没影响视图,影响视图的是另一个问题。isShrinkWrap变量错误的被设置。当键盘弹起的时候,最大高度变小,仅需几条消息即可超过最大高度可以滚动。键盘弹起后,发送消息或者收到消息会调用插入与standby并刷新视图,这个时候isShrinkWrap就会被标记为false,当键盘回收时,最大高度恢复,这个时候应当为true才是正确的。
刚接触大佬的代码哈,可能有点描述的不清楚

[Bug Report] Flutter 3.13 下编译失败

  • 今天 8.17 更新了flutter稳定版的 3.13,然后编译失败了:
>>> flutter run -d win


Launching lib\main.dart on Windows in debug mode...
Nuget.exe not found, trying to download or use cached version.
/C:/Users/24650/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/scrollview_observer-1.16.0/lib/src/utils/src/observer_utils.dart(195,32): error G44692867: A value of type 'RenderObject?' can't be assigned to a variable of type 'AbstractNode?'. [D:\0Acoolight\Program\flutter\mymusic\build\windows\flutter\flutter_assemble.vcxproj]     
/C:/Users/24650/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/scrollview_observer-1.16.0/lib/src/utils/src/observer_utils.dart(198,16): error G44692867: A value of type 'AbstractNode' can't be returned from a function with return type 'RenderViewportBase<ContainerParentDataMixin<RenderSliver>>?'. [D:\0Acoolight\Program\flutter\mymusic\build\windows\flutter\flutter_assemble.vcxproj]
C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Microsoft\VC\v170\Microsoft.CppCommon.targets(248,5): error MSB8066: ��D:\0Acoolight\Program\flutter\mymusic\build\windows\CMakeFiles\c6173e2f88e8998bd5fdf53160c40608\flutter_windows.dll.rule;D:\0Acoolight\Program\flutter\mymusic\build\windows\CMakeFiles\dfd910c006aa9d0d26d2e1aa797bcf2b\flutter_assemble.rule;D:\0Acoolight\Program\flutter\mymusic\windows\flutter\CMakeLists.txt�����Զ����������˳�������Ϊ 1�� [D:\0Acoolight\Program\flutter\mymusic\build\windows\flutter\flutter_assemble.vcxproj]
Building Windows application...                                    43.6s
Exception: Build process failed.
  • flutter doctor:

Flutter assets will be downloaded from https://storage.flutter-io.cn. Make sure you trust this source!
Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel stable, 3.13.0, on Microsoft Windows [版本 10.0.22621.2134], locale zh-CN)
[√] Windows Version (Installed version of Windows is version 10 or higher)
[√] Android toolchain - develop for Android devices (Android SDK version 33.0.0)
[√] Chrome - develop for the web
[√] Visual Studio - develop Windows apps (Visual Studio Community 2022 17.6.2)
[√] Android Studio (version 2022.2)
[√] IntelliJ IDEA Ultimate Edition (version 2021.3)
[√] Connected device (3 available)
[√] Network resources

不支持loading_more_list组件 (横向滚动)

Widget build(BuildContext context) {
    return Container(
      height: 60,
      width: context.screenWidth,
      decoration: BoxDecoration(color: context.appbarBackgroundColor),
      child: ListViewObserver(
        controller: observerController,
        child: LoadingMoreList(
          ListConfig<DailynewDateModel>(
              itemBuilder: (c, item, index) =>
                  renderItem(item, currentSelect, context),
              sourceList: repository,
              scrollDirection: Axis.horizontal,
              controller: scrollController,
              indicatorBuilder: (c, s) =>
                  LoadingMoreCustomLoadingWidgetWithDailynewDate(
                    status: s,
                    repository: repository,
                  )),
          onScrollNotification: (v) => true,
        ),
      ),
    );
  }
observerController.jumpTo(index: index);

没反应

Animation duration

I am using the package for a book that about 300 pages. When I want to go a spesific page, I am using

listObserverController.jumpTo(index: 150) Which is going to 150th page.

But it took a while to go to the page when I am in page 5. The screen animating (emulating) a real scroll. I wait until it reach the point I enter.

Is there a way to really Jump to the spesific index. Not animate.

InitState Jump

Hi! I face a problem about the package and wonder we can solve it or not.

I want to go a spesific index when I open my book.
After everything loaded, there is no problem I can go any page with enter number to method

listObserverController.jumpTo(index: 13);

But When I try to use it in initState, it just doesn't work. There is no error or anything.

my initState like this

  void initState() {
    super.initState();
    bookModel = context.read<BookProvider>();
    _scrollController = ScrollController(initialScrollOffset: widget.book.lastIndex);
    listObserverController = ListObserverController(controller: _scrollController);
    _scrollController.addListener(() {
      //Save the pageIndex for next come.
      bookModel.setSavePage(widget.book, _scrollController.offset);
    });

    WidgetsBinding.instance.addPostFrameCallback((_) {

        listObserverController.jumpTo(index: 13);
      
    });
  };

In first open, there is no move. When I reload the page with ctrl | cmd + S, listObserverController.jumpTo(index: 13); trigger and go the page.

When I don't use WidgetsBinding.instance.addPostFrameCallback it doesn't work also.

ListViewObserver下 onObserve 偶现不回调

场景:TabBar 结合 ListViewObserver->ListView 使用,数据量是超过了两屏的
操作:点击tab,获取tab index,执行controller.jumpTo(index)或者controller.animateTo(index), 特定情况下没有进入onObserve回调
特定情况:listview cellIndex=0 再执行controller.jumpTo(index),index =3,jumpTo 跳转正常。但是onObserve没有回调。
其它情况都正常:只要index 不是3,都能正常回调onObserve,或者 cellIndex >0 的情况,执行controller.jumpTo 也能正常回调onObserve。

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.