【问题标题】:flutter listview alphabet index颤振列表视图字母索引
【发布时间】:2019-04-25 06:00:24
【问题描述】:

如何在“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]}'),
                            ));
                      }),
                ),

【问题讨论】:

标签: listview flutter alphabet


【解决方案1】:

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

第 1 步: A 到 Z 滑块的手势检测器

  1. onVerticalDragUpdate:_onVerticalDragUpdate

  2. onVerticalDragStart: _onVerticalDragStart

第 2 步:为滚动字母添加对话气泡。

第三步:计算垂直滚动位置的索引

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

【讨论】:

  • 嗨,我刚刚实现了上面给出的与 A 到 Z 滑块相关的逻辑。
  • 请分享你的库到 dartpub
【解决方案2】:

拥有这样的东西:

开头部分

要解决此问题,您需要创建一个自定义小部件,该小部件将返回一个 LayoutBuilder,其中包含一个 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 移动滚动条

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

如何做到这一点?

在你的初始化函数中,你设置你的ScrollController 添加一个 _scrollController.addListener(onscrolllistview); 知道用户何时会直接在ListView 中滚动。

在您的 onscrolllistviewfunction 中,您需要进行一些计算才能显示第一个项目和最后一个项目。

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 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

【讨论】:

    【解决方案3】:

    你可以尝试做这样的事情:

             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]}'),
                          ),
                        ),
                      ),
                    );
                  },
                ),
              )
    

    【讨论】:

      猜你喜欢
      • 2020-12-23
      • 2020-12-28
      • 1970-01-01
      • 1970-01-01
      • 2020-06-19
      • 2012-08-09
      • 2018-04-26
      • 2018-12-06
      • 2018-10-26
      相关资源
      最近更新 更多