Поделиться через


Краткое руководство: статические жесты (HTML)

[ Эта статья адресована разработчикам приложений среды выполнения Windows для Windows 8.x и Windows Phone 8.x. При разработке приложений для Windows 10 см. раздел последняя документация]

Используйте обработку событий основных жестов среды выполнения Windows и настраивайте взаимодействие пользователя для статических жестов, описанных в языке касаний Windows (таких как касание, двойное касание, нажатие и удерживание и правое касание).

Большинство приложений обрабатывают жесты касания (касания, сдвига, масштабирования и т. д.), а необработанные данные указателя просто передают средству обнаружения жестов, не используя их никаким иным образом. В этом образце мы используем необработанные данные указателя для поддержки обработки статического жеста, чтобы дополнить модель взаимодействия вашего приложения базовыми событиями указателя, о которых говорится в разделе Краткое руководство: указатели.

Обновления в Windows 8.1: В Windows 8.1 появилось множество обновлений и усовершенствований API ввода с помощью указателя. Подробнее: Изменения API для Windows 8.1.

Если у вас нет опыта в разработке приложений на JavaScript: Прочитайте эти разделы, чтобы ознакомиться с технологиями, обсуждаемыми в данной статье.

Создание первого приложения на JavaScript

Схема создания приложений на JavaScript

Информацию о событиях см. в разделе Краткое руководство: добавление элементов управления HTML и обработчиков событий

Компоненты приложения от начала до конца:

Дополнительные сведения об этой функциональности см. в нашей серии Компоненты приложения от начала до конца.

Взаимодействие с пользователем от А до Я (HTML)

Настройка взаимодействия с пользователем от А до Я (HTML)

Рекомендации по взаимодействию с пользователем:

Библиотеки элементов управления платформы (HTML и XAML) предоставляют все механизмы взаимодействия с пользователем, в том числе стандартные взаимодействия, анимированные физические эффекты и визуальную обратную связь. Если вы не планируете настраивать механизмы поддержки взаимодействий, используйте стандартные элементы управления.

Если элементов управления, предоставляемых платформой, недостаточно, то, чтобы обеспечить привлекательный и современный единый механизм взаимодействия для всех режимов ввода, вы можете воспользоваться следующими рекомендациями. В основном эти рекомендации описывают сенсорный ввод, но также применимы к вводу с сенсорной панели, мыши, клавиатуры и пера.

Примеры: Примеры использования этой функциональности см. в коллекции примеров приложений.

Пример настройки взаимодействия с пользователем от А до Я

Ввод: пример обработки событий указателя DOM

Ввод: пример управления и жестов (JavaScript)

Ввод: пример жестов Windows 8

Цель: Описывается ожидание и обработка статических жестов на основе данных, вводимых с помощью касания, мыши, пера и событий жестов среды выполнения Windows.

Необходимые условия

См. Краткое руководство: указатели и Краткое руководство: жесты и манипуляции DOM.

Предполагается, что вы умеете создавать простые приложения на JavaScript с использованием шаблона библиотеки Windows для JavaScript.

Для выполнения этого руководства вам необходимо:

Время для завершения: 30 мин.

Что такое события жестов?

Жест представляет собой физическое действие или движение, выполняемое устройством ввода или с устройства ввода (с помощью одного или нескольких пальцев на поверхности касания, пера, дигитайзера, мыши и т. д.). Такое естественное взаимодействие сопоставляется с операциями над элементами системы и вашего приложения. См. также раздел Жесты, манипуляции и взаимодействия.

В таблице ниже определяются статические жесты, рассмотренные в этом кратком руководстве.

ЖестОписание
Касание/двойное касаниеЖест касания

Одиночный контакт, который сразу же теряется или прерывается.

Касание элемента вызывает основное действие.

Двойное касание — это два быстрых последовательных касания. Его можно обрабатывать, как требуется вашему приложению.

  • Состояние на входе: обнаружен один контакт в ограничивающей объект прямоугольной области.
  • Движение: отсутствует.
  • Состояние на выходе: контакт потерян или прерван.
