类似于悬停式悬停的触摸处理-无需松开手指即可检测来自不同小部件的触摸

假设我在屏幕上有3个Container,它们通过改变颜色来做出触摸反应。当用户的手指放在他们的手指上时,它们应该改变颜色,而在触摸末端时,它们应该恢复正常。 我想要的是,即使在容器外部的屏幕上随机区域开始触摸时,这些容器也会做出反应。因此,基本上,我正在寻找的东西就像css悬停一样。

如果我分别用GestureDetector包装每个容器,它们将不会对从其外部开始的触摸事件做出反应。关于另一个问题(很遗憾,我现在没有链接),建议用一个GestureDetector包装所有容器,并为每个容器分配一个GlobalKey,以使它们彼此不同。

这是检测触摸手势的面板

class MyBoard extends StatefulWidget {
  static final keys = List<GlobalKey>.generate(3,(ndx) => GlobalKey());

  ...
}

class _MyBoardState extends State<MyBoard> {
  ...

  /// I control the number of buttons by the number of keys,/// since all the buttons should have a key
  List<Widget> makeButtons() {
    return MyBoard.keys.map((key) {
      // preapre some funcitonality here
      var someFunctionality;
      return MyButton(key,someFunctionality);
    }).toList();
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTapDown: (tapDownDetails) {
        handleTouch(context,tapDownDetails.globalPosition);
      },onTapUp: (tapUpDetails) {
        finishTouch(context);
      },onPanUpdate: (dragUpdateDetails) {
        handleTouch(context,dragUpdateDetails.globalPosition);
      },onPanEnd: (panEndDetails) {
        finishTouch(context);
      },onPanCancel: () {
        finishTouch(context);
      },child: Container(
        color: Colors.green,width: 300.0,height: 600.0,child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,children: makeButtons(),),);
  }

这是简单的MyButton

class MyButton extends StatelessWidget {
  final GlobalKey key;
  final Function someFunctionality;
  MyButton(this.key,this.someFunctionality) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Consumer<KeyState>(
      builder: (buildContext,keyState,child) {
        return Container(
          width: 100.0,height: 40.0,color: keyState.touchedKey == this.key ? Colors.red : Colors.white,);
      },);
  }
}

_MyBoardState中,这就是我处理检测到哪个MyButton被触摸的方式:

MyButton getTouchingButton(Offset globalPosition) {
    MyButton currentButton;
    // result is outside of [isTouchingMyButtonKey] for performance
    final result = BoxHitTestResult();

    bool isTouchingButtonKey(GlobalKey key) {
      RenderBox renderBox = key.currentContext.findRenderObject();
      Offset offset = renderBox.globalToLocal(globalPosition);
      return renderBox.hitTest(result,position: offset);
    }

    var key = MyBoard.keys.firstWhere(isTouchingButtonKey,orElse: () => null);
    if (key != null) currentButton = key.currentWidget;

    return currentButton;
  }

我正在使用提供程序包,而不是用MyBoard重建整个setState,而仅重建相关MyButton的相关部分。仍然每个按钮都有一个侦听器,该侦听器会在每次更新时重建,并且我正在使用GlobalKeyOn the flutter docs说:

  

全局密钥相对昂贵。如果您不需要上面列出的任何功能,请考虑改用Key,ValueKey,ObjectKey或UniqueKey。

但是,如果我们查看getTouchingButton方法,则我需要GlobalKey来获取renderBox对象并获取currentWidget。我还必须为每个GlobalKey进行一次hitTest。在触发onPanUpdate时重复此计算,这意味着用户的手指移动像素时。

UI的更新速度不够快。只需轻按一下(tapDown和tapUp以常规速度),您通常不会在MyButton上看到任何变化。

如果需要总结我的问题,当手指以更有效,更优雅的方式悬停在不同的小部件上时,如何从不同的小部件中检测到相同的单点触摸(不抬起)?

ppsda 回答:类似于悬停式悬停的触摸处理-无需松开手指即可检测来自不同小部件的触摸

由于目前还没有人回答,因此我正在分享自己的解决方案,最近我才知道。现在,我每次触摸都能看到视觉反应。它足够快,但是仍然感觉到UI上有一些延迟,并且感觉有点棘手,而不是具体的解决方案。如果有人可以提供更好的解决方案,我可以将其标记为可接受的答案


我的解决方案:

第一件事首先;由于我们必须检测到平移手势,并且我们正在使用onPanUpdateonPanEnd,因此我可以擦除onTapDownonTapUp,而只使用onPanStart。这也可以检测到不动的简单点击。

我也不再使用ProviderConsumer,因为它在每次更新时都会重建所有Consumer。当MyButton的数量增加时,这确实是一个大问题。我没有将MyButton变得简单而虚假,而是将触摸处理工作转移到了其中。每个MyButton都会保存当前被触摸的数据

“更新”按钮是这样的:

class NewButton extends StatefulWidget {
  NewButton(Key key) : super(key: key);
  @override
  NewButtonState createState() => NewButtonState();
}

class NewButtonState extends State<NewButton> {
  bool isCurrentlyTouching = false;

  void handleTouch(bool isTouching) {
    setState(() {
      isCurrentlyTouching = isTouching;
    });
    // some other functionality on touch
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      width: 100.0,height: 40.0,color: isTouched ? Colors.red : Colors.white,);
  }
}

通知NewButtonState不是私有的。我们将在检测触摸手势的地方使用globalKey.currentState.handleTouch(bool)

本文链接:https://www.f2er.com/3128324.html

大家都在问