Guida introduttiva: Gesti statici (HTML)

[ Questo articolo è rivolto agli sviluppatori per Windows 8.x e Windows Phone 8.x che realizzano app di Windows Runtime. Gli sviluppatori che usano Windows 10 possono vedere Documentazione aggiornata ]

Informazioni su come gestire gli eventi di base relativi ai gesti di Windows Runtime e personalizzare l'esperienza utente per i gesti statici descritti in Linguaggio per il tocco di Windows, ad esempio tocco, doppio tocco, pressione prolungata e tocco con due dita.

La maggior parte delle app elabora i gesti (tocco, panoramica, zoom e così via) e si limita a passare i dati del puntatore non elaborati per il rilevamento dei gesti. In questo esempio usiamo questi dati del puntatore non elaborati a supporto della gestione ed elaborazione dei gesti statici per estendere il modello di interazione dell'app sulla base degli eventi puntatore di base descritti in Guida introduttiva: Puntatori.

Aggiornamenti per Windows 8.1: In Windows 8.1 vengono introdotti diversi aggiornamenti e miglioramenti alle API di input tramite puntatore. Per altre informazioni, vedi Modifiche delle API per Windows 8.1.

Se non hai familiarità con lo sviluppo di app mediante JavaScript,: Leggi questi argomenti per imparare a conoscere le tecnologie qui descritte.

Creare la prima app con JavaScript

Roadmap per app in JavaScript

Scopri di più sugli eventi in Guida introduttiva: Aggiunta di controlli HTML e gestione di eventi

Funzionalità delle app dall'inizio alla fine:

Per conoscere meglio questa funzionalità, vedi gli argomenti della serie Funzionalità dell'app dall'inizio alla fine

Interazioni con l'utente, dall'inizio alla fine (HTML)

Personalizzazione delle interazioni con l'utente, dall'inizio alla fine (HTML)

Linee guida per l'esperienza utente:

Le raccolte di controlli della piattaforma (HTML e XAML) forniscono un'esperienza di interazione utente completa, che include interazioni standard, effetti fisici animati e feedback visivo. Se non hai l'esigenza di supportare interazioni personalizzate, usa questi controlli predefiniti.

Se i controlli della piattaforma non sono sufficienti, queste linee guida ti aiuteranno a offrire un'esperienza di interazione coinvolgente e Immersive coerente tra le diverse modalità di input. Queste linee guida sono incentrate principalmente sull'input tocco, ma sono rilevanti anche per input di tipo tocco, mouse, tastiera e stilo.

Esempi: Per esaminare questa funzionalità in azione, vedi gli esempi di app.

Esempio di personalizzazione delle interazioni con l'utente, dall'inizio alla fine

Input: Esempio di gestione degli eventi relativi al puntatore DOM

Input: Esempio di manipolazioni e gesti (JavaScript)

Input: Esempio di gesti di Windows 8

Obiettivo: Viene illustrato come rilevare, gestire ed elaborare gesti statici usando interazioni tramite tocco, mouse, penna/stilo ed eventi relativi ai gesti Windows Runtime.

Prerequisiti

Vedi Guida introduttiva: Puntatori e Guida introduttiva: Gesti e manipolazioni DOM.

In questa guida introduttiva si suppone che tu sia in grado di creare con Javascript un'app di base che usi il modello Libreria Windows per JavaScript.

Per completare questa esercitazione, devi:

Tempo per il completamento: 30 minuti.

Che cosa sono gli eventi relativi ai gesti?

Un gesto è un atto fisico o un movimento eseguito su o tramite il dispositivo di input (un dito o più dita su una superficie di tocco, un digitalizzatori di penna/stilo, il mouse e così via). Queste interazioni naturali vengono mappate a operazioni su elementi nel sistema e nell'app. Per altre informazioni, vedi Gesti, manipolazioni e interazioni.

Nella tabella seguente sono elencati i gesti statici descritti in questa guida introduttiva.

