コンテンツへスキップ →

TextFieldのRightViewに余白(Padding)を付ける方法【Swift】

環境

  • iOS14.5

サブクラスを作成

import UIKit

final class UnitTextField: UITextField {
...
}

UITextFieldのサブクラスを作成します。

各種、オーバライドメソッドの作成

    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
    }

    override func awakeFromNib() {
        super.awakeFromNib()
    }

    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
    }

プロパティの作成

var suffix: String?

suffixを使って、RightViewの文言を設定していきます。

RightViewにLabelをセットする

extension UnitTextField {

    func commonInit() {
        
        let rightLabel = UILabel(frame: .zero)
        rightLabel.font = font
        rightLabel.text = suffix
        rightLabel.textColor = UIColor.black
        rightLabel.sizeToFit()
        let padding: CGFloat = 8
        let container = UIView(frame: CGRect(x: 0, y: 0, width: rightLabel.bounds.width + padding, height: rightLabel.bounds.height))

        container.addSubview(rightLabel)
        rightLabel.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            rightLabel.topAnchor.constraint(equalTo: container.topAnchor),
            rightLabel.leftAnchor.constraint(equalTo: container.leftAnchor),
            rightLabel.bottomAnchor.constraint(equalTo: container.bottomAnchor),
            rightLabel.rightAnchor.constraint(equalTo: container.rightAnchor, constant: -padding),
        ])

        rightViewMode = .always
        rightView = container
    }    
}

ContainerをPadding分広げます。

commonInitの呼び出し

    var suffix: String? {
        didSet {
            commonInit()
        }
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }

    override func awakeFromNib() {
        super.awakeFromNib()
        commonInit()
    }

    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        commonInit()
    }

suffixにdidSetを使ってcommonInit()を呼び出すことによって、動的に単位を変えることがあっても対応できるようになります。 

サブクラスを適用

    @IBOutlet weak var textField: UnitTextField!

StoryboardのCustomClassとコードを書き換えます。

UnitTextの呼び出し

    textField.suffix = "キロメートル"

rightViewにラベルを表示したい時はsuffixに値を入れることにより実現します。

これで完成です。

全体

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var textField: UnitTextField!

    override func viewDidLoad() {
        super.viewDidLoad()
        textField.suffix = "キロメートル"
    }
}

final class UnitTextField: UITextField {

    var suffix: String? {
        didSet {
            commonInit()
        }
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }

    override func awakeFromNib() {
        super.awakeFromNib()
        commonInit()
    }

    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        commonInit()
    }
}

extension UnitTextField {

    func commonInit() {
        
        let rightLabel = UILabel(frame: .zero)
        rightLabel.font = font
        rightLabel.text = suffix
        rightLabel.textColor = UIColor.black
        rightLabel.sizeToFit()
        let padding: CGFloat = 8
        let container = UIView(frame: CGRect(x: 0, y: 0, width: rightLabel.bounds.width + padding, height: rightLabel.bounds.height))

        container.addSubview(rightLabel)
        rightLabel.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            rightLabel.topAnchor.constraint(equalTo: container.topAnchor),
            rightLabel.leftAnchor.constraint(equalTo: container.leftAnchor),
            rightLabel.bottomAnchor.constraint(equalTo: container.bottomAnchor),
            rightLabel.rightAnchor.constraint(equalTo: container.rightAnchor, constant: -padding),
        ])

        rightViewMode = .always
        rightView = container
    }
}

動作確認

このように動的に単位を変えてもレイアウトが崩れることはないようです。

失敗例

rightViewRecteditingRect をつかってインセットを調整しようとしたのですが、これは余白は上手くいくのですが、カーソルの位置がTextField外にズレるなどあり失敗しました。

    override func rightViewRect(forBounds bounds: CGRect) -> CGRect {
        var rect = super.rightViewRect(forBounds: bounds)
        // RightViewの右側に11ポイント余白を付ける
        rect.origin.x -= 11
        return rect
    }

    override func editingRect(forBounds bounds: CGRect) -> CGRect {
        var rect = super.editingRect(forBounds: bounds)
        rect.origin.x -= 11
        return rect
    }

参考

カテゴリー: iOS