UIButtonのtitleLabelとimageViewを左右逆に配置する

f:id:Rakuma:20201008160509p:plain

はじめまして。ラクマでモバイルエンジニアをやっているkurapyです。

iOSアプリを作るうえでよく利用されるUIButtonのimageViewは左、titleLabelは右に配置されるのが一般的です。 その配置を逆にしようとした時に少し苦戦したので、どう対応したのかをお話ししようと思います。

環境

Xcode 12.0.1 Swift 5.3

titleLabelとimageViewを左右逆に配置する

imageViewを右、titleLabelを左に配置したい場合、UIButtonを左右反転することで配置することができます。 その際、imageViewやtitleLabelも反転してしまい、文字や画像まで反対になってしまうので、それぞれをもう一度左右反転させて元に戻します。

let button = UIButton()

// Buttonを左右反転させる
transform = CGAffineTransform(scaleX: -1, y: 1)
// 文字が反転するため、titleLabelを左右反転させ元に戻す
titleLabel?.transform = CGAffineTransform(scaleX: -1, y: 1)
// imageが反転するため、imageViewを左右反転させ元に戻す
imageView?.transform = CGAffineTransform(scaleX: -1, y: 1)

f:id:Rakuma:20201007112732p:plain

左右反転させたUIButtonにbackgroundImageをセットする

背景が単なる単色の場合は上記で想定通りのボタンが完成します。 しかし、背景にも画像を用いる場合にはもう一工夫が必要です。

上記の対応ではUIButton自体は左右反転した状態のため、そのまま button.setBackgroundImage(_:for:) してしまうと背景画像も反転したまま表示されてしまいます。

用意した画像 そのまま背景画像をセットした結果
background.png f:id:Rakuma:20201007111741p:plain

画像を正しい向きで表示させたい場合、左右反転させた状態の画像をsetBackgroundImageすることで対応できます。

let button = UIButton()

// titleLabelとimageViewの位置を反転させるためにbuttonを反転させる時にbackgroundImageも反転されてしまうため、反転させた画像をセットする
let backgroundImage = UIImage(named: "background.png")?.withHorizontallyFlippedOrientation()
button.setBackgroundImage(backgroundImage, for: .normal)

f:id:Rakuma:20201007111736p:plain

サンプルコード

titleLabelとimageViewを左右逆に配置させたUIButtonのサンプルは、Playgroundを使って以下のコードで試せます。

import UIKit
import PlaygroundSupport

final class SampleButton: UIButton {
    override init(frame: CGRect) {
        super.init(frame: frame)

        setTitle("サンプル", for: .normal)
        setTitleColor(.white, for: .normal)
 
        let image = UIImage(named: "image.png")
        setImage(image, for: .normal)
        imageView?.contentMode = .scaleAspectFit

        // titleLabelとimageViewの位置を反転させるためにbuttonを反転させる時にbackgroundImageも反転されてしまうため、反転させた画像をセットする
        let backgroundImage = UIImage(named: "background.png")?.withHorizontallyFlippedOrientation()
        setBackgroundImage(backgroundImage, for: .normal)

        // Buttonを左右反転させる
        transform = CGAffineTransform(scaleX: -1, y: 1)
        // 文字が反転するため、titleLabelを左右反転させ元に戻す
        titleLabel?.transform = CGAffineTransform(scaleX: -1, y: 1)
        // imageが反転するため、imageViewを左右反転させ元に戻す
        imageView?.transform = CGAffineTransform(scaleX: -1, y: 1)

        // 左右反転させているため、左側に設定したい値をrightに、右側に設定したい値をleftに設定する
        contentEdgeInsets = UIEdgeInsets(top: 8, left: 16, bottom: 8, right: 16)
        imageEdgeInsets = UIEdgeInsets(top: 8, left: 0, bottom: 0, right: 4)
        titleEdgeInsets = UIEdgeInsets(top: 8, left: 0, bottom: 0, right: 0)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

PlaygroundPage.current.liveView = SampleButton(frame: CGRect(x: 0, y: 0, width: 150, height: 50))

以上、UIButtonのtitleLabelとimageViewを左右逆に配置する方法を簡単にまとめてみました。

他にもやり方はあるかと思いますが、ユーザーにわかりやすいUIづくりのお役に立てれば幸いです。