google / flutter.widgets

https://pub.dev/packages/flutter_widgets
BSD 3-Clause "New" or "Revised" License
1.38k stars 486 forks source link

[visibility_detector] Not working in Sliver after updating to 4.0.0 #462

Open crizant opened 1 year ago

crizant commented 1 year ago

Problem description

The visibility_detector package does not work properly after updating from 0.3.3 to 0.4.0+2.

Steps to reproduce

Here is the minimum snippet to reproduce the issue:

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:visibility_detector/visibility_detector.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: MyHomePage(),
    );
  }
}

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

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final GlobalKey _detectorKey = GlobalKey();
  final StreamController<List<int>> _streamController = StreamController();
  int _maxIndex = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Column(
          children: [
            TextButton(
              onPressed: () {
                _maxIndex += 30;
                final List<int> data = [];
                for (var i = 0; i < _maxIndex; i++) {
                  data.add(i);
                }
                _streamController.sink.add(data);
              },
              child: const Text('Add data to list'),
            ),
            Expanded(
              child: CustomScrollView(
                slivers: [
                  StreamBuilder(
                    stream: _streamController.stream,
                    builder: (BuildContext context, snapshot) {
                      return SliverList(
                        delegate: SliverChildListDelegate(
                          snapshot.data?.map((int index) {
                                return Container(
                                  padding: const EdgeInsets.all(20.0),
                                  child: Text('$index'),
                                );
                              }).toList() ??
                              [],
                        ),
                      );
                    },
                  ),
                  SliverToBoxAdapter(
                    child: VisibilityDetector(
                      key: _detectorKey,
                      child: Container(
                        padding: const EdgeInsets.symmetric(
                          vertical: 8.0,
                          horizontal: 15.0,
                        ),
                        child: const Text('SECTION HEADER'),
                      ),
                      onVisibilityChanged: (info) {
                        debugPrint(
                          'info.visibleFraction=${info.visibleFraction}',
                        );
                      },
                    ),
                  ),
                  SliverToBoxAdapter(
                    child: Container(
                      height: 1000,
                      color: Colors.blue,
                    ),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

Expected behavior

After clicking the "Add data to list" button, the "section header" is pushed downward in the list, which is invisible. The onVisibilityChanged callback should be executed, showing info.visibleFraction=0.0.

Actual behavior

The onVisibilityChanged callback is not executed when the "section header" is pushed downward.

Environment

Additional details

It used to work on visibility_detector 0.3.3, and stopped to work on 0.4.0+2.

mrverdant13 commented 1 year ago

I feel the recommended approach would be the use of SliverVisibilityDetector.

crizant commented 1 year ago

I feel the recommended approach would be the use of SliverVisibilityDetector.

Oh, I didn't know they have it. But after testing, it still doesn't work. Here is the updated code, did I do anything wrong?

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:visibility_detector/visibility_detector.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: MyHomePage(),
    );
  }
}

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

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final GlobalKey _detectorKey = GlobalKey();
  final StreamController<List<int>> _streamController = StreamController();
  int _maxIndex = 0;

  @override
  void initState() {
    super.initState();
    VisibilityDetectorController.instance.updateInterval = Duration.zero;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Column(
          children: [
            TextButton(
              onPressed: () {
                _maxIndex += 30;
                final List<int> data = [];
                for (var i = 0; i < _maxIndex; i++) {
                  data.add(i);
                }
                _streamController.sink.add(data);
              },
              child: const Text('Add data to list'),
            ),
            Expanded(
              child: CustomScrollView(
                slivers: [
                  StreamBuilder(
                    stream: _streamController.stream,
                    builder: (BuildContext context, snapshot) {
                      return SliverList(
                        delegate: SliverChildListDelegate(
                          snapshot.data?.map((int index) {
                                return Container(
                                  padding: const EdgeInsets.all(20.0),
                                  child: Text('$index'),
                                );
                              }).toList() ??
                              [],
                        ),
                      );
                    },
                  ),
                  SliverVisibilityDetector(
                    key: _detectorKey,
                    sliver: SliverToBoxAdapter(
                      child: Container(
                        padding: const EdgeInsets.symmetric(
                          vertical: 8.0,
                          horizontal: 15.0,
                        ),
                        child: const Text('SECTION HEADER'),
                      ),
                    ),
                    onVisibilityChanged: (info) {
                      debugPrint(
                        'info.visibleFraction=${info.visibleFraction}',
                      );
                    },
                  ),
                  SliverToBoxAdapter(
                    child: Container(
                      height: 1000,
                      color: Colors.blue,
                    ),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}