Нажатие и удерживание/правое касаниеЖест нажатия и удерживания

Одиночный контакт, который не перемещается до превышения порогового значения времени.

Такое взаимодействие с сенсорным экраном приводит к тому, что на нем появляются подробные сведения или обучающие визуальные эффекты (например, подсказка или контекстное меню) без необходимости выполнения действия.

Правое касание тесно связано с жестом нажатия и удерживания. Событие правого касания возникает, когда завершается жест нажатия и удерживания.

  • Состояние на входе: обнаружен один контакт в ограничивающей объект прямоугольной области.
  • Движение: отсутствует.
  • Состояние на выходе: контакт потерян или прерван.

Подробнее об этих жестах и их отношении к языку касаний Windows см. в разделе Взаимодействие с помощью сенсорного ввода.

 

Важно  Если вы реализуете собственную поддержку взаимодействий, помните: пользователи ожидают, что способ взаимодействия с элементами вашего приложения будет интуитивно понятным. Рекомендуется моделирование взаимодействий с пользователем на базе библиотек элементов управления платформы (HTML и XAML) для единообразия элементов и возможности их обнаруживать. Элементы управления в этих библиотеках предоставляют все механизмы взаимодействия с пользователем, в том числе стандартные взаимодействия, анимированные физические эффекты, визуальную обратную связь и специальные возможности. Создавайте пользовательские взаимодействия, только если они действительно необходимы и если ни один стандартный механизм взаимодействия не подходит для вашего сценария.

 

Создание пользовательского интерфейса

Этот пример — базовое приложение вопросов и ответов. Квадрат (inputBox) действует как целевой объект для обнаружения и обработки ввода от указателя и статических жестов. В этом объекте отображаются вопросы, подсказки и ответы.

См. ниже функциональные возможности взаимодействия пользователя, предоставляемые приложением.

  • Двойное касание: запуск и остановка вопросов и таймера приложения.
  • Касание: циклическое переключение между вопросами.
  • Нажатие и удерживание: отображается набор подсказок для текущего вопроса. Пока сохраняется контакт, каждые несколько секунд отображается новая подсказка. Такое поведение взаимодействия соответствует Рекомендациям по визуальной обратной связи и рекомендациям языка касаний, согласно которым жест нажатия и удерживания должен быть ограничен областью отображения информационного пользовательского интерфейса.
  • Правое касание (или завершение нажатия и удерживания): когда контакт разрывается, отображается всплывающее окно с вопросом к пользователю — нравится ли ему ответ. Повторим: мы придерживаемся рекомендаций для контекстного меню из раздела Рекомендации по визуальной обратной связи и языка касаний Windows. Примечание  Чтобы удержать внимание на коде обработки жестов, считывание данных вопроса и ответа из XML-файла, а также некоторые элементы пользовательского интерфейса и функциональные возможности приложения не реализованы полностью.  

HTML-код для этого примера.

<html>
<head>
    <meta charset="utf-8" />
    <title>js</title>

    <!-- WinJS references -->
    <link href="//Microsoft.WinJS.2.0/css/ui-dark.css" rel="stylesheet" />
    <script src="//Microsoft.WinJS.2.0/js/base.js"></script>
    <script src="//Microsoft.WinJS.2.0/js/ui.js"></script>

    <!-- BasicGesture references -->
    <link href="/css/default.css" rel="stylesheet" />
    <script src="/js/default.js"></script>
    <script src="/js/inputprocessor.js"></script>
    <script src="/js/datamanager.js"></script>
    <script src="/js/cluemanager.js"></script>
</head>
<body>
    <div class="TargetContainer" id="targetContainer">
        <div id="inputBox">
            <div id="instructions">Tap gray box below: Double tap to start questions, tap for next question, press and hold to show clues.</div>
            <div id="questions">&nbsp;</div>
            <div id="answers">
                <label for="answer">Answer:</label>
                <input type="text" id="answer" maxlength="30" size="30" style="z-index:1" />
                <button id="submit">Submit</button>
                <button id="stumped">Stumped</button>                
            </div>
            <div id="clues">
            </div>
            <div id="timerBox"></div>
        </div>
        <div id="eventLog"></div>

        <div id="answerFloater">
            <p>Show answer?</p>
            <button id="yes">Yes</button>
            <button id="no">No</button>
        </div>
    </div>
