Refactor dynamic image height and fix crashing
This commit is contained in:
@@ -32,16 +32,16 @@ struct ShareSheet: UIViewControllerRepresentable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
enum ImageShape {
|
||||||
|
case square
|
||||||
|
case landscape
|
||||||
|
case portrait
|
||||||
|
case unknown
|
||||||
|
}
|
||||||
|
|
||||||
struct ImageCarousel: View {
|
struct ImageCarousel: View {
|
||||||
var urls: [URL]
|
var urls: [URL]
|
||||||
|
|
||||||
enum ImageShape {
|
|
||||||
case square
|
|
||||||
case landscape
|
|
||||||
case portrait
|
|
||||||
case unknown
|
|
||||||
}
|
|
||||||
|
|
||||||
@State private var open_sheet: Bool = false
|
@State private var open_sheet: Bool = false
|
||||||
@State private var current_url: URL? = nil
|
@State private var current_url: URL? = nil
|
||||||
@@ -64,37 +64,14 @@ struct ImageCarousel: View {
|
|||||||
view.framePreloadCount = 3
|
view.framePreloadCount = 3
|
||||||
}
|
}
|
||||||
.imageModifier({ img in
|
.imageModifier({ img in
|
||||||
// get the fitting scale factor
|
let fill = calculate_image_fill(geo: geo, img: img, maxHeight: maxHeight, minHeight: minHeight)
|
||||||
let shape: ImageShape = {
|
|
||||||
let imageRatio = img.size.width / img.size.height
|
DispatchQueue.main.async {
|
||||||
switch imageRatio {
|
if let filling = fill.filling {
|
||||||
case 1.0: return .square
|
self.filling = filling
|
||||||
case ..<1.0: return .portrait
|
|
||||||
case 1.0...: return .landscape
|
|
||||||
default: return .unknown
|
|
||||||
}
|
}
|
||||||
}()
|
|
||||||
|
self.height = fill.height
|
||||||
let xfactor = geo.size.width / img.size.width
|
|
||||||
let yfactor = maxHeight / img.size.height
|
|
||||||
// calculate scaled image height
|
|
||||||
// set scale factor and constrain images to minimum 150
|
|
||||||
// and animations to scaled factor for dynamic size adjustment
|
|
||||||
switch shape {
|
|
||||||
case .portrait:
|
|
||||||
filling = yfactor <= 1.0
|
|
||||||
let scaled = img.size.height * xfactor
|
|
||||||
height = filling ? maxHeight : max(scaled, minHeight)
|
|
||||||
case .square:
|
|
||||||
filling = yfactor <= 1.0 && xfactor <= 1.0
|
|
||||||
let scaled = img.size.height * xfactor
|
|
||||||
height = filling ? maxHeight : max(scaled, minHeight)
|
|
||||||
case .landscape:
|
|
||||||
let scaled = img.size.height * xfactor
|
|
||||||
filling = scaled > maxHeight || xfactor < 1.0
|
|
||||||
height = img.kf.imageFrameCount != nil ? scaled : filling ? min(maxHeight, scaled) : max(scaled, minHeight)
|
|
||||||
case .unknown:
|
|
||||||
height = max(img.size.height, minHeight)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.aspectRatio(contentMode: filling ? .fill : .fit)
|
.aspectRatio(contentMode: filling ? .fill : .fit)
|
||||||
@@ -117,6 +94,54 @@ struct ImageCarousel: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func determine_image_shape(_ size: CGSize) -> ImageShape {
|
||||||
|
guard size.height > 0 else {
|
||||||
|
return .unknown
|
||||||
|
}
|
||||||
|
let imageRatio = size.width / size.height
|
||||||
|
switch imageRatio {
|
||||||
|
case 1.0: return .square
|
||||||
|
case ..<1.0: return .portrait
|
||||||
|
case 1.0...: return .landscape
|
||||||
|
default: return .unknown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ImageFill {
|
||||||
|
let filling: Bool?
|
||||||
|
let height: CGFloat
|
||||||
|
}
|
||||||
|
|
||||||
|
func calculate_image_fill(geo: GeometryProxy, img: UIImage, maxHeight: CGFloat, minHeight: CGFloat) -> ImageFill {
|
||||||
|
let shape = determine_image_shape(img.size)
|
||||||
|
|
||||||
|
let xfactor = geo.size.width / img.size.width
|
||||||
|
let yfactor = maxHeight / img.size.height
|
||||||
|
// calculate scaled image height
|
||||||
|
// set scale factor and constrain images to minimum 150
|
||||||
|
// and animations to scaled factor for dynamic size adjustment
|
||||||
|
switch shape {
|
||||||
|
case .portrait:
|
||||||
|
let filling = yfactor <= 1.0
|
||||||
|
let scaled = img.size.height * xfactor
|
||||||
|
let height = filling ? maxHeight : max(scaled, minHeight)
|
||||||
|
return ImageFill(filling: filling, height: height)
|
||||||
|
case .square:
|
||||||
|
let filling = yfactor <= 1.0 && xfactor <= 1.0
|
||||||
|
let scaled = img.size.height * xfactor
|
||||||
|
let height = filling ? maxHeight : max(scaled, minHeight)
|
||||||
|
return ImageFill(filling: filling, height: height)
|
||||||
|
case .landscape:
|
||||||
|
let scaled = img.size.height * xfactor
|
||||||
|
let filling = scaled > maxHeight || xfactor < 1.0
|
||||||
|
let height = img.kf.imageFrameCount != nil ? scaled : filling ? min(maxHeight, scaled) : max(scaled, minHeight)
|
||||||
|
return ImageFill(filling: filling, height: height)
|
||||||
|
case .unknown:
|
||||||
|
let height = max(img.size.height, minHeight)
|
||||||
|
return ImageFill(filling: nil, height: height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct ImageCarousel_Previews: PreviewProvider {
|
struct ImageCarousel_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
ImageCarousel(urls: [URL(string: "https://jb55.com/red-me.jpg")!,URL(string: "https://jb55.com/red-me.jpg")!])
|
ImageCarousel(urls: [URL(string: "https://jb55.com/red-me.jpg")!,URL(string: "https://jb55.com/red-me.jpg")!])
|
||||||
|
|||||||
Reference in New Issue
Block a user