BOID

[swiftUI] swiftUI에서 이미지(Image)란? 본문

swiftUI시작기

[swiftUI] swiftUI에서 이미지(Image)란?

HoonIOS 2022. 3. 13. 17:52
728x90

안녕하세요,  HoonIOS입니다.

UIKit에서 이미지를 표현할 때는 UIImage객체에 이미지를 만들어주고 해당 객체를 UIImageView에 넣어줘서 표현을 했습니다.

반면에 SwiftUI에서는 이렇게 복잡하게 진행하지 않고 바로 이미지를 넣어줘서 표현을 해줄 수 있습니다.

 

얼마나 간단해졌는지 비교해보겠습니다.

//UIKit
let image: UIImage = UIImage(named: "HoonIOS")

UIImageView(UIImageView 객체).image = image

//SwiftUI
Image("HoonIOS")

엄청 간단하게 이미지를 표현해줄 수 있는걸 코드로 볼 수 있습니다!

 

SwiftUI에서 image의 가장 큰 특징은 기본적으로 주어진 공간하고 상관이 없이 고유한 크기를 유지한다는것입니다.

 

예를 들어 이미지의 크기가 100 x 100인 이미지를 50 X 50 또는 200 X 200으로 크기로 변경한다고 해도 이미지 크기는 변하지 않고 컨테이너 뷰의 크기만 달라지는 것을 볼 수 있습니다.

 

이해가 잘 안 되시죠? 아래 코드와 예시로 한번 확인해보겠습니다.

 

swiftUIResize라는 이미지가 있다고 가정하고 코드를 작성해보겠습니다.

HStack {
    Image("swiftUIResize")
        .border(Color.yellow)
    Image("swiftUIResize").frame(width: 50, height: 50)
        .border(Color.red)
    Image("swiftUIResize").frame(width: 100, height: 100)
        .border(Color.blue)
}

이렇게 frame을 각자 다르게 설정하고 각 border을 설정해줬을 때 UIKit의 기준으로는 각자 다른 사이즈의 이미지가 들어갈 것이라고 가정을 합니다.

 

그렇지만 swiftUI에서는 아래와 같은 결과를 볼 수 있습니다.

 

 

어떤가요? 각 이미지의 크기는 같지만 실제로 컨테이너 뷰들은 각자 frame에 맞게 설정되어 있는것을 볼수 있죠 

따라서 frame을 이미지와 맞지않게 설정을 했을때 이미지끼리 겹치는 경우가 있을수 있으니 주의해야 합니다.

 

 

 

 

 

Image의 수식어들

Image의 여러 가지 수식어들을 한번 확인해보겠습니다.

 

수식어 explain
Resizable - 이미지 크기를 변경해야 하는경우에는 resizeable 수식어를 적용해야 합니다.
(단, 이 수식어는 frame수식어보다 먼저 적용되어야 함)
- 이 수식어를 위 코드에서 적용한다면 이미지 사이즈가 변화하는것을 확인할수 있습니다.
- 이미지 타입에 선언되어 있으므로 뷰 프로토콜이 반환되는 수식어를 사용하기 전에 호출해야 합니다. 
- UIKit의 resizableImage 메서드와 동일한 역할을 수행합니다.
ContentMode - 이미지의 비율을 설정해주는 메서드 입니다.
- Scale To Fill, Aspect, Aspect Fit, Aspect Fill이 있습니다.
- 뷰 프로토콜이 반환되는 수식어를 사용하기 전에 호출해야 합니다. 

종류) Scale To Fill, Aspect Fit, Aspect Fill
Scale To Fill은 비율하고 관계 없이 이미지를 늘려 공간을 가득 채우는것을 가장 default한 값이다.
Aspect Fit은 이미지 원본의 비율을 그대로 유지한 상태에서 가능한 최대 크기까지 늘어나게 해주는데 최대 크기는 공간의 너비와 높이 중 작은값을 기준
Aspect Fill은 이미지 원본의 비율을 그대로 유지한 상태에서 가능한 최대한 크기까지 늘어나게 해주는데 Aspect Fit과 다른점은 최대 크기는 공간의 너비와 높이중 큰 값을 기준

적용) .scaledToFit(), ScaleToFill()

