Flutter ListView 滚动到索引滚动不足

Flutter ListView scroll to index insufficient scrolling

我有一个可展开的列表视图,但我有一个滚动问题。单独select滑动或者慢慢滑动都没有问题,但是滚动select快的时候就会滑动不足的问题

我加了一个'dartpad',这样代码就可以测试了。可能是什么问题?

代码:https://dartpad.dev/c4015095fc23456619eb20a5edcb0e8b
视频:https://vimeo.com/532603204

这是一个有趣的问题,我花了一些时间来处理这个问题,而且我在日志中看到滚动控制器似乎更新得很好。但是,出于某种原因,它不起作用,所以我在列表周围放置了滚动视图,并没有给 ListView.builder 滚动。只有这个要考虑的是列表的最后部分,因为如果你在最后部分,你不想向下滚动更多,因为你不能再向下滚动。

这可能不是最好的解决方案,但这是我设法组合在一起的,希望这对您有所帮助。

import 'dart:developer';

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Scroll Bug Demo',
      home: MainScreen(),
    );
  }
}

class MainScreen extends StatefulWidget {
  @override
  _MainScreenState createState() => _MainScreenState();
}

class _MainScreenState extends State<MainScreen> {
  final _demoList = List.generate(100, (index) => 'List Item $index');
  int _expandedIndex = -1;
  final _scrollController = ScrollController();

  bool _isExpanded = false;
  bool _isInLastPart = false;

  @override
  Widget build(BuildContext context) {
    _isInLastPart = (_expandedIndex > _demoList.length - 15);

    final _size = MediaQuery.of(context).size;
    return SafeArea(
      child: Scaffold(
        body: SingleChildScrollView(
          controller: _scrollController,
          child: SizedBox(
            height: (48 * _demoList.length).toDouble() +
                ((_isExpanded && _isInLastPart) ? 80 : 0).toDouble(),
            width: _size.width,
            child: ListView.builder(
              physics: NeverScrollableScrollPhysics(),
              itemBuilder: (context, index) {
                return GestureDetector(
                  onTap: () => clickItem(index),
                  child: Container(
                    color: Colors.grey,
                    height: (_expandedIndex == index && _isExpanded) ? 120 : 40,
                    margin: EdgeInsets.only(bottom: 8),
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        Text(_demoList[index]),
                        if (_expandedIndex == index && _isExpanded)
                          Column(
                            children: <Widget>[
                              Text('text'),
                              Text('text'),
                              Text('text'),
                              Text('text'),
                              Text('text'),
                            ],
                          ),
                      ],
                    ),
                  ),
                );
              },
              itemCount: _demoList.length,
            ),
          ),
        ),
      ),
    );
  }

  clickItem(int index) {
    setState(() {
      if (_expandedIndex == index)
        _isExpanded = !_isExpanded;
      else
        _isExpanded = true;
      _expandedIndex = index;
    });
    if (_expandedIndex < _demoList.length - 15) {
      // log("expanded index_: $_expandedIndex, index: $index, jump to: ${index * 48.toDouble()}/${99 * 48.toDouble()}, scroll> ${_scrollController.position.pixels},isExpanded: $_isExpanded");
      _scrollController.jumpTo(index * 48.toDouble());
    } else {
      if (_isExpanded) {
        // log("expanded index_: $_expandedIndex, index: $index, jump to: ${83 * 48.toDouble() + 8}/${99 * 48.toDouble()}, scroll> ${_scrollController.offset},isExpanded: $_isExpanded");

        _scrollController.jumpTo(83 * 48.toDouble() + 80 + 8);
      } else {
        // log("expanded index_: $_expandedIndex, index: $index, jump to: ${83 * 48.toDouble() + 80 + 8}/${99 * 48.toDouble()}, scroll> ${_scrollController.offset}, isExpanded: $_isExpanded");
        _scrollController.jumpTo(83 * 48.toDouble() + 8);
      }
    }
  }
}