web-dev-qa-db-fra.com

Comment créer un texte vertical UILabel et UITextView pour iOS dans Swift?

Si vous êtes venu à cette question sur la base du titre mais que vous n'êtes pas intéressé par le mongol, vous recherchez peut-être plutôt cette Q&R:


J'ai appris Swift afin de développer des applications iOS pour mongol traditionnel . Le problème est que le mongol traditionnel est écrit verticalement de haut en bas et de gauche à droite . Ma question est de savoir comment afficher le texte verticalement tout en conservant le retour à la ligne?

Si vous restez avec moi pendant une minute, je vais essayer d'expliquer le problème plus clairement. Vous trouverez ci-dessous une image du type d'affichage de texte que j'aimerais réaliser. Au cas où le script étranger vous déconcerte, j'ai inclus un texte anglais qui suit le même modèle. En fait, si l'application a du texte anglais à afficher, voici à quoi cela devrait ressembler.

enter image description here

Pour un simple UILabel à une ligne, une rotation de 90 degrés dans le sens horaire fonctionnerait. Cependant, pour un UITextView multi-lignes, je dois gérer le retour à la ligne. Si je fais juste une rotation de 90 degrés, la première chose écrite finira par être sur la dernière ligne.

Jusqu'à présent, j'ai élaboré un plan qui, je pense, peut résoudre ce problème:

  1. Créez une police personnalisée dans laquelle toutes les lettres sont reflétées verticalement.
  2. Faites pivoter la vue texte de 90 degrés dans le sens des aiguilles d'une montre.
  3. Miroir la vue texte horizontalement.

enter image description here

Cela devrait prendre soin de l'habillage du texte.

Je peux faire la police en miroir. Cependant, je ne sais pas comment faire le codage Swift pour la rotation et la mise en miroir de UITextView. J'ai trouvé les liens suivants qui semblent donner des indications sur des parties de la solution, mais ils sont tous dans l'objectif C et non dans Swift.

Il y a des applications mongoles traditionnelles dans l'App Store (comme this et this ) mais je n'ai encore trouvé personne qui partage son code source, donc je ne sais pas ce qu'ils font en coulisses pour afficher le texte. Je prévois de rendre mon code open source afin qu'il ne soit pas si difficile pour les autres à l'avenir de développer des applications pour les plusieurs millions de personnes qui lisent le mongol traditionnel. Toute aide que vous pourriez apporter à cette entreprise serait très appréciée, non seulement par moi, mais aussi par le peuple mongol. Même si vous ne vous connaissez pas, voter pour cette question pour la rendre plus visible serait utile.

Mettre à jour

La réponse de @ sangonz est toujours une excellente réponse, mais je l'ai temporairement marquée comme réponse acceptée parce que je n'arrivais pas à tout faire fonctionner. Plus précisément:

  • Activation du défilement (soit en incorporant la vue personnalisée dans une vue de défilement, soit en sous-classe UIScrollView ). Dans le projet github, @sangonz a dit que cela devrait être facile, mais ce n'était pas pour moi.
  • Obtenir un relais (plutôt qu'un étirement) des lignes Word lors d'un changement d'orientation. Je pense que cela ne devrait pas être trop difficile à résoudre avec un peu plus de recherche.
  • Pourquoi les lignes de texte ne vont-elles pas jusqu'au bord de la vue? Il y a un grand écart en bas.
  • Comment dissocier le NSTextStorage de la vue verticale personnalisée de l'autre UITextView. (voir cette question )

Jusqu'à ce point j'ai utilisé la méthode d'origine J'ai proposé ci-dessus, mais ce que je veux vraiment, c'est obtenir quelque chose comme ce que @sangonz a proposé de travailler.

J'envisage également maintenant des méthodes alternatives comme

46
Suragch

Edit: C'est ainsi que je l'ai finalement fait.

Voici une implémentation très basique dans mon GitHub: Vertical-Text-iOS .

Rien d'extraordinaire, mais ça marche. Enfin, j'ai dû mélanger TextKit et le traitement d'image. Jetez un œil au code. Ça implique:

  1. Sous-classer NSTextContainer pour obtenir les bonnes dimensions de texte.
  2. Création d'un UIView personnalisé pour rendre le texte en appliquant des transformations affines à chaque ligne et rendu à l'aide de NSLayoutManager pour conserver toutes les fonctionnalités de TextKit.

Manière TextKit

La bonne façon de conserver tous les avantages du texte natif (par exemple, la mise en évidence, la sélection ...) consiste à utiliser les API TextKit standard. La méthode que vous proposez briserait tout cela ou entraînerait peut-être un comportement étrange.

Cependant, il semble que TextKit dans iOS ne prenne pas encore en charge l'orientation verticale, mais il est prêt pour cela. En guise de remarque, dans OS X, il est quelque peu pris en charge et vous pouvez appeler textView.setLayoutOrientation(.Vertical), mais il a toujours quelques limitations.

Le protocole NSTextLayoutOrientationProvider définit une interface fournissant l'orientation par défaut du texte disposé dans un objet conforme, en l'absence d'un attribut explicite NSVerticalGlyphFormAttributeName. La seule classe UIKit qui implémente cette interface est NSTextContainer, dont l'implémentation par défaut renvoie NSTextLayoutOrientationHorizontal. Une sous-classe NSTextContainer qui gère le texte vertical pourrait définir cette propriété sur NSTextLayoutOrientationVertical pour prendre en charge la logique d'orientation de mise en page personnalisée.

Source: IKit> NSTextLayoutOrientationProvider Référence du protocole pour iOS

En conclusion , vous devriez commencer à sous-classer NSTextContainer, et vous devrez traiter avec NSLayoutManager et NSTextContainer beaucoup.


Manière de traitement d'image personnalisée

Si, en revanche, vous décidez de suivre votre rendu de texte personnalisé, je suggère l'approche suivante.

  1. Rendez le texte normal à un calque caché avec une police normale. Donnez-lui la taille correcte à sa boîte englobante.
  2. Obtenez les propriétés du texte , principalement la hauteur du texte et l'espacement des lignes.
  3. Traitez l'image en dessinant chaque ligne dans l'ordre inverse de bas en haut comme vous pouvez le voir dans l'image ci-dessous. Vous devriez donc obtenir un nouveau CGImage.
  4. Faites pivoter l'image en créant un UIImage et en définissant la valeur UIImageOrientation correcte.
  5. Insérez cette image dans un UIScrollView qui ne permet que le défilement horizontal.

Attention cette méthode rend le texte entier, donc ne l'utilisez pas pour des textes très longs. Si vous devez le faire, vous devrez envisager une approche en mosaïque. Regardez WWDC 2013> 217 - Exploration des vues de défilement sur iOS 7 .

this image

Bonne chance!

Mise à jour: (image du projet github)

enter image description here

21
sangonz

Si vous souhaitez faire pivoter le texte, je suggère d'utiliser une disposition de droite à gauche afin de pouvoir ignorer l'étape de mise en miroir (et simplement faire pivoter dans l'autre sens).

Vous devriez pouvoir simplement définir la propriété transform de label/textview:

view.transform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(CGFloat(-M_PI_2)), view.bounds.width, view.bounds.height)

Vous devez traduire après avoir pivoté car la vue tourne autour de son origine (en haut à gauche).

La bonne nouvelle est que les gestes et les tapotements sont transformés en même temps que les pixels, donc les contrôles continuent de fonctionner comme vous vous y attendez.

3
Frank Schmitt