Éditeurs de texte personnalisés

Les éditeurs de texte personnalisés sont des vues qui ne sont pas des composants EditText ni des widgets de texte WebView, mais qui acceptent la saisie de texte en implémentant le rappel onCreateInputConnection(), qui est appelé lorsqu'une vue est sélectionnée et que le système demande un InputConnection pour cette vue.

Un appel à onCheckIsTextEditor() à partir d'un éditeur de texte personnalisé doit renvoyer true.

Prendre en charge l'écriture manuscrite au stylet dans les éditeurs de texte personnalisés

Android 14 (niveau d'API 34) ou version ultérieure est compatible par défaut avec la saisie au stylet dans les composants de saisie de texte Android standards (voir Saisie au stylet dans les champs de texte). Toutefois, les champs de saisie de texte personnalisés (ou éditeurs) nécessitent des efforts supplémentaires de développement.

Pour créer un éditeur de texte personnalisé, procédez comme suit:

  1. Activer l'initiation de l'écriture manuscrite
  2. Déclarer la prise en charge de l'écriture manuscrite
  3. Prendre en charge les gestes d'écriture manuscrite (sélectionner, supprimer, insérer, etc.)
  4. Fournir l'emplacement du curseur et d'autres données de position à l'IME
  5. Afficher l'icône de pointage de l'écriture manuscrite au stylet

Activer l'initiation de l'écriture manuscrite

Si une vue ne comporte qu'un seul éditeur de texte, le système de vues peut automatiquement lancer l'écriture manuscrite au stylet pour cette vue. Sinon, la vue doit implémenter sa propre logique d'initiation de l'écriture manuscrite.

Lancement automatique de l'écriture manuscrite

Si une vue affiche un seul éditeur de texte et aucun autre contenu, elle peut activer le lancement automatique de l'écriture manuscrite du système de vues en appelant setAutoHandwritingEnabled(true).

Lorsque l'écriture manuscrite est activée, le mouvement du stylet qui commence n'importe où dans les limites de l'écriture manuscrite de la vue lance automatiquement ce mode. L'éditeur du mode de saisie (IME) reçoit les événements de mouvement du stylet et valide le texte reconnu.

Champ de saisie avec un rectangle autour indiquant les limites de détection des événements de mouvement du stylet.
Figure 1 : Écriture manuscrite dans les limites d'un champ EditText.

Lancement personnalisé de l'écriture manuscrite

Si un affichage contient plusieurs éditeurs de texte ou du contenu en plus d'un seul éditeur de texte, il doit implémenter sa propre logique d'initiation d'écriture manuscrite comme suit:

  1. Désactivez l'initiation automatique de l'écriture manuscrite du système de vues en appelant setAutoHandwritingEnabled(false).

  2. Effectuez le suivi de tous les éditeurs de texte visibles dans la vue.

  3. Surveillez les événements de mouvement reçus par la vue dans dispatchTouchEvent().

    • Lorsque le stylet se déplace dans les limites de l'écriture manuscrite d'un éditeur de texte, sélectionnez l'éditeur de texte (s'il n'est pas déjà sélectionné).

    • Si l'éditeur n'était pas déjà sélectionné, redémarrez l'IME de l'éditeur avec le nouveau contenu en appelant InputMethodManager#restartInput().

    • Démarrez la session d'écriture manuscrite du stylet en appelant InputMethodManager#startStylusHandwriting().

Si un éditeur de texte se trouve dans une vue déroulante, le mouvement du stylet dans les limites de l'écriture manuscrite de l'éditeur doit être considéré comme de l'écriture manuscrite, et non comme un défilement. Utilisez ViewParent#requestDisallowInterceptTouchEvent() pour empêcher une vue ascendante déroulante d'intercepter les événements tactiles d'un éditeur de texte.

Détails de l'API

  • MotionEvent#getToolType() : indique si le MotionEvent provient d'un stylet, auquel cas la valeur renvoyée est TOOL_TYPE_STYLUS ou TOOL_TYPE_ERASER.

  • InputMethodManager#isStylusHandwritingAvailable() : indique si l'IME est compatible avec l'écriture manuscrite au stylet. Appelez cette méthode avant chaque appel à InputMethodManager#startStylusHandwriting(), car la disponibilité de l'écriture manuscrite peut avoir changé.

  • InputMethodManager#startStylusHandwriting() : active le mode d'écriture manuscrite de l'IME. Un événement de mouvement ACTION_CANCEL est envoyé à l'application pour annuler le geste en cours. Les événements de mouvement du stylet ne sont plus envoyés à l'application.

    Les événements de mouvement du stylet associés au geste actuel qui ont déjà été envoyés à l'application sont transmis à l'IME. L'IME est nécessaire pour afficher une fenêtre d'encre de stylet à travers laquelle il reçoit tous les objets MotionEvent suivants. L'IME valide le texte d'écriture manuscrite reconnu à l'aide des API InputConnection.

    Si l'IME ne peut pas passer en mode écriture manuscrite, cet appel de méthode est no-op.

Déclarer la prise en charge de l'écriture manuscrite

Lorsque vous remplissez l'argument EditorInfo de View#onCreateInputConnection(EditorInfo), appelez setStylusHandwritingEnabled() pour informer l'IME que l'éditeur de texte prend en charge l'écriture manuscrite. Déclarez les gestes compatibles avec setSupportedHandwritingGestures() et setSupportedHandwritingGesturePreviews().

Prendre en charge les gestes d'écriture manuscrite

Les IME peuvent accepter divers gestes d'écriture manuscrite, par exemple entourer le texte pour le sélectionner ou en griffonnant sur du texte pour le supprimer.

Figure 2 : Entourez pour sélectionner du texte.
Figure 3 : Dessinez pour supprimer du texte.

Les éditeurs personnalisés implémentent InputConnection#performHandwritingGesture() et InputConnection#previewHandwritingGesture() pour prendre en charge différents types de HandwritingGesture, tels que SelectGesture, DeleteGesture et InsertGesture.

Déclarez les gestes d'écriture manuscrite acceptés lors de la saisie de l'argument EditorInfo de View#onCreateInputConnection(EditorInfo) (consultez la section Déclarer la prise en charge de l'écriture manuscrite).

Détails de l'API

  • InputConnection#performHandwritingGesture(HandwritingGesture, Executor, IntConsumer) : implémente des gestes. L'argument HandwritingGesture contient des informations de localisation que vous pouvez utiliser pour déterminer où effectuer le geste dans le texte. Par exemple, SelectGesture fournit un objet RectF qui spécifie la plage de texte sélectionnée, et InsertGesture fournit un objet PointF qui spécifie le décalage du texte auquel insérer le texte.

    Utilisez les paramètres Executor et IntConsumer pour renvoyer le résultat de l'opération. Lorsque les arguments de l'exécuteur et des clients sont fournis, utilisez l'exécuteur pour appeler IntConsumer#accept(), par exemple:

    
    executor.execute { consumer.accept(HANDWRITING_GESTURE_RESULT_SUCCESS) }
    
    
  • HandwritingGesture#getFallbackText() : fournit le texte de remplacement validé par l'IME à la position du curseur si aucun texte applicable ne se trouve sous la zone d'un geste d'écriture manuscrite.

    Parfois, l'IME n'est pas en mesure de déterminer si un geste au stylet est destiné à effectuer une opération gestuelle ou à écrire à la main. Un éditeur de texte personnalisé est chargé de déterminer l'intention de l'utilisateur et d'effectuer l'action appropriée (en fonction du contexte) à l'emplacement du geste.

    Par exemple, si l'IME ne peut pas déterminer si l'utilisateur voulait dessiner un caret vers le bas ⋁ pour effectuer un geste d'insertion d'espace ou pour écrire la lettre "v" à la main, il peut envoyer un InsertGesture avec le texte de remplacement "v".

    L'éditeur doit d'abord essayer d'effectuer le geste d'insertion d'espace. Si le geste ne peut pas être effectué (par exemple, s'il n'y a pas de texte à l'emplacement spécifié), l'éditeur doit insérer la lettre "v" à la position du curseur.

  • InputConnection#previewHandwritingGesture(PreviewableHandwritingGesture, CancellationSignal) : prévisualise un geste en cours. Par exemple, lorsque l'utilisateur commence à dessiner un cercle autour du texte, un aperçu en direct de la sélection obtenue peut être affiché et mis à jour en continu à mesure que l'utilisateur continue de dessiner. Seuls certains types de gestes peuvent être prévisualisés (voir PreviewableHandwritingGesture).

    Le paramètre CancellationSignal peut être utilisé par l'IME pour annuler l'aperçu. Si d'autres événements perturbent l'aperçu (par exemple, si du texte est modifié de façon programmatique ou que de nouvelles commandes InputConnection se produisent), l'éditeur personnalisé peut annuler l'aperçu.

    Les gestes d'aperçu ne sont destinés qu'à l'affichage et ne doivent pas modifier l'état de l'éditeur. Par exemple, un aperçu SelectGesture masque la plage de sélection actuelle de l'éditeur et met en surbrillance la plage d'aperçu des gestes. Toutefois, une fois l'aperçu annulé, l'éditeur doit restaurer sa plage de sélection précédente.

