文章の先頭や末尾にアイコン画像をつけるってやつをSwiftで比較的簡単にやってみる

React ES2015 webpack BrowserSync Babel thee.js

Posted on 2017-05-16


Webサイトなどではよく文章の先頭にアイコン画像をつけることでリンク先や文章内容を類推しやすくして読ませるってことをよくやってますね。
Yahoo! JAPANのトップページでも左カラムに各サービスへのリンクエリアを設けて先頭へ各サービスのアイコン画像を配置したりトピックなどでも末尾にカメラアイコンやNEW、またビデオ再生のアイコン画像を配置してリンク先のコンテンツには写真があるよとかビデオがあるよなどを類推しやすくしていますね。
CSSで背景に画像を配置して左パディングすることで実現したりafterやbefore疑似要素を使って配置することが一般的によくやる方法だったりします。比較的簡単にできHTMLコードへ直接画像を置くことによる弊害もありませんね。
これをiOSアプリでやろうってなるとちょっと面倒だったりします。
アプリでも文字表示って細かくコントロールしようとすると面倒です。そう考えるとHTML+CSSって文字要素を柔軟に扱いやすくしてくれてます。

でSwift3で書いてみましたがNSMutableAttributedStringってのを使うと文字にいろいろと装飾がつけれます。
FonwAwesomeKitを利用して星型のアイコン画像を作ってます。
またアイコン画像と文章にパディングをつけたかったので透明のアイコン画像をつくってます。
全角や半角スペースを挿入すればまあそれなりのスペースは作れますがなんとなく空き文字をいれるってのはアクセシビリティ的にも避けたかったのでこうしました。
最後にlabel(UILabel)のattributedTextにいれます。

let iconSize: CGFloat = 13.0
let starIcon = FAKFontAwesome.starIcon(withSize: iconSize)
starIcon?.addAttribute(NSForegroundColorAttributeName, value: UIColor.red)
let starIconImage = (starIcon?.image(with: CGSize(width:iconSize, height: iconSize)))! as UIImage

let muAttString = NSMutableAttributedString.init(string: "10,000")

//アイコン画像を先頭につけたテキストにします
let txtAtt = NSTextAttachment.init()
txtAtt.image = starIconImage
txtAtt.bounds = CGRect(x: 0, y: -1, width: iconSize, height: iconSize)
let attAttString = NSAttributedString.init(attachment: txtAtt)
muAttString.insert(attAttString, at: 0)

//アイコン画像を先頭につけたテキストにします
let txtAttEmpty = NSTextAttachment.init()
let paddingWidth = iconSize * 0.2

//空きの塗りつぶし画像を作ります
let rect = CGRect(origin: CGPoint(x: 0, y: 0), size: CGSize(width: paddingWidth, height: iconSize))
UIGraphicsBeginImageContextWithOptions(size, false, 0)
UIColor.clear.setFill()
UIRectFill(rect)
let emptyImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
txtAttEmpty.image = emptyImage
txtAttEmpty.bounds = CGRect(x: 0, y: -2, width: paddingWidth, height: iconSize)
let attAttStringEmpty = NSAttributedString.init(attachment: txtAttEmpty)
muAttString.insert(attAttStringEmpty, at: 1)

//ラベルにテキストを設定します
label.attributedText = muAttString

なんども使うようならclass化した方が使い勝手よいですよね。 色で塗りつぶしたUIimageをつくるgetImageWithColorとわけて使っています。

import UIKit

class Utils: NSObject {

  //空きの塗りつぶし画像を返す
  class func getImageWithColor(color: UIColor, size: CGSize) -> UIImage {
    let rect = CGRect(origin: CGPoint(x: 0, y: 0), size: CGSize(width: size.width, height: size.height))
    UIGraphicsBeginImageContextWithOptions(size, false, 0)
    color.setFill()
    UIRectFill(rect)
    let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
    UIGraphicsEndImageContext()
    return image
  }

  //アイコン付きテキスト(NSMutableAttributedString)を返す
  class func getInsertIconString(string: String, iconImage: UIImage, iconSize: CGFloat) -> NSMutableAttributedString {

    let muAttString = NSMutableAttributedString.init(string: string)

    //アイコン画像を先頭につけたテキストにします
    let txtAtt = NSTextAttachment.init()
    txtAtt.image = iconImage
    txtAtt.bounds = CGRect(x: 0, y: -1, width: iconSize, height: iconSize)
    let attAttString = NSAttributedString.init(attachment: txtAtt)
    muAttString.insert(attAttString, at: 0)

    //アイコン画像の左に余白をつけたテキストにします
    let txtAttEmpty = NSTextAttachment.init()
    let paddingWidth = iconSize * 0.2
    txtAttEmpty.image = Utils.getImageWithColor(color: UIColor.clear, size: CGSize(width: paddingWidth, height: iconSize))
    txtAttEmpty.bounds = CGRect(x: 0, y: -2, width: paddingWidth, height: iconSize)
    let attAttStringEmpty = NSAttributedString.init(attachment: txtAttEmpty)
    muAttString.insert(attAttStringEmpty, at: 1)

    return muAttString
  }
}

Utils.swiftというファイルでclass化します。

let iconSize: CGFloat = 13.0
let starIcon = FAKFontAwesome.starIcon(withSize: iconSize)
starIcon?.addAttribute(NSForegroundColorAttributeName, value: UIColor.red)
let starIconImage = (starIcon?.image(with: CGSize(width: iconSize, height: iconSize)))! as UIImage
//先頭にアイコン画像をつけたい文字列とアイコン画像を引数で渡します
label.attributedText = Utils.getInsertIconString(string: "10,000", iconImage: starIconImage, iconSize: iconSize)

こっちは呼び出し元ですね。

shigeki.takeguchi

渋谷の某ソーシャルゲームの会社でフロントエンドエンジニアとして働いてます。20世紀よりウェブ業界。気づいたらアラフィフ業界人です。
まだまだ現場で粘り強く作る側でいたいと思います。

By year

  1. 2017 (14)
  2. 2016 (23)
  3. 2015 (13)
  4. 2013 (15)
  5. 2012 (21)
  6. 2011 (34)

© 2012 shigeki.takeguchi