ラベル 文字 の投稿を表示しています。 すべての投稿を表示
ラベル 文字 の投稿を表示しています。 すべての投稿を表示

2018年3月7日水曜日

文字列の長さを調べる

結論

先に言うと、文字列.count で得られる。

詳細

文字列の長さ(文字数)を調べるのに、Swiftでは多くのプログラミング言語にあるlengthなどのプロパティがない。
これはUnicodeの導入で1文字あたりのバイト数のバリエーションが増えたため、一つのlengthで対応できないためのようだ。

そこで以下のようなそれぞれに対応したcountプロパティで得ることになる。
unicodeScalarsはUTF32用だ。

"猫".utf8.count ->3
"🐱".utf8.count ->4

"猫".utf16.count ->1
"🐱".utf16.count -> 2

"猫".unicodeScalars.count ->1
"🐱".unicodeScalars.count ->1

"猫".characters.count ->1

"🐱".characters.count ->1

最後のcharactersが「見た目に何文字か」を返してくれて一番良かったのだが、Swift 4でdeprecatedになり、結局
"猫".count ->1
"🐱".count ->1
で落ち着いたようだ。
これなら楽でいいや。

2018年1月14日日曜日

任意の位置の文字を取り出す

やりたいこと

たとえば"abcdefghijklmn"という文字列の中から、任意の位置の文字(文字列)を取り出したい。

やり方

let str = "abcdefghijklmn"
let start = str.index(str.startIndex, offsetBy: 3) //①
let end = str.index(start, offsetBy: 2) //②
let subS = str[start..<end] //③
let s = String(subS) //④

昔のBASICだとRight$、Left$、Mid$とかの関数でちょいちょいできたんだけど、Swiftだとちょっと面倒。
文字を取り出す開始位置、終了位置を決め、それをSwiftのRange(範囲指定)の書き方で指定してやる必要がある。

例として4文字目から2文字「de」を取り出してみる。

①が開始位置、②が終了位置を設定するもの。

①が開始位置の指定。
offsetBy:は何文字目かということ。0オリジンのインデックスなので、4文字目なら3。

②が終了位置の指定。
直前で得た開始位置startを使い、そこから何文字目かという書き方をしている。取り出すのが2文字なのでoffsetBy:に2。
逆に終了位置を元の文字列strの先頭から数えて指定する場合は以下でもいい。
let end = str.index(str.startIndex, offsetBy: 5)
これによってともに「f」の文字の位置がendに入る。

それを
③str[start..<end]
と範囲指定をして実際に取り出す。
新しいfor構文の for i in 0...10 と同じようなやり方だ。[ ] で囲むのがなんか配列っぽい。

終了位置を1つ前にする必要あるけど、当然
str[start...end]
という書き方もできる。

注意点

④ただ使うだけならこれだけでいいんだけど、取り出した文字列はSubStringというものになってて元の文字列を参照しているだけなので、元の文字列(ここではstr)が消えると消えてしまうのだそうだ。
だから独立した文字列にするためString( )で囲んでやってる。

Swift4より前では別の書き方をしていたそうだが、それは知らんのでここでは触れない。

もっと簡単にしてよ

開始/終了位置のindexを作り…ってのはわかるけど、SubStringがどーのってのも含め、もっと簡単にして欲しいよね。
それこそBASICのmid$に相当する関数を自作しておいた方がいい。

なお、先頭から/末尾から3文字取り出すっていうのは
let pre = str.prefix(3)
let suf = str.suffix(3)
のように超簡単。SubStringになってるのかどうかは知らんが。

2017年8月20日日曜日

UITextViewのセンタリング

やりたいこと

ImageViewで描かれた吹き出しの中にTextViewを貼っている。
吹き出しの大きさが変更された時、中のテキストをそれに合わせ、吹き出しのできるだけ中心部分にセンタリングしたい。

必要なこと

TextViewのframeでなく、中のテキストが実際に表示されてる部分のrectを求め、それを元にセンタリングする。
CSSとかのpaddingに当たる値ですな。

TextViewの中のテキストの画面に表示されてる部分のみのrectはNSStringの以下の関数で得られる。
当然得られる値はTextViewのframe.sizeよりも小さくなる。