GestoDescrizione
Tocco/doppio toccoGesto tocco

Un singolo contatto che viene rilasciato, o terminato, immediatamente.

Toccare un elemento ne richiama la relativa azione principale.

Un doppio tocco consiste in due tocchi in successione rapida e può essere gestito in base alle esigenze dell'app.

  • Stato iniziale: un contatto rilevato entro il rettangolo di delimitazione di un oggetto.
  • Movimento: nessuno.
  • Stato finale: contatto rilasciato o terminato.
Pressione prolungata/tocco con due ditaGesto pressione prolungata

Un singolo contatto che non si muove finché non viene superata una soglia temporale.

Tenere premuto genera la visualizzazione di informazioni dettagliate o elementi visivi a scopo didattico, ad esempio una descrizione comando o un menu contestuale, senza dover eseguire un'azione specifica.

Il tocco con due dita è strettamente legato al gesto di pressione prolungata. L'evento di tocco con due dita viene generato quando si conclude la pressione prolungata.

  • Stato iniziale: un contatto rilevato entro il rettangolo di delimitazione di un oggetto.
  • Movimento: nessuno.
  • Stato finale: contatto rilasciato o terminato.

Per altre informazioni sui gesti e sulla correlazione con il linguaggio per il tocco di Windows, vedi Progettazione delle interazioni tramite tocco.

 

Importante  Se implementi un supporto personalizzato per le interazioni, tieni presente che gli utenti si aspettano un'esperienza intuitiva che include l'interazione diretta con gli elementi dell'interfaccia utente della tua app. Ti consigliamo di modellare le tue interazioni personalizzate sulle raccolte di controlli della piattaforma (HTML e XAML) per garantire la coerenza e l'intuitività. I controlli inclusi in queste librerie forniscono un'esperienza di interazione utente completa che include le interazioni standard, gli effetti fisici animati, il feedback visivo e l'accessibilità. Crea interazioni personalizzate solo in presenza di un requisito chiaro e ben definito e qualora le interazioni di base non siano in grado di supportare il tuo scenario.

 

Creare l'interfaccia utente

Questo esempio rappresenta una semplice app di domande e risposte. Un quadrato (inputBox) funge da oggetto di destinazione per il rilevamento e l'elaborazione dell'input del puntatore e dei gesti statici. Le domande, le indicazioni e le risposte vengono tutte visualizzate all'interno di questo oggetto.

L'app offre le seguenti funzionalità di interazione utente:

  • Doppio tocco: avvia e arresta le domande e il timer dell'app.
  • Tocco: passa da una domanda all'altra.
  • Pressione prolungata: visualizza un insieme di indizi per la domanda corrente, con un nuovo indizio visualizzato dopo qualche secondo durante il contatto. Questo comportamento di interazione è conforme alle Linee guida per il feedback visivo e alle raccomandazioni del linguaggio per il tocco, in base alle quali il gesto di pressione prolungata deve essere limitato alla visualizzazione dell'interfaccia utente informativa.
  • Tocco con due dita (o rilascio della pressione prolungata): visualizza un messaggio popup quando il contatto viene sollevato in cui viene chiesto all'utente se vuole la risposta. Anche questo caso è conforme alle raccomandazioni per il menu di scelta rapida illustrate nelle Linee guida per il feedback visivo e nel linguaggio per il tocco di Windows. Nota  Per concentrare l'attenzione sul codice di gestione dei gesti, la lettura dei dati delle domande e risposta da un file XML e alcune funzionalità dell'interfaccia utente e dell'app non sono completamente implementate.  

HTML per questo esempio.

<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 (Cascading Style Sheets) per questo esempio.

Nota  Gli eventi puntatore non vengono generati durante un'interazione di tipo panoramica o zoom. Puoi disabilitare la panoramica e lo zoom in un'area tramite le proprietà msTouchAction, overflow e -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;
}

Inizializzare l'app

