관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swift] UIButton의 imageView 크기 조절 방법 (imageView, titleLabel) 본문

iOS 응용 (swift)

[iOS - swift] UIButton의 imageView 크기 조절 방법 (imageView, titleLabel)

jake-kim 2023. 4. 4. 01:33

UIButton 하나로 구현한 화면

UIButton의 imageView, titleLabel

  • UIButton에는 내부적으로 UIImageView와 UILabel이 존재
  • 아래처럼 UIButton하나만 사용하면 버튼안에 이미지와 텍스트 삽입이 가능

UIButton하나안에 imageView, titlaLabel

import UIKit

class ViewController: UIViewController {
    private let button: UIButton = {
        let button = UIButton()
        button.setTitle("button", for: .normal)
        button.setTitleColor(.systemBlue, for: .normal)
        button.setTitleColor(.blue, for: .highlighted)
        button.addTarget(self, action: #selector(tapButton), for: .touchUpInside)
        button.backgroundColor = .lightGray
        button.layer.cornerRadius = 12
        button.clipsToBounds = true
        button.layer.borderWidth = 1
        button.layer.borderColor = UIColor.black.cgColor
        button.translatesAutoresizingMaskIntoConstraints = false
        return button
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.addSubview(button)
        NSLayoutConstraint.activate([
            button.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 16),
            button.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -16),
        ])
        
        button.setImage(UIImage(named: "img"), for: .normal)
    }
    
    @objc
    private func tapButton() {
        print("tap!")
    }
}
  • UIButton안에 있는 imageView의 크기를 설정하는 방법?
    • 1번) button.imageView, button.titleLabel 각각 인스턴스를 얻어서 autolayout을 하는 방법
button.imageView?.translatesAutoresizingMaskIntoConstraints = false
button.titleLabel?.translatesAutoresizingMaskIntoConstraints = false

...
  • 위처럼하면 코드가 길어지게되므로 다른 방법 사용
    • imageEdgeInsets 프로퍼티를 활용하여 구현이 가능

imageEdgeInsets 개념

  • UIButton에는 3가지의 inset 옵션이 존재
    • imageEdgeInsets
    • titleEdgeInsets
    • contentEdgeInsets

(3가지 구체적인 개념은 이전 포스팅 글 참고)

  • imageEdgeInsets에서 left에 10을 주면 이미지가 왼쪽에 10만큼 margin이 생기게 되어 오른쪽으로 이동
button.imageEdgeInsets = .init(top: 0, left: 10, bottom: 0, right: 0)

left:10 -> 오른쪽으로 밀림

  • inset의 핵심
    • top, left, bottom, right 모두 button과의 간격이 기준임
    • titleLabel과의 기준이 아님을 주의

ex) 만약 right: 10을 주면 아무 변동이 없음

(이미 titleLabel의 길이만큼 떨어져 있으므로 이 길이보다 작은값을 주게되면 무시됨)

button.imageEdgeInsets = .init(top: 0, left: 0, bottom: 0, right: 10)

  • titlaLabel의 길이보다 조금 더 크게 주게되면 적용됨

ex) 이미지와 titlaLabel 간의 간격을 5로 하고싶은 경우?

  • layoutSubview 에서 titleLabel의 크기가 정해질때 길이를 구해서 이 값에 + 5를 button.inageEdgeInsets의 right에 주면 해결
  • iamgeEdgeInsets.right값이 증가하면 오른쪽에 있는 label도 오른쪽으로부터 +5가 되므로 left값으로 채워줘야함
override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    
    let titleLabelWidth = button.titleLabel?.frame.width ?? 0
    guard titleLabelWidth > 0 else { return }
    let imageRightSpacing = 5.0
    button.imageEdgeInsets = .init(top: 0, left: 0, bottom: 0, right: titleLabelWidth + imageRightSpacing)
    button.titleEdgeInsets = .init(top: 0, left: imageRightSpacing, bottom: 0, right: 0)
}

 

이미지 사이즈 고정하기

  • 요구사항
    • 버튼 내부의 콘텐츠(imageView, titleLabel)의 간격을 5로 설정
    • imageView와 titleLabel사이의 간격을 16으로 설정
    • 이미지 사이즈 50 x 50으로 설정
  • 구현 방법
    • 내부 콘텐츠가 고정된 크기라고 가정하면, 버튼의 크기를 고정하고나서 내부 크기를 설정해주는 방향으로 구현
    • 구현 목적은 autolayout없이 간편하게 설정하는 것

1. 버튼 내부의 콘텐츠(imageView, titleLabel)의 간격을 5로 설정

  • contentEdgeInsets 사용 (이 값을 사용하면 뷰가 줄어드는게 아닌 커지는 쪽으로 content가 증가)
button.contentEdgeInsets = .init(top: 5, left: 5, bottom: 5, right: 5)

2. imageView와 titleLabel사이의 간격을 16으로 설정

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    
    setSpacingImageViewAndTitleLabel(spacing: 16)
}

private func setSpacingImageViewAndTitleLabel(spacing: CGFloat) {
    let titleLabelWidth = button.titleLabel?.frame.width ?? 0
    guard titleLabelWidth > 0 else { return }
    button.imageEdgeInsets = .init(top: 0, left: 0, bottom: 0, right: titleLabelWidth + spacing)
    button.titleEdgeInsets = .init(top: 0, left: spacing, bottom: 0, right: 0)
}

3. 이미지 사이즈 50 x 50으로 설정

  • 지금은 이미지 고유의 사이즈만큼 imageView가 커진 상태
  • 이미지의 크기를 줄이기 위해서 UIButton의 크기를 고정시켜버리면, 안쪽 뷰의 크기가 동적으로 변경되는 것에 맞추어서 UIButton의 크기가 동적으로 변하지 않으므로 UIButton의 크기를 고정시키는 방법은 지양
  • CGContext를 사용하여 UIImage의 크기를 줄여서 사용하면 해결

(resize 메소드 의미는 이전 포스팅 글 참고)

extension UIImage {
    func resize(targetSize: CGSize) -> UIImage? {
        let newRect = CGRect(x: 0, y: 0, width: targetSize.width, height: targetSize.height).integral
        UIGraphicsBeginImageContextWithOptions(newRect.size, true, 0)
        guard let context = UIGraphicsGetCurrentContext() else { return nil }
        context.interpolationQuality = .high
        draw(in: newRect)
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage
    }
}

private let button: UIButton = {
    let button = UIButton()
    
    // 이미지 크기 줄여서 사용
    let imageSize = CGSize(width: 100, height: 100)
    let resizedImage = UIImage(named: "img")?.resize(targetSize: imageSize)
    
    button.imageView?.contentMode = .scaleToFill
    ...
    return button
}()

주의) 이미지 크기를 줄일 때 scale을 잘못 입력하면 이미지가 흐려보이니 주의

그래픽스를 사용할때 scale을 현재 화면 크기 기준으로 잡은 경우 그래픽스를 사용할때 scale을 이미지 크기의 기준으로 잡은 경우

* 전체 코드: https://github.com/JK0369/ExUIImage_imageView

 

Comments