Swift TextLabelの縦書き表示とその編集

個人開発したアプリの宣伝
目的地が設定できる手帳のような使い心地のTODOアプリを公開しています。
Todo with Location

Todo with Location

  • Yoshiko Ichikawa
  • Productivity
  • Free


名刺レイアウトのような縦書きにTextLabelを対応させたい時。

色々試した結果、TTTAttributedLabelというライブラリを利用するのが楽そう。

github.com

podのインストール

Podfileに

pod 'TTTAttributedLabel'

の後、

pod install

すればよい。

実装例

f:id:letitride:20191209140952p:plain:h400

以下のような実装で縦書きラベルが表示される。

import UIKit
import TTTAttributedLabel

class ViewController: UIViewController {

    var myLabel:TTTAttributedLabel!

    override func viewDidLoad() {
        super.viewDidLoad()
        //viewサイズと配置位置 注意点については後述
        myLabel = TTTAttributedLabel(frame: CGRect(x: 0, y: 0, width: 500, height: 30))
        myLabel.center.x = self.view.frame.width - 15 - 30
        myLabel.center.y = 250 + 100
        view.addSubview(myLabel)

        myLabel.verticalAlignment = .top
        //view中心をZ軸に右に90度回転する
        let angle = CGFloat.pi/2
        myLabel.transform = CGAffineTransform(rotationAngle: CGFloat(angle))

        let text = "株式会社かぶ〜さん"
        //表示テキストの設定
        myLabel.setText(text) { (mutableAttributedString) -> NSMutableAttributedString? in
            mutableAttributedString!.addAttribute(NSAttributedString.Key.init(rawValue: kCTVerticalFormsAttributeName as String), value: true, range: NSMakeRange(0, mutableAttributedString!.length))
            return mutableAttributedString
        }
        
    }
}
viewサイズと配置位置の注意点

ViewはZ軸に90度右回転するので、heightが回転後の横の長さ、widthが縦の長さとして扱われる。

また、Z軸はView中心を軸とするので、xの指定として仮に親viewの右側から20ptマージンを取る場合、回転軸を

//親viewのサイズからtextLabelの横中心距離を引くと右済みとなる。
myLabel.center.x = self.view.frame.width - (myLabel.frame.height / 2) - 20

とすれば良い。

y座標は仮に親view上側から100ptのマージンを取る場合、

myLabel.center.y = (myLabel.frame.width / 2) + 100

となり、回転するviewの長さを考慮してpoint指定する必要がある。

縦書きLabelを編集する

残念ながらTTTAttributedLabel自体に編集する機能はないようなので、TTTAttributedLabelのタップジェスチャとhiddenなtextFieldを用意して編集を実現した。

import UIKit
import TTTAttributedLabel

class ViewController: UIViewController {

    var myLabel:TTTAttributedLabel!
    override func viewDidLoad() {
        super.viewDidLoad()
        
        myLabel = TTTAttributedLabel(frame: CGRect(x: 0, y: 200, width: 500, height: 30))
        myLabel.center.x = self.view.frame.width - 15 - 15
        myLabel.center.y = 250 + 100

        view.addSubview(myLabel)
        //編集可能とする設定        
        myLabelEditable()
    }
    
    let textField = UITextField()
    private func myLabelEditable(){
        //編集用のtextField ユーザに見せる必要はない
        textField.isHidden = true
        textField.addTarget(self, action: #selector(textFieldEditingChanged(_:)), for: .editingChanged)
        view.addSubview(textField)
        //TTTAttributedLabelタップ時にhiddenのtextFieldの編集を開始する
        myLabel.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(changeLabel)))
    }
    
    @objc func changeLabel(){
        textField.becomeFirstResponder()
    }
    
    //textFieldに変更があればTTTAttributedLabelを変更する
    @objc func textFieldEditingChanged(_ textField: UITextField){
        myLabel.setText(textField.text!) { (mutableAttributedString) -> NSMutableAttributedString? in
            mutableAttributedString!.addAttribute(NSAttributedString.Key.init(rawValue: kCTVerticalFormsAttributeName as String), value: true, range: NSMakeRange(0, mutableAttributedString!.length))
            return mutableAttributedString
        }
    }
}

サンプルコード

GitHub - letitride/MySwiftParts at VerticalLabel


SwiftUIの本が出るみたい。買って試してみようかな。