I am basically trying to recreate the photos app. In doing so, matched geometry effect should be the best way to recreate the animation that is used in the photos app when you click on an image/close it. However, on opening of an image it only does half of the animation. When closing the image the animation is only contained to the lazyvgrid individual image not the whole view. Also the first image of the gallery simply does not animate when closing.
Gallery view is made from a lazyvgrid and for each, full screen view is made of a tabview and for each.
Here is what it looks like:
Main view:
struct ImageSelectorView: View {
@EnvironmentObject var isvm: ImageSelectorViewModel
@Namespace var namespace
@State private var selectedImages: [SelectedImagesModel] = []
@State private var selectedImageID: String = ""
@State private var liveEventID: String = ""
@State var showImageFSV: Bool = false
@State var showPicker: Bool = false
@Binding var liveEvent: [EventModel]
public var pickerConfig: PHPickerConfiguration {
var config = PHPickerConfiguration(photoLibrary: .shared())
config.filter = .any(of: [.images, .livePhotos, .videos])
config.selectionLimit = 10
return config
}
private var gridItemLayout = [GridItem(.flexible()), GridItem(.flexible()), GridItem(.flexible())]
private let viewWidth: CGFloat = UIScreen.main.bounds.width
private let viewHeight: CGFloat = UIScreen.main.bounds.height
private let viewHPadding: CGFloat = 30
init(liveEvent: Binding<[EventModel]>) {
self._liveEvent = liveEvent
}
var body: some View {
ZStack {
Color.theme.background.ignoresSafeArea()
VStack {
ZStack {
ScrollView(.vertical, showsIndicators: true) {
LazyVGrid(columns: self.gridItemLayout, alignment: .center, spacing: 0.5) {
ForEach(self.liveEvent[0].eventImages.indices) { image in
GalleryImage(selectedImageID: self.$selectedImageID, showImageFSV: self.$showImageFSV, image: self.liveEvent[0].eventImages[image], namespace: self.namespace)
}
}
}
if self.showImageFSV {
KFImagesFSV(eventImages: self.$liveEvent[0].eventImages, showImageFSV: self.$showImageFSV, selectedImageID: self.$selectedImageID, namespace: self.namespace)
}
}
}
}
}
}
Gallery Image View:
struct GalleryImage: View {
@Binding var selectedImageID: String
@Binding var showImageFSV: Bool
public var image: EventImage
public var namespace: Namespace.ID
private let viewWidth: CGFloat = UIScreen.main.bounds.width
private let viewHeight: CGFloat = UIScreen.main.bounds.height
var body: some View {
Button {
DispatchQueue.main.async {
withAnimation(.spring()) {
self.selectedImageID = image.id
if self.selectedImageID == image.id {
self.showImageFSV.toggle()
}
}
}
} label: {
KFImage(URL(string: image.url))
.placeholder({
Image("topo")
.resizable()
.aspectRatio(contentMode: .fill)
})
.loadDiskFileSynchronously()
.cacheMemoryOnly()
.fade(duration: 0.2)
.resizable()
.matchedGeometryEffect(id: self.selectedImageID == image.id ? "" : image.id, in: self.namespace)
.aspectRatio(contentMode: .fill)
.frame(width: (self.viewWidth/2.9) - 3, height: (self.viewWidth/2.9) - 3)
.clipped()
}
}
}
Image full screen view (tab view):
struct KFImagesFSV: View {
@Binding var eventImages: [EventImage]
@Binding var showImageFSV: Bool
@Binding var selectedImageID: String
public var namespace: Namespace.ID
private let viewWidth: CGFloat = UIScreen.main.bounds.width
private let viewHeight: CGFloat = UIScreen.main.bounds.height
private let viewHPadding: CGFloat = 30
var body: some View {
ZStack {
TabView(selection: self.$selectedImageID) {
ForEach(self.eventImages.indices) { image in
KFImage(URL(string: self.eventImages[image].url))
.placeholder({
Image("topo")
.resizable()
.aspectRatio(contentMode: .fill)
})
.loadDiskFileSynchronously()
.cacheMemoryOnly()
.fade(duration: 0.2)
.resizable()
.tag(self.eventImages[image].id)
.matchedGeometryEffect(id: self.selectedImageID == self.eventImages[image].id ? self.eventImages[image].id : "", in: self.namespace)
.aspectRatio(contentMode: .fit)
.frame(width: self.viewWidth, height: self.viewHeight)
}
}
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .always))
}
}
}



.animationin yourKFImagesFSV. You have to have it animated both ways. That, I am sure is the reason when you are going back to the grid view, that the animation only runs in the grid view. As to the rest of it, you don't seem to have set up the configuration from the tutorial that handles the transition from the grid view to the hero view. Did you download the linked project? The tutorial kind of ends with that project for you to figure out the rest yourself.