154 lines
4.6 KiB
Swift
154 lines
4.6 KiB
Swift
|
|
//
|
||
|
|
// IMImageContainerLogic.swift
|
||
|
|
// Crush
|
||
|
|
//
|
||
|
|
// Created by Leon on 2025/8/22.
|
||
|
|
//
|
||
|
|
|
||
|
|
import UIKit
|
||
|
|
|
||
|
|
/// 设计稿中的常量
|
||
|
|
struct ImageDisplayConstants {
|
||
|
|
var W_MAX: CGFloat
|
||
|
|
var H_MAX: CGFloat
|
||
|
|
var W_MIN: CGFloat
|
||
|
|
var H_MIN: CGFloat
|
||
|
|
var RATIO_MIN: CGFloat
|
||
|
|
var RATIO_MAX: CGFloat
|
||
|
|
|
||
|
|
static let `default` = ImageDisplayConstants(
|
||
|
|
W_MAX: 372,
|
||
|
|
H_MAX: 372,
|
||
|
|
W_MIN: 48,
|
||
|
|
H_MIN: 48,
|
||
|
|
RATIO_MIN: 9.0 / 21.0,
|
||
|
|
RATIO_MAX: 21.0 / 9.0
|
||
|
|
)
|
||
|
|
}
|
||
|
|
|
||
|
|
/// 计算结果
|
||
|
|
struct CalculatedImageSize {
|
||
|
|
var width: CGFloat
|
||
|
|
var height: CGFloat
|
||
|
|
var type: ImageType
|
||
|
|
var ratio: CGFloat
|
||
|
|
}
|
||
|
|
|
||
|
|
/// 图片类型
|
||
|
|
enum ImageType: String {
|
||
|
|
case large
|
||
|
|
case small
|
||
|
|
case tiny
|
||
|
|
}
|
||
|
|
|
||
|
|
/// 工具类
|
||
|
|
class ImageDisplayLogic {
|
||
|
|
|
||
|
|
/// 限制数值范围
|
||
|
|
private static func clamp(_ value: CGFloat, min: CGFloat, max: CGFloat) -> CGFloat {
|
||
|
|
return Swift.min(Swift.max(value, min), max)
|
||
|
|
}
|
||
|
|
|
||
|
|
/// 判断图片类型
|
||
|
|
static func getImageType(originalWidth: CGFloat,
|
||
|
|
originalHeight: CGFloat,
|
||
|
|
constants: ImageDisplayConstants = .default) -> ImageType {
|
||
|
|
let W_MAX = constants.W_MAX
|
||
|
|
let H_MAX = constants.H_MAX
|
||
|
|
let W_MIN = constants.W_MIN
|
||
|
|
let H_MIN = constants.H_MIN
|
||
|
|
|
||
|
|
// A. 大图
|
||
|
|
let isLargeImage = (
|
||
|
|
(originalWidth >= W_MAX && originalHeight > (9.0/21.0) * H_MAX) ||
|
||
|
|
(originalHeight >= H_MAX && originalWidth > (9.0/21.0) * W_MAX)
|
||
|
|
)
|
||
|
|
if isLargeImage { return .large }
|
||
|
|
|
||
|
|
// C. 超小图
|
||
|
|
let isTinyImage = (originalWidth < W_MIN || originalHeight < H_MIN)
|
||
|
|
if isTinyImage { return .tiny }
|
||
|
|
|
||
|
|
// B. 小图
|
||
|
|
return .small
|
||
|
|
}
|
||
|
|
|
||
|
|
/// 计算最终展示比例
|
||
|
|
static func calculateDisplayRatio(originalWidth: CGFloat,
|
||
|
|
originalHeight: CGFloat,
|
||
|
|
imageType: ImageType,
|
||
|
|
constants: ImageDisplayConstants = .default) -> CGFloat {
|
||
|
|
let originalRatio = originalWidth / originalHeight
|
||
|
|
if imageType == .large {
|
||
|
|
return clamp(originalRatio, min: constants.RATIO_MIN, max: constants.RATIO_MAX)
|
||
|
|
} else {
|
||
|
|
return originalRatio
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// 计算最终展示尺寸
|
||
|
|
static func calculateImageDisplaySize(originalWidth: CGFloat,
|
||
|
|
originalHeight: CGFloat,
|
||
|
|
constants: ImageDisplayConstants = .default) -> CalculatedImageSize {
|
||
|
|
let W_MAX = constants.W_MAX
|
||
|
|
let H_MAX = constants.H_MAX
|
||
|
|
let W_MIN = constants.W_MIN
|
||
|
|
let H_MIN = constants.H_MIN
|
||
|
|
|
||
|
|
// 1. 类型
|
||
|
|
let imageType = getImageType(originalWidth: originalWidth, originalHeight: originalHeight, constants: constants)
|
||
|
|
|
||
|
|
// 2. 比例
|
||
|
|
let displayRatio = calculateDisplayRatio(originalWidth: originalWidth, originalHeight: originalHeight, imageType: imageType, constants: constants)
|
||
|
|
|
||
|
|
// 3. 最终尺寸
|
||
|
|
var finalWidth: CGFloat = 0
|
||
|
|
var finalHeight: CGFloat = 0
|
||
|
|
|
||
|
|
switch imageType {
|
||
|
|
case .large:
|
||
|
|
if displayRatio >= 1 {
|
||
|
|
// 宽图
|
||
|
|
finalWidth = W_MAX
|
||
|
|
finalHeight = W_MAX / displayRatio
|
||
|
|
} else {
|
||
|
|
// 高图
|
||
|
|
finalHeight = H_MAX
|
||
|
|
finalWidth = H_MAX * displayRatio
|
||
|
|
}
|
||
|
|
case .small:
|
||
|
|
if displayRatio >= 1 {
|
||
|
|
finalHeight = originalHeight
|
||
|
|
finalWidth = min(originalWidth, W_MAX)
|
||
|
|
} else {
|
||
|
|
finalWidth = originalWidth
|
||
|
|
finalHeight = min(originalHeight, H_MAX)
|
||
|
|
}
|
||
|
|
case .tiny:
|
||
|
|
if displayRatio >= 1 {
|
||
|
|
finalHeight = H_MIN
|
||
|
|
finalWidth = min(H_MIN * displayRatio, W_MAX)
|
||
|
|
} else {
|
||
|
|
finalWidth = W_MIN
|
||
|
|
finalHeight = min(W_MIN / displayRatio, H_MAX)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return CalculatedImageSize(
|
||
|
|
width: round(finalWidth),
|
||
|
|
height: round(finalHeight),
|
||
|
|
type: imageType,
|
||
|
|
ratio: displayRatio
|
||
|
|
)
|
||
|
|
}
|
||
|
|
|
||
|
|
/// 根据容器宽度调整常量
|
||
|
|
static func adjustConstants(for containerWidth: CGFloat) -> ImageDisplayConstants {
|
||
|
|
let maxSize = min(containerWidth * 0.5, 372)
|
||
|
|
var c = ImageDisplayConstants.default
|
||
|
|
c.W_MAX = maxSize
|
||
|
|
c.H_MAX = maxSize
|
||
|
|
return c
|
||
|
|
}
|
||
|
|
}
|