概要
TwitterでフォロワーさんがUIStackViewで挑戦してたのを見かけた。
あえて同じくStackViewで挑戦して¥が下はみ出る… https://t.co/0rPgMqLocr
— ありぜ (@a_aryzae) 2018年9月7日
スレッドを遡ってみると、NSAttributedStringで実装できるんじゃないかという話があり、興味が湧いたので挑戦してみた。
作ったもの
文字のサイズ感は目見当。
説明
ソースコードを部分的に切り出して処理内容を説明する。
let fontSize: CGFloat = 80 let font = UIFont.systemFont(ofSize: fontSize) let attributeText = NSMutableAttributedString(string: "各種¥(税込)280", attributes: [.font: font, .foregroundColor: UIColor.red])
はじめに attributeText
に基本的な装飾と文字列を格納しておいて、装飾を変更したい部分をNSRangeで指定して、加工していく方法をとることにした。
// 各種 attributeText.addAttributes([.font: UIFont.systemFont(ofSize: fontSize * 0.4), .baselineOffset: 2], range: NSRange(location: 0, length: 2))
各種 の部分。
文字サイズは基本サイズの40%の大きさを指定。
¥
や数字よりベースラインが少し下にずれて見えるので、.baselineOffset: 2
を指定して少し上にずらした。
ベースラインについては ラテン文字と欧文組版 をP14の図を参照。
雑に説明すると、.baselineOffset
に正の数を与えると上に移動し、負の数を与えると下に移動する。
// ¥ attributeText.addAttributes([.font: UIFont.systemFont(ofSize: fontSize * 0.6), .kern: -50], range: NSRange(location: 2, length: 1))
¥ の部分。
文字サイズは基本サイズの60%の大きさを指定。
.kern: -50
を指定して、次の文字の ( との字間を詰めた。
雑に説明すると、.kern
(カーニング)は当該文字と次の文字の文字間のアキを詰める設定。
なお、パーレンにはカーニングが適用されないっぽかったので、¥を前にもってきてカーニング設定をしている。
// (税込) attributeText.addAttributes([.font: UIFont.systemFont(ofSize: fontSize * 0.2), .baselineOffset: (fontSize * 0.8) - (fontSize * 0.2) - 4], range: NSRange(location: 3, length: 4))
(税込) の部分。
文字サイズは基本サイズの20%の大きさを指定。
ベースラインは相対値で計算したものの、それだけではうまく揃わなかったので、微調整している。
// ()のベースライン調整 attributeText.addAttributes([.baselineOffset: (fontSize * 0.8) - (fontSize * 0.2) - 3], range: NSRange(location: 3, length: 1)) attributeText.addAttributes([.baselineOffset: (fontSize * 0.8) - (fontSize * 0.2) - 3], range: NSRange(location: 6, length: 1))
( と ) の部分。
ベースラインが揃わなかったので、この部分だけさらに微調整した。
文字列ごとにNSAttributedStringKeyを指定していき、最後に結合する方法でも良かったんだけど、DTP的な手法のほうが手慣れているため、この方法にしてしまったがゆえに、すごくIllustratorやInDesignを触っている気分になった。
まとめ
奥さんに「できたで!」って誇らしげに見せたら「あ、はい」という感想をいただいた。iOSでもチラシレイアウトできるんやで!すごくない?!すごいやろ?! https://t.co/7VlaDJlVyc
— こうちゃん黒猫まみれ (@macneko_ayu) 2018年9月7日