</body>
</html>

Код каскадных таблиц стилей (CSS) для этого примера.

Примечание  События указателя не генерируются в процессе взаимодействий сдвига или масштабирования. Сдвиг и масштабирование для области можно отключить при помощи таких свойств CSS, как msTouchAction, overflow и -ms-content-zooming.

 

body {
/*
A manipulation-blocking element is defined as an element that explicitly 
blocks direct manipulation via declarative markup, and instead fires gesture 
events such as MSGestureStart, MSGestureChange, and MSGestureEnd.
*/
    overflow: hidden;
    position: absolute;
    font-family: 'Segoe UI';
    font-size: small;
    touch-action: none;
    background-color: black;
}

div #targetContainer {
    position: relative;
    height: fill-available;
    width: fill-available;
}

div #inputBox {
    position: relative;
    width: 640px;
    height: 640px;
    color: black;
    overflow: hidden;
    background-color: darkgrey;
    margin: 0px;
    padding: 0px;
    border-width: 1px;
    border-color: white;
    border-style: solid;
}

div #instructions {
    position: relative;
    width: 100%;
    height: fit-content;
    color: black;
    background-color: white;
    visibility: visible;
}

div #questions {
    position: relative;
    width: 100%;
    height: fit-content;
    color: white;
    background-color: black;
    visibility: visible;
}

div #answers {
    position: relative;
    width: 100%;
    height: fit-content;
    color: white;
    background-color: black;
    visibility: visible;
}

div #clues {
    position: relative;
    width: 100%;
    height: 100%;
    background-color: DimGray;
}

div #timerBox {
    background-color: red;
    color: black;
    position: absolute;
    width: 100%;
    bottom: 0px;
    height: 20px;
    text-align: center;
}

div #answerFloater {
    position: absolute;
    visibility: hidden;
    top: 0px;
    left: 0px;
    background-color: blue;
}

div #eventLog {
    font-size: xx-small;
    position: absolute;
    left: 0px;
    top: 0px;
    width: 640px;
    height: 50px;
    overflow: auto;
    overflow-style: auto;
}

Инициализация приложения

Инициализируйте объект вопросов и ответов.

Здесь мы объявляем глобальные переменные и получаем ссылки на объекты пользовательского интерфейса.

var _applicationData;
var _localSettings;
var _data;
var _inputBox;
var _instructions;
var _answers;
var _questions;
var _clues;
var _eventLog;
var _floater;

function initialize() {
    // Get our UI objects.
    _inputBox = document.getElementById("inputBox");
    _instructions = document.getElementById("instructions");
    _questions = document.getElementById("questions");
    _answers = document.getElementById("answers");
    _clues = document.getElementById("clues");
    _eventLog = document.getElementById("eventLog");
    _floater = document.getElementById("answerFloater");

    // Configure the target.
    setTarget();
}

Затем мы размещаем пользовательский интерфейс вопросов и ответов и настраиваем объект взаимодействия для обработки данных вопроса и ответа из XML-файла. Дополнительную информацию об XML-данных для этого примера можно просмотреть в полном листинге в конце раздела.

// Configure the interaction target.
function setTarget() {
    //  Set the position of the input target.
    var inputLeft = (window.innerWidth - _inputBox.clientWidth) / 2.0;
    var inputTop = (window.innerHeight - _inputBox.clientHeight) / 2.0;
    var transform = (new MSCSSMatrix()).translate(inputLeft, inputTop);
    _inputBox.style.msTransform = transform;

    // Set the position of the event log.
    transform = (new MSCSSMatrix()).translate(inputLeft, inputTop + _inputBox.clientHeight);
    _eventLog.style.msTransform = transform;

    // Associate interaction target with our input manager.
    // Scope input to clue area only.
    _clues.inputProcessor = new QandA.InputProcessor(_clues);
}

