颤振listview字母索引

时间:2018-11-22 14:13:41

标签: listview flutter alphabet

如何像“ recyclerview字母表索引在android中”那样颤动地获得手指移动事件,请检查示例图像。

我已经创建了位置字母索引列表视图,但是在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]}'),
                            ));
                      }),
                ),

enter image description here

3 个答案:

答案 0 :(得分:3)

执行以下步骤以实现此目的。

第一步:用于A到Z滑块的手势检测器

  1. onVerticalDragUpdate:_onVerticalDragUpdate

  2. onVerticalDragStart:_onVerticalDragStart

第2步::为滚动字母添加语音提示。

步骤3:计算垂直滚动位置的索引

if ((_offsetContainer + details.delta.dy) >= 0 &&
        (_offsetContainer + details.delta.dy) <=
            (_sizeheightcontainer - _heightscroller)) {
    _offsetContainer += details.delta.dy;
    posSelected =
        ((_offsetContainer / _heightscroller) % _alphabet.length).round();
    _text = _alphabet[posSelected];
    if (_text != _oldtext) {
        for (var i = 0; i < exampleList.length; i++) {
            if (_text
                    .toString()
                    .compareTo(exampleList[i].toString().toUpperCase()[0]) == 0) {
                _controller.jumpTo(i * _itemsizeheight);
                break;
            }
        }
        _oldtext = _text;
    }
}

有关完整实施的信息,请检查以下内容:

https://github.com/sanjaysingh1990/AtoZSliderCustomized.git

答案 1 :(得分:1)

要拥有这样的东西:

Exemple

初始部分

要解决此问题,您需要创建一个自定义窗口小部件,该窗口小部件将返回包含LayoutBuilder的{​​{1}},其中Stack的第一层包含ListView,而Container包含第二层(作为滚动条)在右边(将滚动条放在右边,将alignment: Alignment.topRight添加到Stack中。)

移动滚动条

要移动滚动条,请添加GestureDetector并捕获onVerticalDragUpdate,使用自定义属性_offsetContainer到您要添加的details.delta.dy(来自事件)中让您的滚动条上下滚动。

从滚动条中移动ListView

第一部分

此后,您需要向ScrollController中添加ListView来控制它的垂直移动(作为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()];

第三部分

现在您知道字母了,那么移动您的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;
   }
}

现在您有了索引,只需使用ScrollController移动ListView

_scrollController.animateTo(index * _itemsizeheight,                         
   duration: new Duration(milliseconds: 500),
   curve: Curves.ease);

使滚动条从ListView中移出

好,现在可以了,但是我们也需要移动滚动条,不是吗?我的意思是当V向我显示ListView个字母项目时,我不希望它停留在A字母上。

如何执行此操作?

在您设置自己的ScrollController之后,请在init函数中添加一个 _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;

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

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

fletter var将取决于滚动方向。

如果您要向下走,它将是:

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

如果您要向上走,将会是:

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

修复滚动动画

现在确定,如果您放置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;
        }
   }

现在只需将滚动条的代码围拢在onscrolllistview中,

if (_animationcounter == 0) {/*...your code...*/}

PS

您需要_offsetContainer照顾自己,以免越界。 例如,您可以这样做:

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

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

答案 2 :(得分:0)

您可以尝试执行以下操作:

         Material(
            child: ListView.builder(
              itemCount: alphabet.length,
              itemBuilder: (BuildContext context, int index) {
                var letterHeight = (SizeConfig.safeBlockVertical * 100) / 33;
                return GestureDetector(
                  onVerticalDragUpdate: (DragUpdateDetails detail) {
                    setState(() {
                      currentPosition += detail.delta.dy;
                    });
                  },
                  onVerticalDragEnd: (DragEndDetails detail) {
                    setState(() {
                      int letters = currentPosition > 0
                          ? ((currentPosition + letterHeight) / letterHeight)
                              .round()
                          : ((currentPosition - letterHeight) / letterHeight)
                              .round();
                      if (index + letters < alphabet.length) {
                        index += letters;
                      } else {
                        index = alphabet.length;
                      }

                      currentPosition = 0;
                      currentLetter = alphabet[index];
                    });
                  },
                  child: InkWell(
                    onTap: () {
                      setState(() {
                        currentLetter = alphabet[index];
                      });
                    },
                    child: Container(
                      height: letterHeight,
                      child: Center(
                        child: Text('${alphabet[index]}'),
                      ),
                    ),
                  ),
                );
              },
            ),
          )