コード中のfdってのは俺のコードの都合なので無視して。
要は調べたいtextViewがどういうrectで、中のテキストはどんなフォント(サイズも含む)で画面に描画されるかを渡して調べてもらうわけだろう。

let rect = NSString(string: (fd!.textView.text)!)
                .boundingRect(with: (fd?.textView.frame.size)!,
                options: NSStringDrawingOptions.usesLineFragmentOrigin,
                attributes: [NSFontAttributeName : fd?.textView.font! as Any], context: nil)


textViewのframeサイズから得られたrectの値を引いて2で割れば上下/左右の均等なpaddingの値が求まる。
それをtextView.textContainerInset.〜に入れてやればいい。
textView.contentInset.〜と書かれてるサイトもあるけど、textContainerInsetじゃないとうまくいかないので注意。
contentInsetとはUITextViewの中にあるUIScrollViewに対するInsetだそうである。

var topPadding = (fd!.textView.bounds.size.height - rect.height * fd!.textView.zoomScale) / 2
topPadding = topPadding < 0.0 ? 0.0 : topPadding
var leftPadding = (fd!.textView.bounds.size.width - rect.width * fd!.textView.zoomScale) / 2
leftPadding = leftPadding < 0.0 ? 0.0 : leftPadding
//containerInset.topとleft(上と左の余白)を設定
fd!.textView.textContainerInset.top = topPadding
fd!.textView.textContainerInset.bottom = topPadding / 2
fd!.textView.textContainerInset.left = leftPadding
fd!.textView.textContainerInset.right = leftPadding / 2

本来ならtopとbottom、leftとrightは同じ値を入れるべきだが、なんか微妙にテキストの位置が偏るみたいだったので、bottomとrightは値を半分にしたり、いろいろ変えてテストしてる。最適な値を探してみてほしい。
いいんだよ、理論がどうであろうと、見た目ちゃんとしてればw
また、描画の関係で文字が書かれるまでの空白とか少しできるけど、いいの。完璧じゃなくても。

参考サイト

2017年1月1日日曜日

文字を修飾

LabelやTextViewなどで文字の一部の色を変えたり、フォントサイズを変えたり、影をつけたりする方法。
NSMutableAttributedStringというクラスを作り、それにattributeをaddしていくという使い方。
attributeの種類はNS○○AttributeNameというので指定する。


textViewというUITextViewがあるとして、中の文字の一部(「いうえお」の部分)を緑色で赤い影付きにする。

attributeを個別に追加

let str = NSMutableAttributedString(string: "あいうえお")


let shadow = NSShadow() //影はNSShadowというクラス

shadow.shadowColor = UIColor.red //影の色
shadow.shadowOffset = CGSize(width: 2, height: 2) //影のズレ
shadow.shadowBlurRadius = 3.0 //影の半径


//影の色

str.addAttribute(NSShadowAttributeName, value: shadow, range: NSMakeRange(1, 4))
//文字の色
str.addAttribute(NSForegroundColorAttributeName, value: UIColor.green, range: NSMakeRange(1, 4))


//textViewのattributexTextプロパティとして指定

textView.attributedText = str

attributeをまとめて追加

let str = NSMutableAttributedString(string: "あいうえお")
let shadow = NSShadow()
shadow.shadowColor = UIColor.red
shadow.shadowOffset = CGSize(width: 2, height: 2)
shadow.shadowBlurRadius = 3.0
//attributeを[]内で,区切りで複数指定
str.addAttributes([NSForegroundColorAttributeName: UIColor.green,
                   NSShadowAttributeName: shadow], range: NSMakeRange(1, 4))
textView.attributedText = str

