서버에서 보내준 이미지를 앱에서 보여줘야 한다!!
그런데 이미지 크기가 다 제각각이라서 이미지 뷰의 크기를 지정하면 다 잘리고 난리난다!!
이 문제를 Multiplier
를 사용해서 해결해보자!!
현재 스토리보드의 이미지 뷰는 다음과 같이 정의되어 있다.
StackView 안에 포함되어 있고, 높이는 200이다.
이 상태로 웹 이미지를 불러와 이미지 뷰에 설정하면,
이렇게 잘려서 보인다..ㅠㅡㅠ
현재 이미지 뷰에 높이가 설정되어 있기 때문에 사진이 잘리게 되는 건데, 이런 경우에 비율을 사용해 뷰의 크기를 지정할 수 있다.
먼저 이미지 뷰의 높이를 지우자.
그리고 비율을 설정할건데, 이미지 뷰를 오른쪽 마우스 클릭한 상태에서 자기 자신에게 놓으면 아래와 같은 창이 뜬다.
여기서 Aspect Ratio
를 선택하자.
이제 ViewController로 이동하자.
ViewController에 새로운 아웃렛 변수를 선언한다.
@IBOutlet weak var imageRatio: NSLayoutConstraint!
그리고 스토리보드와 소스파일을 함께 열어, 파란색으로 나타나는 비율을 imageRatio
변수와 연결해준다.
웹 이미지는 Nuke라는 라이브러리를 사용해 가져온다.
먼저 Nuke를 사용해 이미지를 로드하는 함수를 구현하자.
public func setNukeImage(url: String, iv: UIImageView, placeholderImageName: String = "", callback:@escaping (UIImage?) -> (), errorCallback:@escaping () -> ()) {
let encodedString = url.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
if let url = URL(string: encodedString) {
let request = ImageRequest(url: url)
var options: ImageLoadingOptions = getOptions()
if "" != placeholderImageName {
options.placeholder = UIImage(named: placeholderImageName)
}
Nuke.loadImage(with: request, options: options, into: iv) { result in
if case let .success(response) = result {
callback(response.container.image)
} else {
errorCallback()
}
}
}else {
errorCallback()
}
}
func getOptions() -> ImageLoadingOptions {
var options = ImageLoadingOptions(
placeholder: UIImage(named: "placeholder"),
transition: .fadeIn(duration: 0.25),
failureImage: UIImage(named: "failureImage"),
contentModes: .init(success: .scaleAspectFill, failure: .center, placeholder: .scaleAspectFill)
)
options.pipeline = getPipeline()
_ = ImagePrefetcher(destination: .diskCache)
return options
}
이어서 앞서 만든 이미지 뷰에 이미지를 로드해보자.
setNukeImage
함수를 Callback으로 구현했기 때문에, 각각 맞는 동작을 작성하면 된다.
setNukeImage(url: imageURL, iv: ivImage) { image in
let width = image?.size.width ?? 0
let height = image?.size.height ?? 0
self.imageRatio = self.imageRatio.setMultiplier(multiplier: width / height)
} errorCallback: {
self.ivImage.isHidden = true
}
func setMultiplier(multiplier:CGFloat) -> NSLayoutConstraint {
NSLayoutConstraint.deactivate([self])
let newConstraint = NSLayoutConstraint(
item: firstItem,
attribute: firstAttribute,
relatedBy: relation,
toItem: secondItem,
attribute: secondAttribute,
multiplier: multiplier,
constant: constant)
newConstraint.priority = priority
newConstraint.shouldBeArchived = self.shouldBeArchived
newConstraint.identifier = self.identifier
NSLayoutConstraint.activate([newConstraint])
return newConstraint
}
여기서 이 부분을 보면,
웹 이미지의 너비와 높이 값을 받아, width / height
로 multiplier
를 설정해준다.
let width = image?.size.width ?? 0
let height = image?.size.height ?? 0
self.imageRatio = self.imageRatio.setMultiplier(multiplier: width / height)
이 말은 즉, 이미지 사이즈에 따라 이미지 뷰의 너비와 높이를 조정한다는 뜻!
어.. 무슨 말인지 모르겠다면 이어서 보자!
이미지 뷰의 Aspect Ratio를 선택하면 아래와 같이 Aspect Ratio Constraint 창을 확인할 수 있다.
여기서 First Item, Second Item, Constant, Multiplier에는 다음 공식이 성립한다.
FirstItem.Attribute = Multiplier * SecondItem.Attribute + Constant
0인 Constant 값을 제외하면, Multiplier 값에 따라 각 항의 값이 증가하는 것을 알 수 있다.
현재를 공식에 대입하면 아래와 같다.
ivImage.width = Multiplier * ivImage.height
만약 Multiplier의 값이 2라면, 이미지 뷰의 너비가 높이의 2배가 된다.
이를 활용해 이미지 뷰의 크기를 조절할 수 있다.
이제 이 코드를 다시 보자.
let width = image?.size.width ?? 0
let height = image?.size.height ?? 0
self.imageRatio = self.imageRatio.setMultiplier(multiplier: width / height)
여기서 이미지 뷰의 Multiplier 값을 width / height
로 설정했다.
만약 너비보다 높이가 더 큰 이미지라면, width / height 값은 1보다 작은 값일 것이다.
앞서 구했던 공식에 대입한다면, 그만큼 이미지 뷰의 height가 증가한다는 것을 알 수 있다.
높이보다 너비가 더 큰 경우에는 반대가 될 것이다.
이렇게 구현한 뒤, 다시 빌드해보면
잘리지 않고 제대로 나온다!!
끗