Entrada de texto com a exibição de texto manuscrito

Observação

O modo de exibição manuscrito não é compatível com controles de texto no SDK do Aplicativo Windows. Este artigo é válido somente para aplicativos UWP.

Caixa de texto se expande quando tocado com a caneta

Personalize a exibição de manuscrito (para entrada tinta em texto) integrada aos controles de texto UWP, como TextBox, RichEditBox e AutoSuggestBox.

Visão geral

Os controles de entrada de texto UWP são compatíveis com entrada por caneta usando o Windows Ink, transformando-se em uma superfície manuscrita quando um usuário toca em uma caixa de entrada de texto usando uma caneta.

O texto é reconhecido à medida que o usuário escreve em qualquer lugar na superfície de escrita, e uma janela de candidatos mostra os resultados do reconhecimento. O usuário pode tocar em um resultado para escolhê-lo ou continuar escrevendo para aceitar o candidato proposto. Os resultados do reconhecimento literal (letra pela letra) estão incluídos na janela de candidatos, para que o reconhecimento não fique restrito a palavras em um dicionário. Conforme o usuário escreve, a entrada de texto aceita é convertida em uma fonte de script que mantém a sensação de escrita.

Observação

A exibição de texto manuscrito é habilitada por padrão, mas você pode desabilitá-la por controle e reverter para o painel de entrada de texto.

Caixa de texto com tinta e sugestões

Um usuário pode editar o texto usando gestos e ações padrão:

  • tachado ou rabisco – desenhar para excluir uma palavra ou parte de uma palavra
  • unir – desenhar um arco entre as palavras para excluir o espaço entre elas
  • inserir – desenhar um símbolo de acento circunflexo para inserir um espaço
  • substituir – escrever sobre o texto existente para substituí-lo

Caixa de texto com a correção de tinta

Desabilitar o modo de exibição de manuscrito

O modo de exibição interno de manuscrito é habilitado por padrão.

Talvez você queira desabilitar o modo de exibição de manuscrito se você já fornece funcionalidade equivalente de tinta em texto em seu aplicativo ou sua experiência de entrada de texto se baseia em algum tipo de formatação ou caractere especial (como uma guia) não disponível por meio de manuscrito.

Neste exemplo, podemos desabilitar o modo de exibição de manuscrito definindo a propriedade IsHandwritingViewEnabled do controle TextBox como false. Todos os controles de texto que dão suporte à exibição de texto manuscrito oferecem suporte a uma propriedade semelhante. ​

<TextBox Name="SampleTextBox"​
    Height="50" Width="500" ​
    FontSize="36" FontFamily="Segoe UI" ​
    PlaceholderText="Try taping with your pen" ​
    IsHandwritingViewEnabled="False">​
</TextBox>​

Especificar o alinhamento do modo de exibição de manuscrito

O modo de exibição de manuscrito está localizado acima do controle de texto subjacente e dimensionado para acomodar as preferências de manuscrito do usuário (confira Configurações -> Bluetooth e dispositivos -> Caneta e Windows Ink -> Manuscrito -> Tamanho da fonte). O modo de exibição também é alinhado automaticamente em relação ao controle de texto e sua localização dentro do aplicativo.

A interface do usuário do aplicativo não reflui para acomodar o controle maior, o que pode obstruir uma interface do usuário importante.

O snippet a seguir mostra como usar a propriedade PlacementAlignment de um TextBox HandwritingView para especificar qual âncora no controle de texto subjacente é usada para alinhar o modo de exibição de manuscrito. ​

<TextBox Name="SampleTextBox"​
    Height="50" Width="500" ​
    FontSize="36" FontFamily="Segoe UI" ​
    PlaceholderText="Try taping with your pen">​
        <TextBox.HandwritingView>​
            <HandwritingView PlacementAlignment="TopLeft"/>​
        </TextBox.HandwritingView>​
</TextBox>​

Desabilitar candidatos de preenchimento automático

O pop-up de sugestão de texto está habilitado por padrão. Ele fornece uma lista de candidatos de reconhecimento de tinta principais da qual o usuário pode selecionar caso o candidato principal esteja incorreto.

Se o aplicativo já fornece a funcionalidade de reconhecimento robusta e personalizada, você pode usar a propriedade AreCandidatesEnabled para desabilitar as sugestões internas, conforme mostrado no exemplo a seguir.

<TextBox Name="SampleTextBox"​
    Height="50" Width="500" ​
    FontSize="36" FontFamily="Segoe UI" ​
    PlaceholderText="Try taping with your pen">​
        <TextBox.HandwritingView>​
            <HandwritingView AreCandidatesEnabled="False"/>​
        </TextBox.HandwritingView>​
