一统天下 flutter - 输入: 命中测试(hit test)

源码 https://github.com/webabcd/flutter_demo
作者 webabcd

一统天下 flutter - 输入: 命中测试(hit test)

示例如下:

lib\input\hit_test.dart

/*
 * 命中测试(hit test)
 *
 * hit test 的作用是根据事件的位置收集所有在该位置上的 widget,然后从最底层的节点开始向上将每个节点收集到一个集合中,最后根据这个集合进行事件分发
 * hit test 是在 RenderObject 上实现的
 */

import 'package:flutter/material.dart';
import 'package:flutter_demo/helper.dart';

class HitTestDemo extends StatefulWidget {
  const HitTestDemo({Key? key}) : super(key: key);

  @override
  _HitTestDemoState createState() => _HitTestDemoState();
}

class _HitTestDemoState extends State<HitTestDemo> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("title"),),
      backgroundColor: Colors.orange,
      body: Column(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: [
          /// HitTestBehavior.deferToChild - 子被命中了,则监听器被命中,这个是默认值
          /// 对于本例来说
          /// 1、MyText 被命中了,则 GestureDetector 被命中
          /// 2、如果是 Container 中的非 MyText 区域被命中了,则 GestureDetector 不会被命中
          GestureDetector(
            behavior: HitTestBehavior.deferToChild,
            child: Container(
              height: 50,
              alignment: Alignment.center,
              child: const MyText("webabcd"),
            ),
            onTap: () {
              log("onTap: ${currentTimestamp()}");
            },
          ),

          /// HitTestBehavior.opaque - 子被命中或者自己被命中,则监听器被命中
          /// 对于本例来说
          /// 1、MyText 被命中了,则 GestureDetector 被命中
          /// 2、如果是 Container 中的非 MyText 区域被命中了,则 GestureDetector 也会被命中
          GestureDetector(
            behavior: HitTestBehavior.opaque,
            child: Container(
              height: 50,
              alignment: Alignment.center,
              child: const MyText("webabcd"),
            ),
            onTap: () {
              log("onTap: ${currentTimestamp()}");
            },
          ),

          /// 如果 Container 设置了 color 则因为其对应的 _RenderColoredBox 的 behavior 是 HitTestBehavior.opaque
          /// 所以设置了 color 的 Container 的行为与 HitTestBehavior.opaque 一致
          GestureDetector(
            child: Container(
              height: 50,
              color: Colors.green,
              alignment: Alignment.center,
              child: const MyText("webabcd"),
            ),
            onTap: () {
              log("onTap: ${currentTimestamp()}");
            },
          ),

          /// HitTestBehavior.translucent - 与 HitTestBehavior.opaque 的行为一致,并且不会影响同级的上面的节点的命中测试
          /// 对于本例来说
          /// 1、MyText 被命中了,则 onTap2
          /// 2、如果是 Container 中的非 MyText 区域被命中了,则先 onTap2 再 onTap1(如果不是 translucent 则不会走到 onTap1)
          Stack(
            children: [
              Listener(
                child: Container(child: const MyText("webabcd"), width: 300, height: 50, alignment: Alignment.center, color: Colors.red),
                onPointerDown: (event) {
                  log("onTap1: ${currentTimestamp()}");
                },
              ),
              Listener(
                child: Container(child: const MyText("webabcd"), width: 300, height: 50, alignment: Alignment.center),
                onPointerDown: (event) {
                  log("onTap2: ${currentTimestamp()}");
                },
                behavior: HitTestBehavior.translucent,
              ),
            ],
          ),
        ],
      ),
    );
  }
}

源码 https://github.com/webabcd/flutter_demo
作者 webabcd

posted @ 2023-04-18 12:23  webabcd  阅读(131)  评论(0编辑  收藏  举报