Настройте распознаватель жестов.

Здесь задается обработка взаимодействия.

В большинстве случаев рекомендуется получать информацию об указателе через аргумент события обработчиков события указателя на выбранном языке платформы.

Если аргумент события не предоставляет сведения об указателе, необходимые вашему приложению, вы можете получить доступ к расширенным сведениям об указателе из аргумента события с помощью методов getCurrentPoint и getIntermediatePoints или свойств currentPoint иintermediatePoints. Рекомендуется использовать методы getCurrentPoint и getIntermediatePoints, так как для них можно указать контекст указателя данных.

Совет  В этом примере только один объект сопоставляется с распознавателем жестов. Если ваше приложение содержит большое количество объектов, которыми можно управлять (например, головоломка), рассмотрите возможность динамического создания распознавателя жестов только в моменты, когда на конечном объекте определяется ввод с помощью указателя. Распознаватель жестов может быть удален при завершении всех операций (см. пример жестов, который допускает создание экземпляров). Чтобы сократить временные затраты на создание и удаление распознавателей жестов, создайте небольшой пул распознавателей жестов при инициализации и динамически распределяйте их по мере необходимости.

 

Объект обработчика ввода включает распознаватель жестов (gr), который ожидает передачи данных и обрабатывает все события указателя и жестов. Пользовательским интерфейсом вопросов и ответов управляют обработчики событий распознавателя жестов.