</TextBox>

Usar as preferências de fonte de manuscrito

Um usuário pode escolher de uma coleção predefinida de fontes com base em texto manuscrito para usar ao renderizar texto com base no reconhecimento de tinta (confira Configurações -> Bluetooth e dispositivos -> Caneta e Windows Ink -> Manuscrito -> Fonte).

Seu aplicativo pode acessar essa configuração e usar a fonte selecionada para o texto reconhecido no controle de texto.

Neste exemplo, podemos escutar o evento TextChanged de um TextBox e aplicar a fonte de selecionada do usuário se a alteração de texto se originou do HandwritingView (ou uma fonte padrão, caso contrário). ​

private void SampleTextBox_TextChanged(object sender, TextChangedEventArgs e)​
{​
    ((TextBox)sender).FontFamily = 
        ((TextBox)sender).HandwritingView.IsOpen ?
            new FontFamily(PenAndInkSettings.GetDefault().FontFamilyName) : 
            new FontFamily("Segoe UI");​
}​

Acessar HandwritingView em controles compostos

Controles compostos que usam o controle TextBox ou RichEditBox, como AutoSuggestBox, também são compatíveis com HandwritingView.

Para acessar o HandwritingView em um controle composto, use a API VisualTreeHelper.

O snippet XAML a seguir exibe um controle AutoSuggestBox.

<AutoSuggestBox Name="SampleAutoSuggestBox"​ 
    Height="50" Width="500"​ 
    PlaceholderText="Auto Suggest Example"​ 
    FontSize="16" FontFamily="Segoe UI" ​ 
    Loaded="SampleAutoSuggestBox_Loaded">​
</AutoSuggestBox>​

No code-behind correspondente, mostramos como desabilitar o HandwritingView no AutoSuggestBox.

  1. Em primeiro lugar, manipulamos o evento Loaded do elemento e chamamos uma função FindInnerTextBox para iniciar a travessia da árvore visual.

    private void SampleAutoSuggestBox_Loaded(object sender, RoutedEventArgs e)​
    {​
        if (FindInnerTextBox((AutoSuggestBox)sender))​
            autoSuggestInnerTextBox.IsHandwritingViewEnabled = false;​
    }​
    
  2. Na função FindInnerTextBox, iteramos pela árvore visual (começando em uma AutoSuggestBox) chamando uma função FindVisualChildByName.

    private bool FindInnerTextBox(AutoSuggestBox autoSuggestBox)​
    {​
        if (autoSuggestInnerTextBox == null)​
        {​
            // Cache textbox to avoid multiple tree traversals. ​
            autoSuggestInnerTextBox = 
                (TextBox)FindVisualChildByName<TextBox>(autoSuggestBox);​
        }​
        return (autoSuggestInnerTextBox != null);​
    }​
    ​```
    
    
  3. Por fim, essa função FindVisualChildByName itera na árvore visual até que TextBox seja recuperado.

    private FrameworkElement FindVisualChildByName<T>(DependencyObject obj)​
    {​
        FrameworkElement element = null;​
        int childrenCount = 
            VisualTreeHelper.GetChildrenCount(obj);​
        for (int i = 0; (i < childrenCount) && (element == null); i++)​
        {​
            FrameworkElement child = 
                (FrameworkElement)VisualTreeHelper.GetChild(obj, i);​
            if ((child.GetType()).Equals(typeof(T)) || (child.GetType().GetTypeInfo().IsSubclassOf(typeof(T))))​
            {​
                element = child;​
            }​
            else​
            {​
                element = FindVisualChildByName<T>(child);​
            }​
        }​
        return (element);​
    }​
    ​```
    
    

Reposicionar o HandwritingView

Em alguns casos, talvez seja necessário garantir que o HandwritingView abranja elementos de interface do usuário que, de outra forma, não faria.

Aqui, podemos criar um TextBox que dá suporte a ditado (implementado colocando um TextBox e um botão de ditado em um StackPanel).

Captura de tela de uma caixa de texto que dá suporte a ditado

Como o StackPanel agora é maior do que o TextBox, o HandwritingView talvez não obstrua todos os controles compostos.

Captura de tela de um controle HandwritingView que parcialmente oclui um TextBox e outro que é reposicionado para ocluir totalmente o Textbox

Para resolver isso, defina a propriedade PlacementTarget do HandwritingView como o elemento de interface do usuário para o qual deve ser alinhada.

