fluttercandies / flutter_scrollview_observer

A widget for observing data related to the child widgets being displayed in a ScrollView. Maintainer: @LinXunFeng
https://pub.dev/packages/scrollview_observer
MIT License
438 stars 47 forks source link

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

Closed mdddj closed 1 year ago

mdddj commented 1 year ago

以前关联的问题: https://github.com/LinXunFeng/flutter_scrollview_observer/issues/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

点击按钮没有响应

LinXunFeng commented 1 year ago

调整代码:

+ import 'package:extended_list/src/rendering/sliver_list.dart';

- customTargetRenderSliverType: (p0) => true,
+ customTargetRenderSliverType: (p0) {
+   return p0 is ExtendedRenderSliverList;
+ },

观察第三方库的滚动视图时,需要判断滚动视图所对应的 RenderObject 类型,你这里直接在 customTargetRenderSliverType 里返回 true 是不对的,会拿到错误的对象。

相关说明:1.4、customTargetRenderSliverType 回调

mdddj commented 1 year ago

emm,一些场景下还是不太行,我再试试能不能复现

mdddj commented 1 year ago

第一次 build 后小部件,跳转没反应,添加 key后跳转生效

mdddj commented 1 year ago

问题复现了: https://github.com/mdddj/ops_bug_demo 加了一个等待时间: await Future.delayed(const Duration(seconds: 3));


class _SourceRepository extends LoadingModel<String> {
  @override
  Future<bool> loadData([bool isLoadMoreAction = false]) async {
    await Future.delayed(const Duration(seconds: 3));
    addAll(List.generate(100, (index) => "$index"));
    return true;
  }
}
LinXunFeng commented 1 year ago

这个第三方库里的滚动视图是在拿到数据后才被渲染的,所以 ListViewObserver 在被渲染时拿不到相应的数据

重写 LoadingModel 里的 refresh 方法,在该方法内调用 ListObserverControllerreattach 重新附加一下就好

class _SourceRepository extends LoadingModel<String> {
+  _State state;
+
+  _SourceRepository(this.state) : super();
+
+  @override
+  Future<bool> refresh([bool notifyStateChanged = false]) {
+    final result = super.refresh(notifyStateChanged);
+    result.then((value) {
+      WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
+        state._ss.reattach();
+      });
+    });
+    return result;
+  }

  @override
  Future<bool> loadData([bool isLoadMoreAction = false]) async {
    await Future.delayed(const Duration(seconds: 3));
    addAll(List.generate(100, (index) => "$index"));
    return true;
  }
}
- sourceList: _SourceRepository(),
+ sourceList: _SourceRepository(model),
mdddj commented 1 year ago

太强了大佬👍👍