Inizializza l'oggetto domande e risposte.

Qui dichiariamo le variabili globali e recuperiamo i riferimenti agli oggetti dell'interfaccia utente.

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();
}

Posizioniamo poi l'interfaccia utente per le domande e le risposte e impostiamo l'oggetto per le interazioni per elaborare i dati relativi alle domande e alle risposte dal file XML. I dettagli relativi ai dati XML per questo esempio sono disponibili nell'elenco completo alla fine di questo argomento.

// 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);
}

Configura il riconoscitore di gesti.

Impostiamo ora la gestione delle interazioni.

Nella maggior parte dei casi è consigliabile ottenere informazioni sul puntatore mediante l'argomento dell'evento del gestore eventi del puntatore nel framework del linguaggio che hai scelto.

Se l'argomento dell'evento non espone i dettagli del puntatore richiesti dall'app, puoi ottenere l'accesso a dati del puntatore estesi dall'argomento dell'evento tramite i metodi getCurrentPoint e getIntermediatePoints o le proprietà currentPoint e intermediatePoints. Ti consigliamo di usare i metodi getCurrentPoint e getIntermediatePoints perché puoi specificare il contesto dei dati del puntatore.

Suggerimento  Per questo esempio, solo un oggetto è associato a un riconoscitore di gesti. Se l'app contiene un numero elevato di oggetti manipolabili, ad esempio un puzzle, prova a creare dinamicamente un riconoscitore di gesti solo quando viene rilevato l'input del puntatore su un oggetto di destinazione. Il riconoscitore di gesti può essere eliminato al termine della manipolazione. Per un esempio, vedi Input: Esempio di gesti istanziabili. Per evitare il sovraccarico delle attività di creazione ed eliminazione, crea un piccolo pool di riconoscitori di gesti in fase di inizializzazione e assegnali dinamicamente in base alle necessità.

 

L'oggetto InputProcessor include il riconoscitore di gesti (gr) che rileva e gestisce tutti gli eventi del puntatore e dei gesti. L'interfaccia utente per le domande e le risposte è gestita dai gestori eventi del riconoscitore di gesti.

// 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
    });
})();

Configuriamo infine il gestore degli indizi che visualizza una serie di indizi basati sulla domanda corrente durante il gesto di pressione prolungata.

// 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
    });
})();

Per i link a esempi più complessi, vedi gli Argomenti correlati alla fine della pagina.

Esempio completo

Vedi il codice completo per i gesti statici.

Riepilogo e passaggi successivi

In questa Guida introduttiva hai imparato i concetti relativi alla gestione degli eventi relativi ai gesti statici nelle app di Windows Store in JavaScript.

Il riconoscimento dei gesti di base, unitamente agli eventi del puntatore, è utile per la gestione di semplici interazioni quali il tocco, il doppio tocco, la pressione prolungata e il tocco con due dita.

Per un esempio più complesso di gestione dei gesti, vedi Input: Esempio di gesti istanziabili.

Nota  Questo esempio non è conforme alle linee guida del linguaggio per il tocco di Windows per quanto concerne le interazioni personalizzate. Alcuni dei gesti statici sono stati ridefiniti per scopi formativi.

 

Per la gestione di interazioni di manipolazione più elaborate, ad esempio scorrimento, scorrimento rapido, avvicinamento e allontanamento delle dita e rotazione, per offrire un'esperienza di interazione utente completamente personalizzata, vedi Guida introduttiva: Gesti di manipolazione.

Per altre info sul linguaggio per il tocco di Windows, vedi Progettazione delle interazioni tramite tocco.

Argomenti correlati

Sviluppatori

Risposta alle interazioni degli utenti

Sviluppo di app di Windows Store (JavaScript e HTML)

Guida introduttiva: Puntatori

Guida introduttiva: Gesti e manipolazioni DOM

Guida introduttiva: Gesti di manipolazione

Designer

Progettazione delle interazioni tramite tocco