しずおかオンラインで「まちぽスタンプ」というスタンプラリーができるiOSアプリを開発しているKazuomatzです。
このアプリで、スタンプラリーのミッションを達成すると、iPhoneのアクティビティやPokémon GOのように報酬としてバッジが貰えると楽しいと思い、バッジの実装を行いました。
バッジには色々なアイコンを表示したいですよね。そのため、色と絵柄を自由に組み合わせで様々なバッジを作るためのライブラリを考えました。
アイコンをひとつひとつ作成するのは現実的ではないので、Web開発ではお馴染みのFontAwesomeの豊富なアイコンを使って実現したいと思いました。
最終的にできあがったアプリの画面は、こんな感じ。
何となくバッジ感があってよい感じです。
スタンプラリーを管理する管理コンソールでアイコンと色を選択してバッジを設定しておきます。そのスタンプラリーのミッションを達成するとバッジを取得できる仕掛けです。
このような形で、カラーとFontAwesomeのフォント名を選択して設定します。アプリとはAPIでカラーコードとフォント名とでインタフェイスを取っています。
{
"badge_title" : "ミッションクリア",
"badge_color" : "#ed6d46",
"badge_icon" : "fa-spoon"
}
このアプリを開発した時点では、FontAwesome 4.7を使いましたが、時代はFontAwesome 5なので、FontAwesome5 対応にして、githubで公開しましたので紹介します。
AwesomeBadge
サンプルアプリはgithubからダウンロードできます。
CocoaPodsでも使えます。
pod 'AwesomeBadge'
内部でFontAwesomeのラッパーライブラリーFontAwesome.swiftを使用しています。
使い方
使い方はこんな感じです。
import AwesomeBadge
let badgeView = AwesomeBadgeView(
fontStyle: .brands, // font awesome style .solid / .regular / .brands
fontName: "fa-android", // font awesome font name 'fa-xxxxx'
frame: CGRect(x:0, y:0, width: 100,height: 100),
backgroundColor: "#a4c639" // Color (Hex String)
)
self.view.addSubView(badgeView)
- FontAwesome 5 は、スタイルがsolid / regular / brandsから選択できますので、スタイルを選択できます。
- fontNameは文字列で指定します。FontAwesome.swiftでは、フォント名がすべてenumで定義されていますが、APIでのやりとりを考えるとStringの方が何かと便利なので、引数はフォント名をStringで指定するようにしました。同じ理由で、色もUIColorではなくStringとしています。
let badgeView = AwesomeBadgeView(
fontStyle: .brands, // font awesome style .solid / .regular / .brands
fontName: "fa-android", // font awesome font name 'fa-xxxxx'
frame: CGRect(x:0, y:0, width: 100,height: 100),
backgroundColor: "#a4c639" // Color (Hex String)
gradient: false // not add GradientLayer
)
self.view.addSubView(badgeView)
こちらはお好みですが、gradient = false にするとグラデーションのないフラットなバッジになります。
@IBOutlet weak var badgeView:AwesomeBadgeView!
badgeView.drawBadge(
fontStyle: .solid,
fontName: "fa-star-and-crescent",
radius: 200,
backgroundColor: "#273751",
gradient: true,
foregroundColor: "#f4e242"
)
Interface BuilderでAwesomeBadgeViewを埋め込む場合は、drawBadgeをコールします。
foregroundColorも指定できます(デフォルトは#ffffff)。
実装について
実際にBadgeを作成しているコードは以下の通りです。
public func drawBadge(fontStyle:FontStyle ,fontName:String, radius:CGFloat, backgroundColor:String, gradient:Bool = true, foregroundColor:String = "ffffff") {
// 再呼び出しを考慮して、SubViewをすべて削除
self.subviews.forEach { (view) in
view.removeFromSuperview()
}
self.backgroundColor = UIColor(hex: backgroundColor)
self.clipsToBounds = true
self.backgroundColor = .clear
self.frame = CGRect(x: self.frame.origin.x, y: self.frame.origin.y, width: radius, height: radius)
// バッジの縁
let boderWidth:CGFloat = radius * 0.08
let backgroundView:UIView = UIView(frame:self.frame)
// バッジの縁を20%暗い色にする
backgroundView.backgroundColor = UIColor(hex: backgroundColor).darker(by: 20)
backgroundView.layer.cornerRadius = radius / 2
// フォント画像を配置するView
let badgeBackgroundViewFrame = CGRect(x: boderWidth, y: boderWidth,width: radius - boderWidth * 2, height: radius - boderWidth * 2)
let badgeBackgroundView = UIView(frame: badgeBackgroundViewFrame)
badgeBackgroundView.layer.cornerRadius = (radius - boderWidth * 2) / 2
badgeBackgroundView.clipsToBounds = true
badgeBackgroundView.backgroundColor = UIColor(hex: backgroundColor)
// 指定があればグレデーションのLayerを追加します。
if gradient {
let color = UIColor(hex: backgroundColor)
let gradientLayer:CAGradientLayer = CAGradientLayer(layer: badgeBackgroundView.layer)
gradientLayer.frame = badgeBackgroundView.bounds
gradientLayer.colors = [
color.lighter(by:60)?.cgColor as Any,
color.cgColor as Any,
color.darker(by:30)?.cgColor as Any
]
gradientLayer.cornerRadius = (radius - boderWidth * 2) / 2
badgeBackgroundView.layer.addSublayer(gradientLayer)
}
// スタイル、フォント名を指定して、フォントが描画されたUIImageViewを取得します。
let iconSize = CGSize(width: radius - boderWidth * 4, height: radius - boderWidth * 4)
let imageView:UIImageView = UIImageView(frame:CGRect(x:0,y:0,width:radius - boderWidth * 2, height:radius - boderWidth * 2))
imageView.contentMode = .center
let faFontName = FontAwesomeIcons[fontName]
if faFontName != nil {
let image = UIImage.fontAwesomeIcon(name: FontAwesome(rawValue: faFontName!)!, style: FontAwesomeStyle(rawValue: fontStyle.rawValue)!, textColor: UIColor(hex:foregroundColor), size: iconSize)
imageView.image = image
imageView.backgroundColor = .clear
imageView.layer.cornerRadius = (radius - boderWidth * 2) / 2
}
badgeBackgroundView.addSubview(imageView)
backgroundView.addSubview(badgeBackgroundView)
self.addSubview(backgroundView)
}
手軽にバッジを生成できるので、アプリのアクセントとして使ってみて下さい。