ios: constrain image height in layout (#6732)

* ios: constrain image height in layout

* refactor

* video aspect

---------

Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
This commit is contained in:
Evgeny
2026-03-30 18:00:14 +01:00
committed by GitHub
co-authored by Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
parent 462e47bacd
commit b24d003a83
6 changed files with 20 additions and 10 deletions
@@ -96,12 +96,13 @@ struct CIImageView: View {
if img.imageData == nil {
Image(uiImage: img)
.resizable()
.scaledToFit()
.frame(width: w)
.scaledToFill()
.frame(width: w, height: w * heightRatio(img.size))
.clipped()
} else {
SwiftyGif(image: img)
.frame(width: w, height: w * img.size.height / img.size.width)
.scaledToFit()
SwiftyGif(image: img, contentMode: .scaleAspectFill)
.frame(width: w, height: w * heightRatio(img.size))
.clipped()
}
if !blurred || !showDownloadButton(chatItem.file?.fileStatus) {
loadingIndicator()
@@ -19,7 +19,8 @@ struct CILinkView: View {
if let uiImage = imageFromBase64(linkPreview.image) {
Image(uiImage: uiImage)
.resizable()
.scaledToFit()
.aspectRatio(1 / heightRatio(uiImage.size), contentMode: .fill)
.clipped()
.modifier(PrivacyBlur(blurred: $blurred))
.if(!blurred) { v in
v.simultaneousGesture(TapGesture().onEnded {
@@ -185,7 +185,8 @@ struct CIVideoView: View {
ZStack(alignment: .center) {
let canBePlayed = !chatItem.chatDir.sent || file.fileStatus == CIFileStatus.sndComplete || (file.fileStatus == .sndStored && file.fileProtocol == .local)
VideoPlayerView(player: player, url: url, showControls: false)
.frame(width: w, height: w * preview.size.height / preview.size.width)
.frame(width: w, height: w * heightRatio(preview.size))
.clipped()
.onChange(of: m.stopPreviousRecPlay) { playingUrl in
if playingUrl != url {
player.pause()
@@ -313,8 +314,9 @@ struct CIVideoView: View {
return ZStack(alignment: .topTrailing) {
Image(uiImage: img)
.resizable()
.scaledToFit()
.frame(width: w)
.scaledToFill()
.frame(width: w, height: w * heightRatio(img.size))
.clipped()
.modifier(PrivacyBlur(blurred: $blurred))
if !blurred || !showDownloadButton(chatItem.file?.fileStatus) {
fileStatusIcon()
@@ -29,6 +29,7 @@ struct VideoPlayerView: UIViewRepresentable {
func makeUIView(context: UIViewRepresentableContext<VideoPlayerView>) -> UIView {
let controller = AVPlayerViewController()
controller.showsPlaybackControls = showControls
controller.videoGravity = .resizeAspectFill
if #available(iOS 16.0, *) {
controller.speeds = []
}
+5
View File
@@ -402,6 +402,11 @@ extension UIImage {
}
}
// Max image height/width ratio for chat item display, taller images are cropped
public func heightRatio(_ size: CGSize) -> CGFloat {
size.width > 0 ? min(size.height / size.width, 2.33) : 1
}
public func imageFromBase64(_ base64Encoded: String?) -> UIImage? {
if let base64Encoded {
if let img = imageCache.object(forKey: base64Encoded as NSString) {
@@ -437,7 +437,7 @@ fun PriorityLayout(
) { measureable, constraints ->
// Find important element which should tell what max width other elements can use
// Expecting only one such element. Can be less than one but not more
// Constrain max image height to prevent crashes and scroll issues from images with extreme aspect ratios
// Max image height for chat item display, taller images are cropped
val maxImageHeight = (constraints.maxWidth * 2.33f).toInt().coerceAtMost(constraints.maxHeight)
val imageConstraints = constraints.copy(maxHeight = maxImageHeight)
val imagePlaceable = measureable.firstOrNull { it.layoutId == priorityLayoutId }?.measure(imageConstraints)