[iOS] 웹 이미지 사이즈에 맞게 동적으로 ImageView 비율 조정하기

Hoojeong Kim·2022년 8월 23일
0

서버에서 보내준 이미지를 앱에서 보여줘야 한다!!
그런데 이미지 크기가 다 제각각이라서 이미지 뷰의 크기를 지정하면 다 잘리고 난리난다!!

이 문제를 Multiplier를 사용해서 해결해보자!!


현재 스토리보드의 이미지 뷰는 다음과 같이 정의되어 있다.

StackView 안에 포함되어 있고, 높이는 200이다.


이 상태로 웹 이미지를 불러와 이미지 뷰에 설정하면,
이렇게 잘려서 보인다..ㅠㅡㅠ


ImageView Ratio 설정!

현재 이미지 뷰에 높이가 설정되어 있기 때문에 사진이 잘리게 되는 건데, 이런 경우에 비율을 사용해 뷰의 크기를 지정할 수 있다.


먼저 이미지 뷰의 높이를 지우자.

그리고 비율을 설정할건데, 이미지 뷰를 오른쪽 마우스 클릭한 상태에서 자기 자신에게 놓으면 아래와 같은 창이 뜬다.

여기서 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 / heightmultiplier를 설정해준다.

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가 증가한다는 것을 알 수 있다.

높이보다 너비가 더 큰 경우에는 반대가 될 것이다.


이렇게 구현한 뒤, 다시 빌드해보면

잘리지 않고 제대로 나온다!!



profile
나 애기 개발자 👶🏻

0개의 댓글