颤振列表视图字母索引

Posted

技术标签:

【中文标题】颤振列表视图字母索引【英文标题】: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]'),
                            ));
                      ),
                ),

【问题讨论】:

pub.dartlang.org/packages/side_header_list_view 有点类似 或者这个:pub.dartlang.org/packages/draggable_scrollbar 这正是您所寻求的:pub.dev/packages/alphabet_list_scroll_view 【参考方案1】:

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

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

    onVerticalDragUpdate:_onVerticalDragUpdate

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

【讨论】:

以上是关于颤振列表视图字母索引的主要内容,如果未能解决你的问题,请参考以下文章

做个简单的Android列表字母索引控件

html Miva - 显示分类列表的字母索引

联系人列表字母排序索引

如何将 NSArray 拆分为按字母顺序排列的部分以与索引表视图一起使用

iOS UITableView字母索引——系统自带检索栏

具有快速滚动和字母部分索引的 Android ListView