字母索引快速定位

字母索引快速定位

关于Context的获取

将Widegt写到方法体中与单独写成一个Wiget的区别在于能否拿到context

///右栏的字母表
  Widget _buildLetterIndexView(BuildContext context) => Positioned(
      // top: getScreenUtilHeight(55),
      right: 0,
      bottom: 75,
      width: ScreenUtil().setHeight(30),
      child: Container(
          alignment: Alignment.centerLeft,
          padding: EdgeInsets.symmetric(vertical: ScreenUtil().setHeight(5)),
          color: Colors.transparent,
          // color: Colors.amberAccent,
          child: Column(
            children: _presenter
                .getIndexTags()
                .map((letter) => GestureDetector(
                    onTapDown: (details) {
                      setState(() {
                        _onTap = letter;
                        jumpToLetter(letter);
                      });
                    },
                    onTapUp: (details) {
                      setState(() {
                        _onTap = '';
                      });
                    },
                    onLongPressStart: (details) {
                      setState(() {
                        _onTap = letter;
                      });
                      jumpToLetter(letter);
                    },
                    onLongPressEnd: (details) {
                      setState(() {
                        _onTap = '';
                      });
                    },
                    onVerticalDragStart: (start) {
                      //获取滑动点击的屏幕坐标
                      //获取点触摸到的标签的父盒子,indexBar
                      final RenderBox rb = context.findRenderObject();
                      //计算触摸点在父盒子中的相对位置
                      var local = rb.globalToLocal(start.globalPosition);
                      //获取单个标签的高度
                      final double hight =
                          rb.size.height / _presenter.getIndexTags().length;
                      print('hight:$hight');
                      //求当前触摸的标签的index
                      final int index =
                          (local.dy / _presenter.getIndexTags().length).round();
                      print('当前的index:$index');

                      setState(() {
                        if (index <= 0) {
                          _onTap = _presenter.getIndexTags().first;
                        } else if (index >= _presenter.getIndexTags().length) {
                          _onTap = _presenter.getIndexTags().last;
                        } else {
                          _onTap = _presenter.getIndexTags()[index];
                        }
                      });
                      jumpToLetter(_onTap);
                    },
                    onVerticalDragUpdate: (details) {
                      //获取滑动点击的屏幕坐标
                      //获取点触摸到的标签的父盒子,indexBar

                      final RenderBox rb = context.findRenderObject();
                      //计算触摸点在父盒子中的相对位置
                      print('position:${details.globalPosition}');
                      print('position:${details.localPosition}');
                      var local = rb.globalToLocal(details.globalPosition);
                      print('position:$local');
                      //获取单个标签的高度
                      final double hight =
                          rb.size.height / _presenter.getIndexTags().length;
                      print('hight:$hight');
                      //求当前触摸的标签的index
                      final int index = (local.dy / hight).round();
                      print('当前的index:$index');

                      setState(() {
                        if (index <= 0) {
                          _onTap = _presenter.getIndexTags().first;
                        } else if (index >= _presenter.getIndexTags().length) {
                          _onTap = _presenter.getIndexTags().last;
                        } else {
                          _onTap = _presenter.getIndexTags()[index];
                        }
                      });
                      jumpToLetter(_onTap);
                    },
                    onVerticalDragEnd: (details) {},
                    child: Padding(
                        padding: EdgeInsets.only(
                            top: ScreenUtil().setHeight(1),
                            bottom: ScreenUtil().setHeight(1)),
                        child: Container(
                            // color: Colors.blueAccent,
                            decoration: BoxDecoration(
                              borderRadius: BorderRadius.circular(80),
                              color: _onTap == letter
                                  ? Colours.black.withAlpha(50)
                                  : Colors.transparent,
                            ),
                            width: ScreenUtil().setWidth(30),
                            height: ScreenUtil().setHeight(16),
                            child: Center(
                                child: Text(
                              letter,
                              textAlign: TextAlign.center,
                              style: TextStyle(
                                fontSize: ScreenUtil().setSp(Dimens.superfine),
                                color: _onTap == letter
                                    ? Colours.white
                                    : Colours.darkGray,
                                fontWeight: Weights.bold,
                              ),
                            ))))))
                .toList(),
          )));

  ///跳转到指定的字母位置
  void jumpToLetter(String letter) {
    final index = _presenter.findLastStartLetterIndex(letter);
    //计算顶部到[AllContacts]的固定距离
    // final RenderBox top = _topHightGlobalkey.currentContext.findRenderObject();
    // final RenderBox contactsGroupTitle =
    // _contactsGroupTitleGlobalKey.currentContext.findRenderObject();
    // final RenderBox contacts =
    //     _contactsGlobalKey.currentContext.findRenderObject();

    // final itemHight = contacts.size.height / (_presenter.currentContactsLength);
    final itemHight = ScreenUtil().setHeight(90);

    if (index != -1) {
      _letterPositions[letter] = index * itemHight;
      print('itemHight:$itemHight');
      print('高度:${_letterPositions[letter]}');
    }

    if (_letterPositions.isNotEmpty) {
      final _pos = _letterPositions[letter];

      if (_pos != null) {
        _scrollController.animateTo(
            _pos.clamp(0, _scrollController.position.maxScrollExtent),
            duration: const Duration(microseconds: 200),
            curve: Curves.easeOut);
      }
    }
  }

