颤动列表视图字母索引

Ani*_*lil 6 listview alphabet flutter

如何在颤动中获取手指移动事件,例如“android 中的 recyclerview 字母索引”检查示例图像。

我创建了一个定位字母索引列表视图,但在 DragUpdate 中找不到当前索引。

            var alphabet = ["#","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"];

            new Positioned(
                top: .0,
                left: 1,
                bottom: 10,
                width: 55,
                child: Material(
                  borderRadius: BorderRadius.circular(15.0),
                  elevation: 10.0,
                  child: ListView.builder(
                      itemCount: alphabet.length,
                      itemBuilder: (BuildContext context, int index) {


                        return new GestureDetector(
                            onVerticalDragUpdate:
                                (DragUpdateDetails detail) {
                              setState(() {
                                _barOffset += detail.delta.dy;
                              });

                              print("$detail");
                              print("Update ${alphabet[index]}");
                            },

                             onVerticalDragStart: (DragStartDetails detail) {
                              print("onVerticalDragStart");
                              print("Start ${alphabet[index]}");
                            },
                            onVerticalDragEnd: (DragEndDetails detail) {
                              print("onVerticalDragEnd");
                              print("End ${alphabet[index]}");
                            },
                            onTap: () => print(alphabet[index]),
                            child: new Container(
                              margin: EdgeInsets.only(
                                  left: 20.0, right: 10.0, top: 6.5),
                              height: 15.0,
                              child: new Text('${alphabet[index]}'),
                            ));
                      }),
                ),
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

OOM*_*OOM 2

要有这样的东西:

示例

初始部分

为了解决这个问题,您需要创建一个自定义小部件,该小部件将返回一个LayoutBuilderwho 包含一个Stackwho 包含一个ListView在第一层和一个Container在第二层(作为滚动条)的右侧(将滚动条放在右侧添加alignment: Alignment.topRight到您的Stack)。

移动滚动条

要移动滚动条,请添加 aGestureDetector并捕获onVerticalDragUpdate添加,请使用自定义属性_offsetContainer,您将添加details.delta.dy(从事件中)以使滚动条向下和向上移动。

让 ListView 从滚动条中移动

第一部分

之后,您需要添加一个ScrollControllerListView控制它的垂直移动(作为controller属性)。

好的,现在您需要了解多个内容才能继续:

  • 你的字母数组长度
  • 您的身高尺寸ListView
  • 滚动条的高度尺寸
  • 对项目集合进行排序(逻辑)
  • 您的一件商品的高度尺寸ListView(我们称之为_itemsizeheight

现在要达到的目标是移动ListView列表中以所选字母开头的第一项。

为此,你需要一些数学知识和一些技巧。

要计算您的ListView身高,您需要获取身体高度并删除其他小部件的高度。但为了简化,我们会说你ListView占据了所有的身高。那么它对应contrainsts.biggest.height(感谢LayoutBuilder)。

要计算滚动条高度,您可以有效地将主体高度除以字母表数组中的字母数。 _heightscroller = contrainsts.biggest.height / _alphabet.length;

第二部分

我们首先将使用小部件使滚动条显示字母索引Text。然后将一个Text小部件添加到您的控制器,并_text在自定义小部件中添加一个属性,以允许您使用该功能更改它setState

在你的onVerticalDragUpdate你有_offset与你的滚动条位置相对应的值。然后您需要进行一个“简单”计算来找到它对应的字母数组的女巫索引。

_text = _alphabet[((_offsetContainer / _heightscroller) % _alphabet.length).round()];
Run Code Online (Sandbox Code Playgroud)

第三方

现在您知道了这封信,那么移动您的ListView. 首先获取列表中与所选字母对应的第一个元素的索引。

例子:

var index = 0;
for (var i = 0; i < widget.items.length; i++) {
   if (widget.items[i].toString().trim().length > 0 &&
       widget.items[i].toString().trim().toUpperCase()[0] ==
       _text.toString().toUpperCase()[0]) {
      index = i;
      break;
   }
}
Run Code Online (Sandbox Code Playgroud)

现在您已经有了索引,只需使用您的ScrollController来移动您的ListView.

_scrollController.animateTo(index * _itemsizeheight,                         
   duration: new Duration(milliseconds: 500),
   curve: Curves.ease);
Run Code Online (Sandbox Code Playgroud)

从 ListView 中移动滚动条

好的,现在它可以工作了,但是我们也需要移动滚动条不是吗?V我的意思是,当ListView将显示我的信件项目时,我不希望它留在信件上 A

这个怎么做 ?

在您的 init 函数中,您可以设置ScrollController添加 _scrollController.addListener(onscrolllistview);以了解用户何时会直接在ListView.

在您的onscrolllistview函数中,您需要一些计算来显示第一个项目和最后一个项目。

var indexFirst = ((_scrollController.offset / _itemsizeheight) % widget.items.length).floor();
var indexLast = ((((_heightscroller * _alphabet.length) / _itemsizeheight).floor() + indexFirst) - 1) % widget.items.length;
Run Code Online (Sandbox Code Playgroud)

现在完美了,您可以轻松地知道需要在滚动条上显示的女巫字母,然后知道它需要在哪里(更改其偏移量)。

var i = _alphabet.indexOf(fletter);
        if (i != -1) {
          setState(() {
            _text = _alphabet[i];
            _offsetContainer = i * _heightscroller;
          });
Run Code Online (Sandbox Code Playgroud)

varfletter将取决于滚动的方向。

如果你往下走,那就是:

var fletter = widget.items[indexLast].toString().toUpperCase()[0];

如果你向上走的话会是:

var fletter = widget.items[indexFirst].toString().toUpperCase()[0];

修复滚动动画

好的,现在如果您输入 a,debugPrint您将可以看到该onscrolllistview函数始终被调用,即使我们使用滚动条也是如此。这是个问题。那么如何解决呢?

当所有动画完成时,您需要知道何时完成移动。

然后只需_animationcounter在您的类中添加一个属性即可。当您移动滚动条时,您将增加它,并在一个动画完成时减少它。像这样:

for (var i = 0; i < widget.items.length; i++) {
   if (widget.items[i].toString().trim().length > 0 &&
       widget.items[i].toString().trim().toUpperCase()[0] ==
       _text.toString().toUpperCase()[0]) {
     _animationcounter++;
     _scrollController.animateTo(i * _itemsizeheight,
             duration: new Duration(milliseconds: 500),
             curve: Curves.ease) .then((x) => {_animationcounter--});
             break;
        }
   }
Run Code Online (Sandbox Code Playgroud)

onscrolllistview现在只需围绕您的滚动条移动代码

if (_animationcounter == 0) {/*...your code...*/}
Run Code Online (Sandbox Code Playgroud)

聚苯乙烯

你需要照顾好自己,_offsetContainer不要越界。你可以这样做,例如:

if ((_offsetContainer + details.delta.dy) >= 0 &&
                  (_offsetContainer + details.delta.dy) <=
                      (context.size.height - _heightscroller)) {
                _offsetContainer += details.delta.dy;
    }
Run Code Online (Sandbox Code Playgroud)

该解决方案可能可以优化(不发送多个动画,添加 var 减少计算)。您可以在这里找到完整的实现: AtoZscrollflutter