改进Single-Finger平移体验

如果你构建面向 Windows Touch 的应用程序,它会自动提供基本的平移支持。 但是,可以使用 WM_GESTURE 消息为单指平移提供增强支持。

概述

若要改进单指平移体验,请使用以下步骤,如本主题的后续部分所述:

  • 创建具有滚动条和禁用轻拂的应用程序。
  • 添加对手势平移消息的支持。
  • 启用退回。

创建具有滚动条和禁用轻拂的应用程序

在开始之前,必须使用滚动条创建应用程序。 使用滚动条进行平移的旧版支持部分介绍了此过程。 如果要从示例内容开始,请转到该部分,使用滚动条创建应用程序,然后禁用轻拂。 如果已有一个具有正常运行的滚动条的应用程序,请禁用该部分中所述的轻拂。

添加对笔势平移消息的自定义平移支持

若要支持笔势平移消息,必须在 WndProc 方法中处理它们。 手势消息用于确定平移消息的水平和垂直增量。 增量用于更新滚动条对象,从而更新用户界面。

首先,更新 targetver.h 文件中的 Windows 版本设置以启用 Windows Touch。 以下代码显示了应替换 targetver.h 中的各种 Windows 版本设置。

#ifndef WINVER                  // Specifies that the minimum required platform is Windows Vista.
#define WINVER 0x0601           // Change this to the appropriate value to target other versions of Windows.
#endif

#ifndef _WIN32_WINNT            // Specifies that the minimum required platform is Windows Vista.
#define _WIN32_WINNT 0x0601     // Change this to the appropriate value to target other versions of Windows.
#endif

接下来,将 UXTheme.h 文件添加到项目,并将 uxtheme.lib 库添加到项目的其他依赖项。

#include <uxtheme.h>

接下来,将以下变量添加到 WndProc 函数的顶部。 这些将用于平移的计算。

// The following are used for the custom panning handler      
BOOL bResult = FALSE;

static int scale = 8;   // altering the scale value will change how fast the page scrolls
static int lastY = 0;   // used for panning calculations (initial / previous vertical position)
static int lastX = 0;   // used for panning calculations (initial / previous horizontal position)
GESTUREINFO gi;  

接下来,添加 WM_GESTURE 消息的处理程序,以便根据平移手势使用增量更新滚动条。 这为你提供了更精细的平移控制。

以下代码从 lParam 获取 GESTUREINFO 结构,保存结构中的最后一个 y 坐标,并确定更新滚动条对象的位置更改。 以下代码应放置在 WndProc switch 语句中。

    case WM_GESTURE:        
        // Get all the vertial scroll bar information
        si.cbSize = sizeof (si);
        si.fMask  = SIF_ALL;
        GetScrollInfo (hWnd, SB_VERT, &si);
        yPos = si.nPos;

        ZeroMemory(&gi, sizeof(GESTUREINFO));
        gi.cbSize = sizeof(GESTUREINFO);
        bResult = GetGestureInfo((HGESTUREINFO)lParam, &gi);

        if (bResult){
            // now interpret the gesture            
            switch (gi.dwID){
                case GID_BEGIN:
                   lastY = gi.ptsLocation.y;
                   CloseGestureInfoHandle((HGESTUREINFO)lParam);
                   break;                     
                // A CUSTOM PAN HANDLER
                // COMMENT THIS CASE OUT TO ENABLE DEFAULT HANDLER BEHAVIOR
                case GID_PAN:                                                  
                    
                    si.nPos -= (gi.ptsLocation.y - lastY) / scale;

                    si.fMask = SIF_POS;
                    SetScrollInfo (hWnd, SB_VERT, &si, TRUE);
                    GetScrollInfo (hWnd, SB_VERT, &si);                                                        
                                               
                    yOverpan -= lastY - gi.ptsLocation.y;
                    lastY = gi.ptsLocation.y;
                     
                    if (gi.dwFlags & GF_BEGIN){
                        BeginPanningFeedback(hWnd);
                        yOverpan = 0;
                    } else if (gi.dwFlags & GF_END) {
                        EndPanningFeedback(hWnd, TRUE);
                        yOverpan = 0;
                    }
                           
                    if (si.nPos == si.nMin || si.nPos >= (si.nMax - si.nPage)){                    
                        // we reached the bottom / top, pan
                        UpdatePanningFeedback(hWnd, 0, yOverpan, gi.dwFlags & GF_INERTIA);
                    }
                    ScrollWindow(hWnd, 0, yChar * (yPos - si.nPos), NULL, NULL);
                    UpdateWindow (hWnd);                    
                                        
                    return DefWindowProc(hWnd, message, lParam, wParam);
                case GID_ZOOM:
                   // Add Zoom handler 
                   return DefWindowProc(hWnd, message, lParam, wParam);
                default:
                   // You have encountered an unknown gesture
                   return DefWindowProc(hWnd, message, lParam, wParam);
             }          
        }else{
            DWORD dwErr = GetLastError();
            if (dwErr > 0){
                // something is wrong 
                // 87 indicates that you are probably using a bad
                // value for the gi.cbSize
            }
        } 
        return DefWindowProc (hWnd, message, wParam, lParam);