<StackPanel Name="DictationBox" 
    Orientation="Horizontal" ​
    VerticalAlignment="Top" 
    HorizontalAlignment="Left" ​
    BorderThickness="1" BorderBrush="DarkGray" ​
    Height="55" Width="500" Margin="50">​
    <TextBox Name="DictationTextBox" 
        Width="450" BorderThickness="0" ​
        FontSize="24" VerticalAlignment="Center">​
        <TextBox.HandwritingView>​
            <HandwritingView PlacementTarget="{Binding ElementName=DictationBox}"/>​
        </TextBox.HandwritingView>​
    </TextBox>​
    <Button Name="DictationButton" 
        Height="48" Width="48" 
        FontSize="24" ​
        FontFamily="Segoe MDL2 Assets" 
        Content="&#xE720;" ​
        Background="White" Foreground="DarkGray" ​    Tapped="DictationButton_Tapped" />​
</StackPanel>​

Redimensionar o HandwritingView

Você também pode definir o tamanho do HandwritingView, que pode ser útil quando você precisa garantir que o modo de exibição não obstrua uma interface do usuário importante.

Assim como no exemplo anterior, podemos criar um TextBox que dá suporte a ditado (implementado colocando um TextBox e um botão de ditado em um StackPanel).

Captura de tela de um TextBox que dá suporte a ditado

Nesse caso, redimensionamos o HandwritingView para verificar se o botão de ditado está visível.

Captura de tela de um controle HandwritingView que oclui o botão de ditado e outro que é redimensionado para verificar se o botão de ditado está visível

Para fazer isso, podemos associar a propriedade MaxWidth do HandwritingView com a largura do elemento da interface do usuário que ele deve obstruir.

<StackPanel Name="DictationBox" 
    Orientation="Horizontal" ​
    VerticalAlignment="Top" 
    HorizontalAlignment="Left" ​
    BorderThickness="1" 
    BorderBrush="DarkGray" ​
    Height="55" Width="500" 
    Margin="50">​
    <TextBox Name="DictationTextBox" 
        Width="450" 
        BorderThickness="0" ​
        FontSize="24" 
        VerticalAlignment="Center">​
        <TextBox.HandwritingView>​
            <HandwritingView 
                PlacementTarget="{Binding ElementName=DictationBox}"​
                MaxWidth="{Binding ElementName=DictationTextBox, Path=Width"/>​
        </TextBox.HandwritingView>​
    </TextBox>​
    <Button Name="DictationButton" 
        Height="48" Width="48" 
        FontSize="24" ​
        FontFamily="Segoe MDL2 Assets" 
        Content="&#xE720;" ​
        Background="White" Foreground="DarkGray" ​
        Tapped="DictationButton_Tapped" />​
</StackPanel>​

Reposicionar a interface do usuário personalizada

Se você tiver interface do usuário personalizada que aparece em resposta à entrada de texto, como um pop-up informativo, talvez seja necessário reposicionar a interface do usuário para que ela não obstrua o modo de exibição de manuscrito.

TextBox com a interface do usuário personalizada

O exemplo a seguir mostra como escutar eventos Opened, Closed e SizeChanged do HandwritingView para definir o posição de um pop-up.

private void Search_HandwritingViewOpened(
    HandwritingView sender, HandwritingPanelOpenedEventArgs args)​
{​
    UpdatePopupPositionForHandwritingView();​
}​
​
private void Search_HandwritingViewClosed(
    HandwritingView sender, HandwritingPanelClosedEventArgs args)​
{​
    UpdatePopupPositionForHandwritingView();​
}​
​
private void Search_HandwritingViewSizeChanged(
    object sender, SizeChangedEventArgs e)​
{​
    UpdatePopupPositionForHandwritingView();​
}​
​
private void UpdatePopupPositionForHandwritingView()​
{​
if (CustomSuggestionUI.IsOpen)​
    CustomSuggestionUI.VerticalOffset = GetPopupVerticalOffset();​
}​
​
private double GetPopupVerticalOffset()​
{​
    if (SearchTextBox.HandwritingView.IsOpen)​
        return (SearchTextBox.Margin.Top + SearchTextBox.HandwritingView.ActualHeight);​
    else​
        return (SearchTextBox.Margin.Top + SearchTextBox.ActualHeight);​    ​
}​

Remodelar o controle HandwritingView

Assim como com todos os controles de estrutura XAML, você pode personalizar a estrutura e o comportamento visuais de um HandwritingView para suas necessidades específicas.

Para ver um exemplo completo de criação de um modelo personalizado, confira a instrução Criar controles personalizados de transporte ou Exemplo de controle de edição personalizada. ​ ​ ​ ​ ​ ​ ​ ​