展开图块时如何滚动ExpansionTile/Listview? [英] How to scroll an ExpansionTile / Listview when a tile is expanded?

查看:11
本文介绍了展开图块时如何滚动ExpansionTile/Listview?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们在 ListView 中有一堆 ExpansionTile(到目前为止还不算太疯狂,对吧?).我们的用户希望我们在打开 ExpansionTile 时自动滚动"列表,这样新的扩展磁贴现在位于屏幕顶部(或尽可能位于顶部),因此他们不会不必手动滚动查看我们刚刚打开的内容.

We have a bunch of ExpansionTile within a ListView (so far not too crazy, right?). Our users would like us to "auto scroll" the list when they open up an ExpansionTile so the new expanded tile is now at the top (or as top as it can be) of the screen so they don't have to manually scroll to see what we just opened.

我认为我们需要像 ListView 上的 ScrollController 之类的东西——并注册一个 onExpansionChanged .. 来做.. 某事.这对我来说有点模糊.:)

I think we need something like a ScrollController on the ListView -- and to register an onExpansionChanged .. to do .. something. It's the something that's more than a bit vague to me. :)

任何有关如何执行此操作的指示或帮助将不胜感激!

Any pointers or help on how to do this would be greatly appreciated!

TIA!

推荐答案

如果我得到了你的要求,基本上是一种自动滚动你的 ExpansionTile 的方法,这样用户就没有手动执行以查看其内容,对吗?

If I got right what your asking for, is basically a way to scroll automatically your ExpansionTile up so the user doesn't have to do it manually to see its content, right?

然后,您实际上可以在 ListView 中使用 ScrollController 并利用 ExpansionTileonExpansionChanged 回调code> 以根据磁贴的大小与其当前位置相应地向上/向下滚动.

Then, you can actually use a ScrollController in your ListView and take advantage of the onExpansionChanged callback of the ExpansionTile to scroll it up/down accordingly to the size of the tile vs. its current position.

但现在你想知道:我怎么知道要滚动多少?

But now you are wondering: how do I know how much to scroll?

为此,您可以通过给它一些约束(例如构建一个 Container(heigh: 100.0)) 或者在这个特定场景中知道构建小部件时的精确高度.,您不知道 ExpansionTile 高度将占用多少像素.因此,我们可以使用 GlobalKey,然后通过在运行时检查它的 RenderBox 来检查它的渲染高度,以了解准确折叠时它占用了多少像素并乘以它的索引.

For that, either you know previously how exactly is the height of your widget when constructing it by giving it some constraints (like building a Container(heigh: 100.0)) or, in this particular scenario, you don't know exactly how many pixels the ExpansionTile height will take. So, we can use a GlobalKey and then check its rendering height by checking its RenderBox at runtime to know exactly how many pixels it's taking when collapsed and multiply it by its index.

  ExpansionTile _buildExpansionTile(int index) {
    final GlobalKey expansionTileKey = GlobalKey();
    double previousOffset;

    return ExpansionTile(
      key: expansionTileKey,
      onExpansionChanged: (isExpanded) {
        if (isExpanded) previousOffset = _scrollController.offset;
        _scrollToSelectedContent(isExpanded, previousOffset, index, expansionTileKey);
      },
      title: Text('My expansion tile $index'),
      children: _buildExpansionTileChildren(),
    );
  }

好的,现在我们有了一个 ListView,它将在其生成器中使用这个 _buildExpansionTile 和一个 GlobalKey.当我们展开 tile 时,我们还保存了 ListView 的滚动偏移量.但是,我们如何真正向上滚动以显示其内容?让我们看看 _scrollToSelectedContent 方法.

Ok, now we have a ListView that will use this _buildExpansionTile in its generator with a GlobalKey. We are also saving the scroll offset of the ListView when we expand the tile. But, how do we actually scroll up to show its content? Let's see the _scrollToSelectedContent method.

  void _scrollToSelectedContent(bool isExpanded, double previousOffset, int index, GlobalKey myKey) {
    final keyContext = myKey.currentContext;

    if (keyContext != null) {
      // make sure that your widget is visible
      final box = keyContext.findRenderObject() as RenderBox;
      _scrollController.animateTo(isExpanded ? (box.size.height * index) : previousOffset,
          duration: Duration(milliseconds: 500), curve: Curves.linear);
    }
  }

因此,我们通过其键访问渲染对象,然后使用 ListView 滚动控制器在展开时向上滚动,在折叠时通过将其高度乘以它的索引向下滚动回其初始位置.您不必向后滚动,这只是我对这个示例的个人偏好.这将导致如下结果:

So, we are accessing the render object by its key and then use the ListView scroll controller to scroll up when expanded and down back to its initial position when collapsed by multiplying its height with its index. You don't have to scroll back, it was just my personal preference for this example. This will result in something like this:

你有完整的例子在 StatefulWidget

import 'package:flutter/material.dart';

void main() => runApp(MaterialApp(home: MyApp()));

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final ScrollController _scrollController = ScrollController();

  void _scrollToSelectedContent(bool isExpanded, double previousOffset, int index, GlobalKey myKey) {
    final keyContext = myKey.currentContext;

    if (keyContext != null) {
      // make sure that your widget is visible
      final box = keyContext.findRenderObject() as RenderBox;
      _scrollController.animateTo(isExpanded ? (box.size.height * index) : previousOffset,
          duration: Duration(milliseconds: 500), curve: Curves.linear);
    }
  }

  List<Widget> _buildExpansionTileChildren() => [
        FlutterLogo(
          size: 50.0,
        ),
        Text(
          'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse vulputate arcu interdum lacus pulvinar aliquam. Donec ut nunc eleifend, volutpat tellus vel, volutpat libero. Vestibulum et eros lorem. Nam ut lacus sagittis, varius risus faucibus, lobortis arcu. Nullam tempor vehicula nibh et ornare. Etiam interdum tellus ut metus faucibus semper. Aliquam quis ullamcorper urna, non semper purus. Mauris luctus quam enim, ut ornare magna vestibulum vel. Donec consectetur, quam a mattis tincidunt, augue nisi bibendum est, quis viverra risus odio ac ligula. Nullam vitae urna malesuada magna imperdiet faucibus non et nunc. Integer magna nisi, dictum a tempus in, bibendum quis nisi. Aliquam imperdiet metus id metus rutrum scelerisque. Morbi at nisi nec risus accumsan tempus. Curabitur non sem sit amet tellus eleifend tincidunt. Pellentesque sed lacus orci.',
          textAlign: TextAlign.justify,
        ),
      ];

  ExpansionTile _buildExpansionTile(int index) {
    final GlobalKey expansionTileKey = GlobalKey();
    double previousOffset;

    return ExpansionTile(
      key: expansionTileKey,
      onExpansionChanged: (isExpanded) {
        if (isExpanded) previousOffset = _scrollController.offset;
        _scrollToSelectedContent(isExpanded, previousOffset, index, expansionTileKey);
      },
      title: Text('My expansion tile $index'),
      children: _buildExpansionTileChildren(),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('MyScrollView'),
      ),
      body: ListView.builder(
        controller: _scrollController,
        itemCount: 100,
        itemBuilder: (BuildContext context, int index) => _buildExpansionTile(index),
      ),
    );
  }
}

这篇关于展开图块时如何滚动ExpansionTile/Listview?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