AsyncImage
에 대해 알아보도록 합시다.
AsyncImage
iOS 15로 업데이트되면서 추가된 기능인데, AsyncImage
는 URLSession
인스턴스를 사용하여 할당된 URL
에서 이미지를 가져오는 기능을 가지고 있다.
디바이스를 실행하고 몇 초의 시간 후 이미지가 나타나게 하려면 AsyncImage
를 사용할 수 있다.
먼저 간단하게 Url Image
를 코드작성한다.
import SwiftUI
struct ContentView: View {
private let imageName: String = "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlI00H%2FbtqXQ6wtwVP%2FUrgHPkbHKxeqWwHIYzoaK1%2Fimg.png"
var body: some View {
AsyncImage(url:URL(string: imageName))
}
}
앱을 실행시켜보면 몇 초의 지연 후 이미지가 나타나지만, 확대되어 나오는 것을 확인할 수 있다.
Scale
var body: some View {
AsyncImage(url:URL(string: imageName), scale: 2.0)
Scale
의 값이 클수록 이미지의 크기가 작아진다.
PlaceHolder
placeHolder
를 사용하여 어떠한 아이콘 또는 이미지가 먼저 화면에 나온 뒤, AsyncImage
가 출력될 수 있도록해 줄 수 있다.
var body: some View {
AsyncImage(url:URL(string: imageName)) { image in
image
.resizable()
.scaledToFit()
} placeholder: {
Image(systemName: "paperplane.circle.fill")
.resizable()
.scaledToFit()
.frame(maxWidth: 200)
.foregroundColor(.blue.opacity(0.6))
}
.padding(20)
}
Resizable
과 같은 수정자는 AsyncImage
에 직접 사용이 불가하므로 Image
인스턴스에 적용해야 한다.
Image Extenstion
작성한 코드를 살펴보면 이미지의 수정자 중 중복되는 코드가 두 가지나 있다. 코드를 작성할 때 중복 코드는 상당히 보기 좋지 않다. 이럴 때 사용 가능한 Extenstion
프로퍼티이다.
비동기 이미지와 Icon
에 있는 .resizable()
과 .scaledToFit()
수정자를 다음과 같이 코드를 생성할 수 있다.
extension Image {
func ImageModifier() -> some View {
self
.resizable()
.scaledToFit()
}
}
ImageModifier
메서드의 반환 타입을 some View
로 지정해주고 그 안에 수정자를 포함시켰다.
모든 인스턴스는 암시적으로 생성된 self 프로퍼티를 갖는데, 바로 인스턴스 자기 자신을 가리키는 프로퍼티이다.
Image
수정자 메서드는 작성했고, 이제 IconModifier
도 추가해준다.
extension Image {
func ImageModifier() -> some View {
self
.resizable()
.scaledToFit()
}
func IconModifier() -> some View {
self
.ImageModifier()
.frame(maxWidth: 200)
.foregroundColor(.blue.opacity(0.6))
}
}
새로운 IconModifier
메서드에 ImageModifier
를 포함시킬 수 도 있다.
호출 방법
Image extension
을 호출은 아래와 같이 할 수 있고, 코드는 간결해지고 보기도 쉬워졌다.
var body: some View {
AsyncImage(url:URL(string: imageName)) { image in
image.ImageModifier()
} placeholder: {
Image(systemName: "paperplane.circle.fill")
.IconModifier()
}
.padding(20)
}
AsyncImagePhase (Phase)
init(url: scale: transaction: content: )
이니셜라이저를 사용하여 AsyncImage
인스턴스를 생성할 때, 현재 상태를 로드하는 동안 이 클로저를 호출하게 된다. 이 단계에서 몇 가지의 상태를 파악할 수 있게 되는 것이다.
기본 코드
if let
AsyncImage(url: URL(string: "https://example.com/icon.png")) { phase in
if let image = phase.image {
.resizable()
.aspectRatio(contentMode: .fit)
.clipShape(RoundedRectangle(cornerRadius: 15))
.padding() // Displays the loaded image.
} else if phase.error != nil {
Text(.localizedDescription)
} else {
emptyView() // Acts as a placeholder.
}
}
switch
AsyncImage(url: URL(string: imageName)) { phase in
switch phase {
case .success(let image):
image
.resizable()
.padding()
case .failure(let error):
VStack {
Image(systemName: "photo.circle.fill")
.IconModifier()
Text("error code : \(error.localizedDescription)")
.padding()
.lineLimit(3)
}
case .empty:
Image(systemName: "photo.circle.fill")
.IconModifier()
@unknown default:
defaultView()
}
}
사용 방법
AsyncImage
는 이렇게 사용 가능하다.
if let
import SwiftUI
extension Image {
func ImageModifier() -> some View {
self
.resizable()
.scaledToFit()
}
func IconModifier() -> some View {
self
.ImageModifier()
.frame(maxWidth: 200)
.opacity(0.6)
}
}
struct ContentView: View {
private let imageName: String = "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlI00H%2FbtqXQ6wtwVP%2FUrgHPkbHKxeqWwHIYzoaK1%2Fimg.png"
var body: some View {
AsyncImage(url: URL(string: imageName)) { phash in
//SUCCESS : 이미지 로드 성공
//FAILURE : 이미지 로드 실패 에러
//EMPTY : 이미지 없음. 이미지가 로드되지 않음
if let image = phash.image {
image.ImageModifier()
} else if phash.error != nil {
Image(systemName: "exclamationmark.icloud.fill").IconModifier().foregroundColor(.red)
} else {
Image(systemName: "photo.circle.fill").IconModifier().foregroundColor(.blue)
}
}
}
}
switch
var body: some View {
AsyncImage(url: URL(string: imageName)) { phase in
switch phase {
//SUCCESS : 이미지 로드 성공
//FAILURE : 이미지 로드 실패 에러
//EMPTY : 이미지 없음. 이미지가 로드되지 않음
case .success(let image):
image.ImageModifier()
case .failure(_):
Image(systemName: "exclamationmark.icloud.fill").IconModifier().foregroundColor(.red)
case .empty:
Image(systemName: "photo.circle.fill").IconModifier().foregroundColor(.blue)
@unknown default:
//Image(systemName: "photo.circle.fill").IconModifier()
ProgressView()
}
}
}
Animation / Transaction
init(url: scale: transaction: content: )
AsyncImage
에 Animation
효과를 주려면 다음과 같이 작성할 수 있다. transition
효과에 대해 자세히 보려면 여기를 클릭하세요.
transaction 옵션response
- dampingFraction이 0일 때 하나의 진동을 완료하는 데 걸리는 시간dampingFraction
- spring이 얼마나 빨리 멈추는지 제어
➜ 값이 0이면 animation이 멈추지 않음blendDuration
- animation 사이 transition의 길이를 정함
➜ 값이 0일 경우 blending을 끔
var body: some View {
AsyncImage(url: URL(string: imageName), transaction: Transaction(animation: .spring(response: 0.7, dampingFraction: 0.5, blendDuration: 0.3))) { phase in
switch phase {
case .success(let image):
image.imageModifier()
.transition(.move(edge: .bottom)) //아래에서 위로 튀어오르는 효과
case .failure(_):
Image(systemName: "exclamationmark.icloud.fill")
.iconModifier()
case .empty:
Image(systemName: "photo.circle.fill")
.iconModifier()
@unknown default:
ProgressView()
}
}
.padding(30)
}
종류는 아래 말고도 다양하게 많이 있으니 써보는 것을 추천!
image.imageModifier()
.transition(.move(edge: .bottom))
.transition(.slide)
.transition(.scale)
.transition(AnyTransition.scale.animation(.easeInOut))
결과를 확인할 때, 캔버스의 프리뷰에서는 애니메이션 효과가 나타나지 않기 때문에 ⌘ + R 단축키를 사용해 시뮬레이터에서 빌드해야 한다.
AsyncImage
AsyncImage는 iOS 15 이상부터 사용 가능합니다.
읽어주셔서 감사합니다🤟
'SWIFTUI > Image' 카테고리의 다른 글
SwiftUI : Path / Shape (1) | 2021.04.22 |
---|---|
SwiftUI : AspectRatio / GeometryReader / GeometryProxy (3) | 2021.04.04 |
SwiftUI : ContainerRelativeShape (위젯에서만 사용가능) (0) | 2021.03.13 |
SwiftUI : trim( ) - Shape의 일부 그리기 (Timer) (0) | 2021.03.13 |
SwiftUI : Shape (Rectangle, Circle, Capsule...) (0) | 2021.01.22 |