当前的index:7

flutter: position:Offset(409.0, 204.3) //detail获取的全局坐标

flutter: position:Offset(22.2, -142.1) //detail获取的局部坐标

flutter: position:Offset(409.0, 204.3) //获取indexBar的触摸点全局坐标转换为局部坐标

flutter: hight:27.25925925925926

可以看到通过方法体_buildLetterIndexView()来生成的的indexBar,我们是无法通过context获取到它内部的相对坐标的。也就是说这里通过final RenderBox rb = context.findRenderObject();获取的是外部的Widget

class _IndexBarState extends State<IndexBar> {
  ///用于控制字母的对应位置
  Map<String, double> _letterPositions = {};

  ///第一个字母开始的位置
  ///按下时的标志
  String _onTap = '';

  ///跳转到指定的字母位置
  void jumpToLetter(String letter) {
    final index = widget.presenter.findLastStartLetterIndex(letter);
    final itemHight = ScreenUtil().setHeight(90);

    if (index != -1) {
      _letterPositions[letter] = index * itemHight;
      print('itemHight:$itemHight');
      print('高度:${_letterPositions[letter]}');
    }

    if (_letterPositions.isNotEmpty) {
      final _pos = _letterPositions[letter];

      if (_pos != null) {
        widget.scrollController.animateTo(
            _pos.clamp(0, widget.scrollController.position.maxScrollExtent),
            duration: const Duration(microseconds: 200),
            curve: Curves.easeOut);
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return Positioned(
        // top: getScreenUtilHeight(55),
        right: 0,
        bottom: 75,
        width: ScreenUtil().setHeight(30),
        child: Container(
            alignment: Alignment.centerLeft,
            padding: EdgeInsets.symmetric(vertical: ScreenUtil().setHeight(5)),
            color: Colors.transparent,
            // color: Colors.amberAccent,
            child: Column(
              children: widget.presenter
                  .getIndexTags()
                  .map((letter) => GestureDetector(
                      onTapDown: (details) {
                        setState(() {
                          _onTap = letter;
                          jumpToLetter(letter);
                        });
                      },
                      onTapUp: (details) {
                        setState(() {
                          _onTap = '';
                        });
                      },
                      onLongPressStart: (details) {
                        setState(() {
                          _onTap = letter;
                        });
                        jumpToLetter(letter);
                      },
                      onLongPressEnd: (details) {
                        setState(() {
                          _onTap = '';
                        });
                      },
                      onVerticalDragStart: (start) {
                        //获取滑动点击的屏幕坐标
                        //获取点触摸到的标签的父盒子,indexBar
                        final RenderBox rb = context.findRenderObject();
                        //计算触摸点在父盒子中的相对位置
                        final local = rb.globalToLocal(start.globalPosition);
                        //获取单个标签的高度
                        final double hight = rb.size.height /
                            widget.presenter.getIndexTags().length;
                        print('hight:$hight');
                        //求当前触摸的标签的index
                        final int index = (local.dy / hight).round();
                        print('当前的index:$index');

                        setState(() {
                          if (index <= 0) {
                            _onTap = widget.presenter.getIndexTags().first;
                          } else if (index >=
                              widget.presenter.getIndexTags().length) {
                            _onTap = widget.presenter.getIndexTags().last;
                          } else {
                            _onTap = widget.presenter.getIndexTags()[index];
                          }
                        });
                        jumpToLetter(_onTap);
                      },
                      onVerticalDragUpdate: (details) {
                        //获取滑动点击的屏幕坐标
                        //获取点触摸到的标签的父盒子,indexBar

                        final RenderBox rb = context.findRenderObject();
                        //计算触摸点在父盒子中的相对位置
                        print('position:${details.localPosition}');
                        print('position:${details.localPosition}');
                        var local = rb.globalToLocal(details.globalPosition);
                        print('position:${details.localPosition}');
                        //获取单个标签的高度
                        final double hight = rb.size.height /
                            widget.presenter.getIndexTags().length;
                        print('hight:$hight');
                        //求当前触摸的标签的index
                        final int index = (local.dy / hight).round();
                        print('当前的index:$index');

                        setState(() {
                          if (index <= 0) {
                            _onTap = widget.presenter.getIndexTags().first;
                          } else if (index >=
                              widget.presenter.getIndexTags().length) {
                            _onTap = widget.presenter.getIndexTags().last;
                          } else {
                            _onTap = widget.presenter.getIndexTags()[index];
                          }
                        });
                        jumpToLetter(_onTap);
                      },
                      onVerticalDragEnd: (details) {},
                      child: Padding(
                          padding: EdgeInsets.only(
                              top: ScreenUtil().setHeight(1),
                              bottom: ScreenUtil().setHeight(1)),
                          child: Container(
                              // color: Colors.blueAccent,
                              decoration: BoxDecoration(
                                borderRadius: BorderRadius.circular(80),
                                color: _onTap == letter
                                    ? Colours.black.withAlpha(50)
                                    : Colors.transparent,
                              ),
                              width: ScreenUtil().setWidth(30),
                              height: ScreenUtil().setHeight(16),
                              child: Center(
                                  child: Text(
                                letter,
                                textAlign: TextAlign.center,
                                style: TextStyle(
                                  fontSize:
                                      ScreenUtil().setSp(Dimens.superfine),
                                  color: _onTap == letter
                                      ? Colours.white
                                      : Colours.darkGray,
                                  fontWeight: Weights.bold,
                                ),
                              ))))))
                  .toList(),
            )));
  }
}

当前的index:19

flutter: itemHight:81.57635467980296

flutter: 高度:1631.5270935960593

flutter: position:Offset(401.3, 523.0) //detail获取的全局坐标

flutter: position:Offset(14.5, 307.0) //detail获取的局部坐标

flutter: position:Offset(14.5, 311.6) //获取indexBar的触摸点全局坐标转换为局部坐标

flutter: hight:16.650976099251963

IndexBar封装成一个Widegt,此时的全局坐标与局部坐标并不一致,说明此时通过final RenderBox rb = context.findRenderObject();获取的的确是'IndexBar'自身了

所以,导致滑动时,滑动标签项与手势滑动不一致的原因在于context没有真正拿到IndexBar,获取到局部坐标。

参考:

单击字母跳转定位

快速定位

快速滑动定位Demo

siderBar实现

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值