// Handle gesture recognition for this sample.
(function () {
    "use strict";
    var InputProcessor = WinJS.Class.define(
    // Constructor
    function InputProcessor_ctor(target) {
        this._questionsStarted = false;
        this._tapCount = 0;
        // Create a clue manager.
        this._clueManager = new QandA.ClueManager();
        // Load xml data from file into local app settings.
        var _dataObject = new QandA.DataManager();
        _data = _dataObject.getData();

        this._questionTotal = _data.selectNodes("questions/question").length;
        this._doubleTap = false;
        this._startTime;
        this._intervalTimerId;

        // Initialize the gesture recognizer.
        this.gr = new Windows.UI.Input.GestureRecognizer();

        // Turn off visual feedback for gestures.
        // Visual feedback for pointer input is still displayed. 
        this.gr.showGestureFeedback = false;

        // Configure gesture recognizer to process the following:
        // double tap               - start questions and timer.
        // tap                      - move to next question.
        // right tap                - show answer.
        // hold and hold with mouse - start clues.
        this.gr.gestureSettings =
            Windows.UI.Input.GestureSettings.tap |
            Windows.UI.Input.GestureSettings.doubleTap |
            Windows.UI.Input.GestureSettings.rightTap |
            Windows.UI.Input.GestureSettings.hold |
            Windows.UI.Input.GestureSettings.holdWithMouse;

        //
        // Set event listeners.
        //
        // Get our context.
        var that = this;

        // Register event listeners for these gestures.
        this.gr.addEventListener('tapped', tappedHandler);
        this.gr.addEventListener("holding", holdingHandler);
        this.gr.addEventListener("righttapped", rightTappedHandler);

        // The following functions are registered to handle DOM pointer events
        //
        // Basic pointer handling to highlight input area.
        target.addEventListener("pointerover", function onPointerOver(eventInfo) {
            eventInfo.stopImmediatePropagation = true;
            _eventLog.innerText += "pointer over || ";
            eventInfo.target.style.backgroundColor = "DarkGray";
        }, false);
        // Basic pointer handling to highlight input area.
        target.addEventListener("pointerout", function onPointerOut(eventInfo) {
            eventInfo.stopImmediatePropagation = true;
            _eventLog.innerText += "pointer out || ";
            eventInfo.target.style.backgroundColor = "DimGray";
        }, false);
        // Handle the pointer move event.
        // The holding gesture is routed through this event.
        // If pointer move is not handled, holding will not fire.
        target.addEventListener("pointermove", function onPointerMove(eventInfo) {
            eventInfo.stopImmediatePropagation = true;
            // Get intermediate PointerPoints
            var pps = eventInfo.intermediatePoints;

            // Pass the array of PointerPoints to the gesture recognizer.
            that.gr.processMoveEvents(pps);
        }, false);
        // Handle the pointer down event.
        target.addEventListener("pointerdown", function onPointerDown(eventInfo) {
            eventInfo.stopImmediatePropagation = true;
            _eventLog.innerText += "pointer down || ";

            // Hide the floater if visible.
            _floater.style.visibility = "hidden";

            // Get the PointerPoint for the pointer event.
            var pp = eventInfo.currentPoint;

            // Get whether this pointer down event is within
            // the time threshold for a double tap.
            that._doubleTap = that.gr.canBeDoubleTap(pp);

            // Pass the PointerPoint to the gesture recognizer.
            that.gr.processDownEvent(pp);
        }, false);
        // Handle the pointer up event.
        target.addEventListener("pointerup", function onPointerUp(eventInfo) {
            eventInfo.stopImmediatePropagation = true;
            _eventLog.innerText += "pointer up || ";

            // Get the current PointerPoint
            var pp = eventInfo.currentPoint;

            // Pass the PointerPoint to the gesture recognizer.
            that.gr.processUpEvent(pp);
        }, false);

        // The following functions are registered to handle gesture events.
        //
        // This handler processes taps and double taps.
        // Potential double taps are identified in the pointer down handler.
        function tappedHandler(evt) {
            // Single tap and questions started: Display next question.
            if (!that._doubleTap && that._questionsStarted) {
                _eventLog.innerText += "tapped || ";
                _instructions.innerText = "Double tap to stop questions.";
                _clues.innerText = "";
                that._tapCount++;
                that._clueManager.tapCount = that.tapCount;
                if (that._tapCount > that._questionTotal) {
                    _questions.innerText = "No more questions.";
                } else {
                    var xpath = "questions/question[" + (that._tapCount % (that._questionTotal + 1)) + "]/q";
                    // Read data from a simple setting
                    _questions.innerText = _data.selectSingleNode(xpath).innerText;
                }
            }
                // Single tap and questions not started: Don't do much.
            else if (!that._doubleTap && !that._questionsStarted) {
                _eventLog.innerText += "tapped || ";
                _instructions.innerText = "Double tap to start questions.";
            }
                // Double tap and questions not started: Display first question.
            else if (that._doubleTap && !that._questionsStarted) {
                _eventLog.innerText += "double-tapped || ";
                // Return if last question displayed.
                if (that._tapCount > that._questionTotal) {
                    _questions.innerText = "No more questions.";
                    return;
                }
                // Start questions.
                that._questionsStarted = true;
                _instructions.innerText = "Starting questions (double tap to stop questions).";

                // Question number is based on tap count.
                that._tapCount++;

                // Select question from XML data object.
                var xpath = "questions/question[" + (that._tapCount % (that._questionTotal + 1)) + "]/q";
                _questions.innerText = _data.selectSingleNode(xpath).innerText;

                // Display a basic timer once questions started.
                that._startTime = new Date().getTime();
                that._intervalTimerId = setInterval(displayTimer, 100);
            }
                // Double tap and questions started: Stop questions and timer.
            else if (that._doubleTap && that._questionsStarted) {
                _eventLog.innerText += "double-tapped || ";
                _instructions.innerText = "Questions stopped (double tap to start questions).";
                that._questionsStarted = false;
                clearInterval(that._intervalTimerId);
            }
        };

        // For this app, we display a basic timer once questions start.
        // In a more robust app, could be used for achievements.
        function displayTimer() {
            var x = new Date().getTime();
            timerBox.innerText = (x - that._startTime) / 1000;
        }

        // This handler processes right taps.
        // For all pointer devices a right tap is fired on
        // the release of a press and hold gesture.
        // For mouse devices, righttapped is also fired on a right button click.
        // For pen devices, 
        function rightTappedHandler(evt) {
            if (!that._questionsStarted) {
                return;
            }
            var transform = (new MSCSSMatrix()).
                translate(
                (window.innerWidth - _inputBox.clientWidth) / 2.0 + evt.position.x,
                (window.innerHeight - _inputBox.clientHeight) / 2.0 + evt.position.y);
            _floater.style.visibility = "visible";
            _floater.style.msTransform = transform;
            eventLog.innerText = "right-tap || ";
        }

        // The pointer move event must also be handled because the 
        // holding gesture is routed through this event.
        // If pointer move is not handled, holding will not fire.
        // A holding event is fired approximately one second after 
        // a pointer down if no subsequent movement is detected.
        function holdingHandler(evt) {
            if (!that._questionsStarted)
                return;
            if (evt.holdingState == Windows.UI.Input.HoldingState.started) {
                _eventLog.innerText += "holding || ";
                // Create a clue manager.
                that._clueManager.tapCount = that._tapCount;
                // Start displaying clues.
                that._clueManager.displayClues();
            } else if (evt.holdingState == Windows.UI.Input.HoldingState.completed) {
                that._clueManager.destroy();
                _eventLog.innerText += "holding completed || ";
            } else {
                _eventLog.innerText += "holding canceled || ";
            }
        }
    },
    {},
    {});

    WinJS.Namespace.define("QandA", {
        InputProcessor: InputProcessor
    });
})();

