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

UIButtonのimageViewは左、titleLabelは右に配置されるのが一般的です。
その配置を逆にしようとした時に少し苦戦したので、備忘録として記載します。

## 環境
Xcode 11.6
Swift 5.2

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

![button.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149055/27dcd792-088c-fda0-562e-fd7b36e90b38.png)


```swift
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)
```


## 左右反転させたUIButtonにbackgroundImageをセットする
背景が単なる単色の場合は上記で想定通りのボタンが完成します。
しかし、背景にも画像を用いる場合にはもう一工夫が必要です。

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

| 用意した画像 | そのまま背景画像をセットした結果 |
| :---: | :---: |
| <img alt="background.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149055/52951ffa-2c55-776a-58f6-155c76e13be9.png" width="170px" /> | ![スクリーンショット 2020-09-03 16.21.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149055/cb066ea1-8927-66a4-d48a-6263ec2be838.png) |

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

```swift
let button = UIButton()

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

![SampleButton.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149055/981131a8-2262-a87f-723a-33ca0630e360.png)
## サンプルコード
titleLabelとimageViewを左右逆に配置させたUIButtonのサンプルは、Playgroundを使って以下のコードで試せます。


```swift
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))
```