You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UWP InkCanvas触摸模式下自定义手势实现方法咨询

解决UWP InkCanvas触摸模式下无法使用自定义手势的问题

这个问题我之前踩过坑!核心原因很简单:当你把InkPresenter.InputDeviceTypes设为CoreInputDeviceTypes.Touch时,系统会默认将所有触摸输入直接路由给笔迹绘制逻辑,你的PointerPressed这类事件会被InkPresenter拦截,根本轮不到你的自定义代码处理。下面给你两种靠谱的解决方案,亲测有效:

方案一:使用UnprocessedInput处理手势(官方推荐)

InkPresenter专门提供了UnprocessedInput属性,用来处理那些还没被笔迹系统处理的输入,完美适配手势识别场景。你可以通过它来监听触摸输入,判断是否是手势,再决定要不要交给笔迹绘制。

示例代码如下:

private Point _gestureStartPoint;
private bool _isGestureDetected;

private void ink1_Loaded(object sender, RoutedEventArgs e)
{
    // 先设置好触摸输入类型
    ink1.InkPresenter.InputDeviceTypes = CoreInputDeviceTypes.Touch;
    
    // 监听UnprocessedInput的触摸事件
    ink1.InkPresenter.UnprocessedInput.PointerPressed += UnprocessedInput_PointerPressed;
    ink1.InkPresenter.UnprocessedInput.PointerMoved += UnprocessedInput_PointerMoved;
    ink1.InkPresenter.UnprocessedInput.PointerReleased += UnprocessedInput_PointerReleased;
}

private void UnprocessedInput_PointerPressed(InkUnprocessedInput sender, PointerEventArgs args)
{
    // 记录手势起始点
    var point = args.CurrentPoint.Position;
    _gestureStartPoint = new Point(point.X, point.Y);
    _isGestureDetected = false;
}

private void UnprocessedInput_PointerMoved(InkUnprocessedInput sender, PointerEventArgs args)
{
    if (_isGestureDetected) return;
    
    var currentPoint = args.CurrentPoint.Position;
    // 计算移动距离,这里设个阈值(比如20像素)判断是否是滑动手势
    double deltaX = Math.Abs(currentPoint.X - _gestureStartPoint.X);
    double deltaY = Math.Abs(currentPoint.Y - _gestureStartPoint.Y);
    
    if (deltaX > 20 || deltaY > 20)
    {
        // 检测到滑动手势,执行你的逻辑
        HandleSwipeGesture(deltaX > deltaY ? (currentPoint.X > _gestureStartPoint.X ? "右滑" : "左滑") : (currentPoint.Y > _gestureStartPoint.Y ? "下滑" : "上滑"));
        _isGestureDetected = true;
        // 标记输入已处理,阻止笔迹绘制
        args.Handled = true;
    }
}

private void UnprocessedInput_PointerReleased(InkUnprocessedInput sender, PointerEventArgs args)
{
    if (!_isGestureDetected)
    {
        // 没有检测到滑动,判断是否是点击/双击手势
        var currentPoint = args.CurrentPoint.Position;
        double delta = Math.Sqrt(Math.Pow(currentPoint.X - _gestureStartPoint.X, 2) + Math.Pow(currentPoint.Y - _gestureStartPoint.Y, 2));
        if (delta < 10)
        {
            // 点击手势,执行你的逻辑
            HandleTapGesture();
            args.Handled = true;
        }
    }
}

// 自定义手势处理方法
private void HandleSwipeGesture(string direction)
{
    // 这里写你的滑动手势逻辑,比如切换页面、删除笔迹等
    Debug.WriteLine($"检测到{direction}手势");
}

private void HandleTapGesture()
{
    // 这里写你的点击手势逻辑
    Debug.WriteLine("检测到点击手势");
}

方案二:临时切换InputDeviceTypes(应急方案)

如果你的手势逻辑比较简单,也可以在检测到可能的手势时,临时把InkPresenter的输入类型改成None,处理完手势再改回Touch。不过这个方法可能会有轻微的延迟,不如方案一流畅:

private void ink1_PointerPressed(object sender, PointerRoutedEventArgs e)
{
    var pointerPoint = e.GetCurrentPoint(ink1);
    if (pointerPoint.PointerDevice.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Touch)
    {
        // 临时关闭触摸输入,避免笔迹绘制
        ink1.InkPresenter.InputDeviceTypes = CoreInputDeviceTypes.None;
        // 记录起始点,后续判断手势
        _gestureStartPoint = pointerPoint.Position;
    }
}

private void ink1_PointerReleased(object sender, PointerRoutedEventArgs e)
{
    var pointerPoint = e.GetCurrentPoint(ink1);
    double delta = Math.Sqrt(Math.Pow(pointerPoint.Position.X - _gestureStartPoint.X, 2) + Math.Pow(pointerPoint.Position.Y - _gestureStartPoint.Y, 2));
    
    if (delta < 10)
    {
        // 点击手势处理
        HandleTapGesture();
    }
    else
    {
        // 滑动手势处理
        HandleSwipeGesture(/* 判断方向 */);
    }
    
    // 恢复触摸输入,允许笔迹绘制
    ink1.InkPresenter.InputDeviceTypes = CoreInputDeviceTypes.Touch;
    e.Handled = true;
}

关键注意点

  • 一定要用args.Handled = true来标记输入已处理,这样InkPresenter就不会再把这个触摸事件当成笔迹来处理了。
  • 手势的阈值(比如滑动距离、点击误差范围)可以根据你的需求调整,让手势识别更精准。

内容的提问来源于stack exchange,提问作者Kay

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 07:34:43