Fournir l'emplacement du curseur et d'autres données de position

En mode écriture manuscrite, l'IME peut demander l'emplacement du curseur et d'autres données de position à l'aide de InputConnection#requestCursorUpdates(). L'éditeur personnalisé répond par un appel à InputMethodManager#updateCursorAnchorInfo(View, CursorAnchorInfo). Les données de CursorAnchorInfo concernant l'écriture manuscrite au stylet sont fournies via les méthodes CursorAnchorInfo.Builder suivantes:

  • setInsertionMarkerLocation() : définit la position du curseur. L'IME utilise cette valeur pour animer l'encre d'écriture manuscrite à l'emplacement du curseur.
  • setEditorBoundsInfo() : définit les limites de l'éditeur et de l'écriture manuscrite. L'IME utilise ces données pour positionner la barre d'outils d'écriture manuscrite de l'IME à l'écran.
  • addVisibleLineBounds() : définit les limites de toutes les lignes de texte visibles (ou partiellement visibles) dans l'éditeur. L'IME utilise les limites des lignes pour améliorer la précision de la reconnaissance des gestes d'écriture manuscrite.
  • setTextAppearanceInfo() : définit l'apparence du texte à l'aide des informations issues du champ de saisie de texte. L'IME utilise ces informations pour styliser l'encre d'écriture manuscrite.

Afficher l'icône de pointage de l'écriture manuscrite au stylet

Affichez l'icône de pointage de l'écriture manuscrite au stylet lorsque le stylet pointe sur les limites d'écriture manuscrite de votre éditeur de texte personnalisé et que l'IME sélectionné est compatible avec l'écriture manuscrite au stylet (InputMethodManager#isStylusHandwritingAvailable()).

Ignorez View#onResolvePointerIcon() pour obtenir une icône de pointage pour l'écriture manuscrite au stylet. Dans le forçage, appelez PointerIcon.getSystemIcon(context, PointerIcon.TYPE_HANDWRITING) pour accéder à l'icône de pointage de l'écriture manuscrite du stylet du système.

Ressources supplémentaires