ただ画像を右側に表示したいだけなんだ・・・ - UIButtonの画像を右寄せにする

# 概要
UIButtonの画像をどうしても右寄せしたくて色々と調べたことについてのまとめです。

# 実装方法

## 画像の上にUIButtonを配置する
以下の図のように、画像の上にボタンを配置すればデザインの簡単に実装はできます。

<img width="429" alt="スクリーンショット 2017-03-29 11.18.00.png" src="https://qiita-image-store.s3.amazonaws.com/0/69901/1a5ab83e-090e-df63-29c5-73136381d142.png">


しかし、この実装方法だとボタンを押したときに画像がハイライトされません。
ハイライトさせるには以下の処理を追加する必要があります。

1. ハイライト用の画像を設定

<img width="356" alt="スクリーンショット 2017-03-29 11.19.40.png" src="https://qiita-image-store.s3.amazonaws.com/0/69901/dcebed4a-d605-61a5-05bc-2fcddde40b1f.png">

2. ボタンのアクションに合わせて画像のハイライト状態を変更

``` swift
    @IBOutlet private weak var searchButtonImageView: UIImageView!

    @IBAction private func searchButtonTouchCancel() {
        searchButtonImageView.isHighlighted = false
    }

    @IBAction private func searchButtonTouchDown() {
        searchButtonImageView.isHighlighted = true
    }

    @IBAction private func searchButtonTouchUpInside() {
        searchButtonImageView.isHighlighted = false
    }

    @IBAction private func searchButtonTouchUpOutside() {
        searchButtonImageView.isHighlighted = false
    }
```

ボタンを押したときの画像のハイライトを気にしなければとても簡単ですが、
ハイライトも考慮するとなると少し手間がかかります。

## UIButtonのEdgeInsetsを調整する
UIButtonに画像を設定してUIButtonの`Title Insets`と`Image Insets`を調整してデザインを実装します。

1. UIButtonの`Control`の`Horizontal`を左寄せにします。
<img width="350" alt="スクリーンショット 2017-03-28 20.28.04.png" src="https://qiita-image-store.s3.amazonaws.com/0/69901/669916df-c34d-623e-55ab-063f632954f6.png">

2. UIButtonの`Title Insets`と`Image Insets`を調整します。

<img width="677" alt="スクリーンショット 2017-03-28 20.22.14.png" src="https://qiita-image-store.s3.amazonaws.com/0/69901/79e306b5-66ff-af33-ef85-30b956b6ef08.png">

この実装方法なら、ボタンを押したときに画像が適切にハイライトされます。
しかし、ボタン内のテキストが可変する場合はこの実装は向いていません。
ボタン内のテキストにあわせてImage Insetsを動的に変更する必要があり調整が大変だからです。


## UISemanticContentAttributeを使用
UIButtonに画像を設定してviewの`Semantic`を`Force Right-to-Left`にすると画像が右寄せになります。

<img width="534" alt="スクリーンショット 2017-03-28 20.48.33.png" src="https://qiita-image-store.s3.amazonaws.com/0/69901/a205897b-3f92-85e1-e622-593157df22b4.png">

この方法だと画像のハイライトもボタン内の文字が可変になっても大丈夫です。
しかし、`UISemanticContentAttribute`の使い方としては適切では無いので**おすすめできません**。

そもそもUISemantic​Content​AttributeはiOS 9から追加された機能で、
Appleのドキュメントによると

> 左から右へのレイアウトと右から左へのレイアウトの切り替え時にビューを反転する必要があるかどうかを判断するために使用する

とあるので多言語対応するための機能だと思います。
今回設定した`Force Right-to-Left`は`右から左のレイアウトを使用して常に表示する`ものになるので、アラビア語など表記が左から右ではない言語を対応したときに意図したデザインにならないのではないかと思います。(確証はないので、詳しい方教えてください。)

参考
[UISemantic​Content​Attribute](https://developer.apple.com/reference/uikit/uisemanticcontentattribute)
[Stack Overflow](http://stackoverflow.com/questions/2515998/iphone-uibutton-image-position)

## CGAffineTransformを使用
以下のコードを書いてUIButtonのtransformを変更して実装する方法です。

``` swift
    @IBOutlet private weak var searchButton: UIButton!

    private func setupSearchButton() {
        searchButton.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)
        searchButton.titleLabel?.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)
        searchButton.imageView?.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)
    }
```

このコードは以下のようなことをしています。
<img width="894" alt="スクリーンショット 2017-03-28 21.37.17.png" src="https://qiita-image-store.s3.amazonaws.com/0/69901/b45cc577-cfba-6fc3-9512-66d0d4a5e91e.png">


コードを書くので、少し手間ではありますが一番いい実装方法だなと思いました。

参考
[Stack Overflow](http://stackoverflow.com/questions/7100976/how-do-i-put-the-image-on-the-right-side-of-the-text-in-a-uibutton)


# おまけ

しかし、`CGAffineTransform`を使った実装方法ではInterface Builder上で反映されません。
また、画像を右寄せしたいときにいちいちコードを書くのは面倒です。
なので、`@IBDesignable`を設定したUIButtonのサブクラスを作ることをおすすめします。

``` swift
// RightImageButton.swift

import UIKit

@IBDesignable final class RightImageButton: UIButton {

    override func awakeFromNib() {
        super.awakeFromNib()
      
        // アプリで表示されるとき
        setup()
    }

    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
    
        // InterfaceBuilderに表示するため
        setup()
    }

    private func setup() {
        transform = CGAffineTransform(scaleX: -1.0, y: 1.0)
        titleLabel?.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)
        imageView?.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)
    }
}
```

<img width="492" alt="スクリーンショット 2017-03-28 21.32.18.png" src="https://qiita-image-store.s3.amazonaws.com/0/69901/6b3e9d74-1645-4200-b20d-d4210e316864.png">

これでいちいちコードを書かずに済みますし、Interface Builder上にも表示されるのでとても便利です。


参考
[Live Renderingとの上手い付き合い方](https://speakerdeck.com/worlddowntown/live-renderingtofalseshang-shou-ifu-kihe-ifang)


# まとめ
UIButtonの画像を右寄せにする方法でした。
個人的にはCGAffineTransformを使っての実装がおすすめです。
もっと、簡単な方法やいいやり方などあれば教えてください！