![SwiftUI : AsyncImage [Placeholder,Extension,Phase,Transaction] SwiftUI : AsyncImage [Placeholder,Extension,Phase,Transaction]](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
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) }
![SwiftUI : AsyncImage [Placeholder,Extension,Phase,Transaction] - AsyncImage - PlaceHolder SwiftUI : AsyncImage [Placeholder,Extension,Phase,Transaction] - AsyncImage - PlaceHolder](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
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() } } }
![SwiftUI : AsyncImage [Placeholder,Extension,Phase,Transaction] - AsyncImage - AsyncImagePhase (Phase) - 사용 방법 SwiftUI : AsyncImage [Placeholder,Extension,Phase,Transaction] - AsyncImage - AsyncImagePhase (Phase) - 사용 방법](https://blog.kakaocdn.net/dn/bQRJva/btrpU1hdr7S/vGFRFk5zfk2NG33aocoFp0/img.png)
![SwiftUI : AsyncImage [Placeholder,Extension,Phase,Transaction] - AsyncImage - AsyncImagePhase (Phase) - 사용 방법 SwiftUI : AsyncImage [Placeholder,Extension,Phase,Transaction] - AsyncImage - AsyncImagePhase (Phase) - 사용 방법](https://blog.kakaocdn.net/dn/cNXgg0/btrpWyyPB6n/XuK9RKGYv0jMv7wPQgqjr0/img.png)
![SwiftUI : AsyncImage [Placeholder,Extension,Phase,Transaction] - AsyncImage - AsyncImagePhase (Phase) - 사용 방법 SwiftUI : AsyncImage [Placeholder,Extension,Phase,Transaction] - AsyncImage - AsyncImagePhase (Phase) - 사용 방법](https://blog.kakaocdn.net/dn/bee8VK/btrpWyr4riS/xUlqvrzE5HIkQYQKAemdD1/img.png)
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 단축키를 사용해 시뮬레이터에서 빌드해야 한다.
![SwiftUI : AsyncImage [Placeholder,Extension,Phase,Transaction] - AsyncImage - Animation / Transaction SwiftUI : AsyncImage [Placeholder,Extension,Phase,Transaction] - AsyncImage - Animation / Transaction](https://blog.kakaocdn.net/dn/dvhZ1k/btrp3Vy6Coy/VpHhaMyeIC2CXMKhYWa7MK/img.gif)
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 |