Comment rendre une partie de ses TextBlocks insécable

Comment rendre une partie de ses TextBlocks insécable

Avec Silverlight il était très simple de savoir à l’avance quel allait être le rendu de nos pages/contrôles sur l’ensemble des windows phone, en effet, il n’y avait qu’une seule largeur d’écran à gérer, quelque soit la taille physique ou la résolution de l’écran : 480 unités logiques.

Mais avec WinRT les choses ont changé, la largeur d’un écran dépend : de la résolution, de la taille physique et d’un paramètre de zoom propre à chaque device.

Il est donc parfois difficile d’imaginer le rendu de ses contrôles sur l’ensemble des devices et il faut parfois adapter ceux-ci pour être correctement rendu sur l’ensemble des écrans.

Prenons l’exemple suivant d’un message pour inviter un utilisateur à se connecter.

<TextBlock TextAlignment="Center" FontSize="18" FontWeight="Light" TextWrapping="Wrap">
<Run Text="{Binding LocalizedResources.AlreadyHaveAnAccount, Source={StaticResource LocalizedStrings}}"/>
<Run Text="{Binding LocalizedResources.OnBoardingSignIn, Source={StaticResource LocalizedStrings}}" Foreground="{StaticResource PrincBrush}"/>
</TextBlock>

Nous avons donc un TextBlock avec saut de ligne automatique et deux parties : un message descriptif et un message correspondant à l’action de se connecter.

Voici le rendu sur différent téléphones (Lumia 830, Lumia 920 et Lumia 520)

capture2

En soit, le rendu correspond bien à ce que l’on souhaitait, pas vraiment de bugs ici, mais mon côté perfectionniste n’aime pas vraiment le 3ème rendu, “Se connecter” correspond à une action et doit attirer l’oeil, or en étant coupée en deux, on diminue énormément l’attrait pour celle-ci.

Comment éviter le saut de ligne alors ?

Soyons précis, la vraie question est : “comment éviter le saut de ligne dans une partie spécifique de mon texte ?” Car en soit, je n’ai aucun problème avec le saut de ligne entre le “?” et le “Se”, il faut bien que le contenu s’adapte à la résolution d’écran. Si je désactive TextWrap de mon TextBlock, je risque d’avoir des problèmes sur les devices avec un petit écran.

Pour autant, je ne veux pas forcer le saut de ligne non plus, le premier rendu me va très bien s’il y a assez de place sur l’écran, le forcer voudrait dire ne pas utiliser intelligemment la place qui m’est proposée.

Donc pour résumer : je ne veux pas désactiver TextWrap mais pour autant, je ne veux pas que le saut de ligne soit entre “Se” et “Connecter”.

En tant que développeur je vais réfléchir à différente solution technique, en m’enregistrant sur SizeChanged, en mesurant manuellement la taille de chaque mot, en créant de visualState pour chaque résolution, etc… En gros, on va inventer des machines à gaz qui auront un résultat médiocre…. Et si je vous disais que la vraie solution ne se trouve pas dans le code, mais dans… la typographie.

En effet, dans le monde typographique, il n’existe pas qu’un seul espace (le fameux 0x20), il en existe plusieurs, notamment:

  • l’espace-mot : le plus connu
  • l’espace insécable : l’espace utilisé pour les numéros de téléphone par exemple, pour éviter qu’ils soient coupés ou entre un chiffre et une unité (%, px, etc..)
  • l’espace fin insécable : c’est un espace un peu plus fin, que l’on utilise devant les signes de ponctuations doubles (; ! : ? …) afin d’éviter qu’ils ne se trouvent pas sur une autre ligne
  • l’espace cadratin : c’est un espace plus large, correspondant à la force du corp de la police (vulgairement : sa taille), si vous utilisez une police de corp 22, cet espace aura une largeur de 22

La réponse à notre question initiale est donc ici : l’espace insécable. En remplaçant l’espace-mot entre “Se” et “Connecter” par un espace insécable, on indiquera au moteur de rendu de ne pas couper la phrase à cette endroit et de tenter de couper à un autre espace !

Pour information, la valeur de ce caractère est : 0xA0.

Deux écoles s’affrontent alors :

  • ajouter l’espace insécable à vos fichiers ressources, mais celui-ci sera présent partout où vous utiliserez cette ressource
  • l’ajouter manuellement au cas par cas

Si vous choisissez la seconde solution Voici donc un petit converter qui fera le travail pour vous.

 

public class ToNonBreakingSpaceConverter:IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
var txt = value as String;
if (txt == null)
return value;
return txt.Replace(' ', (char)0xA0);
}

public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}

Il suffira alors de l’utiliser sur le Run que l’on souhaite

<TextBlock TextAlignment="Center" FontSize="18" FontWeight="Light" TextWrapping="Wrap">
<Run Text="{Binding LocalizedResources.AlreadyHaveAnAccount, Source={StaticResource LocalizedStrings}}"/>
<Run Text="{Binding LocalizedResources.OnBoardingSignIn, Source={StaticResource LocalizedStrings},Converter={StaticResource ToNonBreakingSpaceConverter}}" Foreground="{StaticResource PrincBrush}"/>
</TextBlock>

Anecdote

Si vous ne connaissiez pas l’espace insécable, vous l’avez peut être très surement déjà utilisé par le passé, notamment dans le monde HTML. Beaucoup de développeurs web pensent qu’un espace est représenté en HTML par   or que signifie N.B.S.P ? non-breaking space.

  est en fait l’espace insécable, le vrai espace-mot étant :  

Donc la prochaine fois que vous voyez ceci dans une page web, n’hésitez pas à demander à votre collègue pourquoi il souhaite que son espace soit insécable 😉

Conclusion

Réfléchir comme un ingénieur n’est pas uniquement connaître l’ensemble des design-patttern par cœur, c’est surtout s’intéresser à tout, notamment à des sujets qui s’éloignent du développement, n’oublions pas que beaucoup des règles informatique viennent du monde typographique et mécanique (notamment l’origine du clavier AZERTY), un ordinateur n’est juste qu’une machine à écrire un peu plus évoluée.

cc14335b2f_Underwood-overview_04

 

Comments are closed.