AspectRatio - 이미지 비율에대해 세부조정이 필요할때 aspectRatio 수식어를 사용합니다.
- 이미지의 너비와 높이의 비율을 조정합니다.
- 이 메서드는 매개변수로 CGFloat또는 CGSize를 전달 받는데 CGFloat타입에는 너비 / 높이를 계산한 비율을 전달 받고 CGSize타입에는 width, heigth에 각각 원하는값을 입력 받는다.
- contentMode를 통해서 scaledToFit은 .fit을 통해 적용하고 scaledToFill은 .fill을 통해 적용한다.
ClipShape - 이 수식어를 통해서 이미지를 원하는 모양으로 만들수 있습니다.
- 원하는 도형의 모습만 남기고 나머지 이미지는 잘라버리는 기능입니다.
- 여기서 도형의 크기는 원하는 크기로 조정도 가능합니다.
RenderingMode - 총 2가지 렌더링 모드가 있습니다.
template - 이미지에서 불투명 영역을 원하는 색으로 변경해서 템플릿 이미지에 적용하는 모드 
original - 항상 이미지 원래의 색을 유지하는 모드
- 만약 이미지에 renderingMode 수식어를 생략했거나 nil을 전달했을 경우 시스템이 알아서 판단해 두가지중 하나를 사용하게 됩니다.
이 경우를 원하지 않으면 설정하면 되겠죠?

ImageScale - 이 수식어는 이미지 스케일을 지정하는 수식어입니다.
- 수식어 종류로는 총 3가지가 있습니다.
small - 작은 스케일
medium - 중간 스케일
large - 큰 스케일
- 이미지의 각 심벌에 원하는 색을 .foregroundcolor속성을 통해 쉽게 적용시킬수 있습니다.
Font - 이미지에 Font가 들어간다고 의아해 할수 있으실겁니다. 이미지에서 Font를 이용해서 크기를 변경하는것도 가능하다고 합니다!~
Weight - 이미지에 굵기를 표현할수도 있는데 굵기를 변경하려면 font 수식어를 이용해서 변경해야 합니다.

 

여기서 ImageScale, Font, Weight 수식어시스템 이미지 즉 심벌 이미지에서 적용되는 수식입니다. 이 부분은 주의하셔야 합니다!~

 

이제 하나씩 수식어를 예를 들어서 차이 및 이미지를 확인해보겠습니다.

단 여기서는 swiftUIResize라는 이미지를 Asset에 있다는 가정하에 적용하는 실습입니다.

 

Resizable

* 코드

HStack {
    Image("swiftUIResize")
        .border(Color.yellow)
    Image("swiftUIResize")
        .resizable()
        .frame(width: 50, height: 50)
        .border(Color.red)
    Image("swiftUIResize").frame(width: 100, height: 100)
        .border(Color.blue)
}

* 결과

- 이미지의 사이즈가 다시 재정의 된 것을 볼 수 있습니다.

 

resizeable의 capInsets와 resizable에 대해 무슨 차이인지 확인해보겠습니다.

* 코드

HStack {
    Image("swiftUIResize")
        .resizable(capInsets: .init(top: 0, leading: 100, bottom: 0, trailing: 0))
        .frame(width: 50, height: 50)
        .border(Color.red)
    Image("swiftUIResize")
        .resizable(resizingMode: .tile)
        .frame(width: 200 , height: 200)
        .border(Color.blue)
}

* 결과

- capsInset을 통해서 top, leading, bottom, trailing을 적용해줬을 때 각 주어진만큼 위 왼쪽 아래 오른쪽으로 이미지가 이동하는 것을 볼 수 있습니다.

- 반면 resizingMode를 tile로 했을 때 이미지가 여러 개로 타이 형태로 나오는 것을 확인할 수 있습니다.

 

ContentMode

* 코드

HStack {
    Image("swiftUIResize")
        .resizable()
        .scaledToFit()
        .frame(width: 150, height: 50)
        .border(Color.red)
    Image("swiftUIResize")
        .resizable()
        .scaledToFill()
        .frame(width: 150, height: 50)
        .border(Color.blue)
}

* 결과

- 같은 프레임을 가졌을 때 scaledToFill은 이미지가 frame만큼 꽉 차는 것을 볼 수 있고 scaledToFit은 넓이 높이중 최소의 크기에 크기가 맞춰지는것을 볼수 있습니다.

 

AspectRatio

*코드

HStack {
    Image("swiftUIResize")
        .resizable()
        .aspectRatio(CGSize(width: 1.5, height: 1), contentMode: .fit)
        .frame(width: 150, height: 50)
        .border(Color.red)
    Image("swiftUIResize")
        .resizable()
        .aspectRatio(0.5, contentMode: .fill)
        .frame(width: 150, height: 50)
        .border(Color.blue)
}

