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


概要

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

実装方法

画像の上にUIButtonを配置する

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

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

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

  1. ボタンのアクションに合わせて画像のハイライト状態を変更
    @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 InsetsImage Insetsを調整してデザインを実装します。

  1. UIButtonのControlHorizontalを左寄せにします。

  2. UIButtonのTitle InsetsImage Insetsを調整します。

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

UISemanticContentAttributeを使用

UIButtonに画像を設定してviewのSemanticForce Right-to-Leftにすると画像が右寄せになります。

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

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

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

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

参考
UISemantic​Content​Attribute
Stack Overflow

CGAffineTransformを使用

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

    @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)
    }

このコードは以下のようなことをしています。

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

参考
Stack Overflow

おまけ

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

// 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)
    }
}

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

参考
Live Renderingとの上手い付き合い方

まとめ

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