Наконец, мы настраиваем диспетчер подсказок, который во время жеста нажатия и удерживания отображает серию подсказок в зависимости от текущего вопроса.

// Handle data for this sample.
(function () {
    "use strict";
    var ClueManager = WinJS.Class.define(
    // Constructor
    function ClueManager_ctor() {
        this._clueTimerId = null;
    },
    {
        displayClues: function () {
            var clue;
            var clueCount = 0;
            var clueCollection = _data.selectNodes("questions/question[" + this.tapCount + "]/clues/clue");

            this._clueTimerId = setInterval(function () {
                clueCount++;

                if (clueCount > clueCollection.length) {
                    _clues.innerText += "\nNo more clues.";
                    clearInterval(_clueTimerId);
                    return;
                }

                if (clueCount == 1)
                    clue = clueCollection.first();

                _clues.innerText += "\n" + clue.current.innerText;
                clue.moveNext();
            }, 2000);
        },
        destroy: function () {
            clearInterval(this._clueTimerId);
        },
        tapCount: {
            get: function () {
                return this._tapCount;
            },
            set: function (tapCount) {
                this._tapCount = tapCount;
            }
        }
    },
    {});

    WinJS.Namespace.define("QandA", {
        ClueManager: ClueManager
    });
})();

См. ссылки на более сложные примеры в разделе "Связанные темы" в нижней части страницы.

Полный пример

См. Полный код для статических жестов.

Краткая сводка и дальнейшие действия

Из данного краткого руководства вы узнали об обработке статических событий жестов в приложениях Магазина Windows на JavaScript.

Распознавание основных жестов вместе с событиями указателя полезно для управления простыми взаимодействиями, такими как касание, двойное касание, нажатие и удерживание и правое касание.

Более сложные примеры обработки жестов см. в разделе Ввод: пример пользовательских жестов.

Примечание  Этот пример не соответствует рекомендациям языка касаний Windows в отношении пользовательского взаимодействия. Некоторые статические жесты переопределены в учебных целях.

 

Сведения об обработке более сложных управляющих взаимодействий (скольжения, прокрутки, сжатия и растяжения), которые могут обеспечить полностью настраиваемое взаимодействие с пользователем, см. в разделе Краткое руководство: жесты управления.

Дополнительные сведения о языке касаний Windows см. в разделе Взаимодействие с помощью сенсорного ввода.

Связанные разделы

Разработчикам

Реакция на взаимодействие с пользователем

Разработка приложений Магазина Windows (JavaScript и HTML)

Краткое руководство: указатели

Краткое руководство: жесты и манипуляции DOM

Краткое руководство: жесты управления

Проектировщикам

Взаимодействие с помощью сенсорного ввода