* 결과

- .aspectRatio(0.5, contentMode: .fill)을 적용한 이미지를 보면 scaledToFill 콘텐츠 모드를 적용 후 너비가 높이의 0.5배의 비율을 가지도록 적용했습니다.

- .aspectRatio(CGSize(width: 1.5, height: 1), contentMode: .fit)을 적용한 이미지를 보면 sclaedToFit 콘텐츠 모드를 적용한 후 너비가 높이보다 1.6배의 비율을 가지도록 조정을 한 모습을 볼 수 있습니다.

 

ClipShape

* 코드

 HStack {
    Image("swiftUIResize")
        .clipShape(Circle().inset(by: 30))
        .border(Color.red)
    Image("swiftUIResize")
        .clipShape(Rectangle().inset(by: 30))
        .border(Color.blue)
}

* 결과

- .circleShape을 통해 Circle().inset(by: 30), Rectangle().inset(by: 30) 원 , 사각형으로 이미지를 자른 것을 볼 수 있습니다. 여기서. inset이란 왼쪽부터 떨어진 위치를 이동한 것으로 각 왼쪽부터 30 떨어진 위치부터의 원 사각형을 잘라준 것입니다.

 

RenderingMode

* 코드

HStack {
    Image("swiftUIResize")
        .border(Color.yellow)
    Image("swiftUIResize")
        .renderingMode(.original)
        .border(Color.blue)
    Image("swiftUIResize")
        .renderingMode(.template)
        .border(Color.blue)
}
.foregroundColor(Color.red)

* 결과

- default값으로는 renderingMode을 적용하지 않았을 때는 original로 적용한 것을 볼 수 있어 뒤에 foregroundColor을 red로 설정해준줘도 기본 이미지로 적용된것을 볼수 있습니다.

- 반면. template을 적용한 이미지는 이미지의 불투명 영역에 대해 색을 red로 입혀진 것을 볼 수 있죠!

 

ImageScale

* 코드

HStack {
    Image(systemName: "trash.fill")
        .imageScale(.small)
        .border(Color.yellow)
    Image(systemName: "trash.fill")
        .imageScale(.medium)
        .border(Color.green)
    Image(systemName: "trash.fill")
        .imageScale(.large)
        .border(Color.blue)
}

* 결과

- 각 system 이미지의 크기가 다르게 적용한 것을 볼 수 있습니다. 여기서 .foreground을 적용하면 각 심볼 이미지의 색상도 변경되는것을 볼수 있습니다.

 

Font

* 코드

 HStack {
    Image(systemName: "trash.fill")
        .font(.body)
        .border(Color.yellow)
    Image(systemName: "trash.fill")
        .font(.title)
        .border(Color.green)
    Image(systemName: "trash.fill")
        .font(.system(size: 40))
        .border(Color.blue)
    Image(systemName: "trash.fill")
        .font(.largeTitle)
        .border(Color.purple)
}

* 결과

- font의 설정에 따라 systemImage의 크기가 변경되는것을 볼수 있습니다.

 

Weight

* 코드

HStack {
    Image(systemName: "arrow.up")
        .font(Font.title.weight(.medium))
        .border(Color.yellow)
    Image(systemName: "arrow.down")
        .font(Font.title.weight(.bold))
        .border(Color.green)
    Image(systemName: "arrow.left")
        .font(Font.title.weight(.semibold))
        .border(Color.blue)
    Image(systemName: "arrow.right")
        .font(Font.title.weight(.light))
        .border(Color.purple)
    Image(systemName: "arrow.left")
        .font(Font.title.weight(.ultraLight))
        .border(Color.black)
}

* 결과

- 이미지의 굵기가 font의 weight 설정값에 따라 변경되는것을 볼수 있습니다. 

 

 

 

지금까지 이미지에 대해 알아봤습니다. UIImage와 다루는 것은 또 다르게 크게 느껴지는 것 같습니다. 여기에 적혀있는 수식어들 말고 다른 수식어도 많으니 추후에 공부하게 되면 보충하도록 하겠습니다.

 

 

혹시 제가 포스팅한것중에 잘못되거나 이해가 안 되는 부분이 있으시면 의견 및 댓글 남겨주시면 감사하겠습니다 :)

반응형
Comments