现在,当你在窗口上执行平移手势时,你将看到文本以惯性滚动。 此时,你可能希望将文本更改为包含更多行,以便可以浏览平移大段文本。

WndProc 中的边界反馈

边界反馈是当用户到达可平移区域的末尾时向用户提供的一种视觉反馈。 当达到边界时,应用程序会触发它。 在WM_GESTURE消息的上一个示例实现中,WM_GESTURE事例中的结束条件(si.nPos == si.yPos)用于测试是否已到达可平移区域的末尾。 以下变量用于跟踪值和测试错误。

// The following are used for panning feedback (Window Bounce)
static int animCount = 0;
static DWORD dwErr   = 0;

static BOOL isOverpan  = FALSE;
static long xOverpan   = 0;
static long yOverpan   = 0;

平移手势大小写已更新为触发边界反馈。 以下代码演示了 WM_GESTURE 消息处理程序中的 GID_PAN 情况。

                case GID_PAN:                                                  
                    
                    si.nPos -= (gi.ptsLocation.y - lastY) / scale;

                    si.fMask = SIF_POS;
                    SetScrollInfo (hWnd, SB_VERT, &si, TRUE);
                    GetScrollInfo (hWnd, SB_VERT, &si);                                                        
                                               
                    yOverpan -= lastY - gi.ptsLocation.y;
                    lastY = gi.ptsLocation.y;
                     
                    if (gi.dwFlags & GF_BEGIN){
                        BeginPanningFeedback(hWnd);
                        yOverpan = 0;
                    } else if (gi.dwFlags & GF_END) {
                        EndPanningFeedback(hWnd, TRUE);
                        yOverpan = 0;
                    }
                           
                    if (si.nPos == si.nMin){                    
                        // we reached the top, pan upwards in y direction
                        UpdatePanningFeedback(hWnd, 0, yOverpan, gi.dwFlags & GF_INERTIA);
                    }else if (si.nPos >= (si.nMax - si.nPage)){
                        // we reached the bottom, pan downwards in y direction
                        UpdatePanningFeedback(hWnd, 0, yOverpan, gi.dwFlags & GF_INERTIA);
                    }
                    ScrollWindow(hWnd, 0, yChar * (yPos - si.nPos), NULL, NULL);
                    UpdateWindow (hWnd);                    
                                        
                    return DefWindowProc(hWnd, message, lParam, wParam);
  

现在,当用户平移过滚动条区域底部时,应用程序的窗口应具有边界反馈。

Windows 触控手势

BeginPanningFeedback

EndPanningFeedback

UpdatePanningFeedback