NS○○AttributeNameのいろいろ

  • NSFontAttributeName: String // UIFont, default Helvetica(Neue) 12
    • フォント名
    • UIFontで指定
  • NSParagraphStyleAttributeName: String // NSParagraphStyle, default defaultParagraphStyle
    • 段落スタイル(文字寄せ、行末の単語をハイフンでつなぐ…など)
    • NSMutableParagraphStyleを作り、そのプロパティをいじって指定
      • .alignment = NSTextAlignmentRightなど
      • .hyphenationFactor = 0.9など 
  • NSForegroundColorAttributeName: String // UIColor, default blackColor
    • 文字色
    • UIColorで指定
  • NSBackgroundColorAttributeName: String // UIColor, default nil: no background
    • 文字背景色
    • UIColorで指定
  • NSLigatureAttributeName: String // NSNumber containing integer, default 1: default ligatures, 0: no ligatures
    • リガチャ(つなげ文字)
    • 0がなし、1があり
  • NSKernAttributeName: String // NSNumber containing floating point value, in points; amount to modify default kerning. 0 means kerning is disabled.
    • カーニング(字間)
    • 浮動小数点のNSNumberで指定
  • NSStrikethroughStyleAttributeName: String // NSNumber containing integer, default 0: no strikethrough
    • 取り消し線
    • 太さをIntで指定(フォントサイズを大きくするとそれに連れて大きくなる)
  • NSStrikethroughColorAttributeName: String // UIColor, default nil: same as foreground color
    • 取り消し線色
  • NSUnderlineStyleAttributeName: String // NSNumber containing integer, default 0: no underline
    • 下線(フォントサイズを大きくするとそれに連れて大きくなる)
    • NSUnderlineStyleSingl、NSUnderlinePatternDash(破線)などの定数も用意
  • NSUnderlineColorAttributeName: String // UIColor, default nil: same as foreground color
    • 下線の色
  • NSStrokeColorAttributeName: String // UIColor, default nil: same as foreground color
    • 中抜き文字の枠の色
  • NSStrokeWidthAttributeName: String // NSNumber containing floating point value, in percent of font point size, default 0: no stroke; positive for stroke alone, negative for stroke and fill (a typical value for outlined text would be 3.0)
    • 中抜き文字の枠の幅(フォントサイズを大きくするとそれに連れて大きくなる)
    • 負の値だと中の塗りつぶしもある
  • NSShadowAttributeName: String // NSShadow, default nil: no shadow
    • 影
  • NSTextEffectAttributeName: String // NSString, default nil: no text effect
    • 文字エフェクト
    • 今のところNSTextEffectLetterpressStyleしかない。プレスしたような文字になるようだが、確認できなかった。
  • NSAttachmentAttributeName: String // NSTextAttachment, default nil
    • テキスト内に画像の埋め込み
  • NSLinkAttributeName: String // NSURL (preferred) or NSString
    • リンクの埋め込み
  • NSBaselineOffsetAttributeName: String // NSNumber containing floating point value, in points; offset from baseline, default 0
    • ベースライン・オフセットの指定
  • NSObliquenessAttributeName: String // NSNumber containing floating point value; skew to be applied to glyphs, default 0: no skew
    • 斜め文字
    • どれくらい右に傾けるかをNSNumberのfloatで。1.0で普通に傾く。負の値だと左に傾く。
  • NSExpansionAttributeName: String // NSNumber containing floating point value; log of expansion factor to be applied to glyphs, default 0: no expansion
    • 拡大(グリフの縦横比)
    • 正の値で横長、負の値で縦長
  • NSWritingDirectionAttributeName: String // NSArray of NSNumbers representing the nested levels of writing direction overrides as defined by Unicode LRE, RLE, LRO, and RLO characters.  The control characters can be obtained by masking NSWritingDirection and NSWritingDirectionFormatType values.  LRE: NSWritingDirectionLeftToRight|NSWritingDirectionEmbedding, RLE: NSWritingDirectionRightToLeft|NSWritingDirectionEmbedding, LRO: NSWritingDirectionLeftToRight|NSWritingDirectionOverride, RLO: NSWritingDirectionRightToLeft|NSWritingDirectionOverride,
    • 文字方向(アラビア語などへの対応)
  • NSVerticalGlyphFormAttributeName: String // An NSNumber containing an integer value.  0 means horizontal text.  1 indicates vertical text.  If not specified, it could follow higher-level vertical orientation settings.  Currently on iOS, it's always horizontal.  The behavior for any other value is undefined.
    • 縦書きグリフ(0が横書き、1が縦書きだが、iOSでは0しか使えない)