7.7 C
New York
Thursday, March 27, 2025

ios – Calculate Offset Restrict of masks bounds


Hi all I am making an attempt to set the offset limits in order that the picture through the dragGesture by no means exceeds the outlines of the masks…

Due to the assistance of Benzy Neez I get hold of a scaleOffset worth that I exploit for the picture in order that the unique offset takes under consideration the variations in measurement of the picture however at this level I can now not make the boundaries work..

I am undoubtedly doing one thing very silly fallacious however I am unable to discover the error

I am going to present you the code

@MainActor
protocol PlatformView: View {
    var horizontalSizeClass: UserInterfaceSizeClass? { get }
    var verticalSizeClass: UserInterfaceSizeClass? { get }
    var isCompact: Bool { get }
    var isRegular: Bool { get }
}

extension PlatformView {
    var isCompact: Bool 
    var isRegular: Bool { horizontalSizeClass == .common && verticalSizeClass == .common }
}

public enum Masks {
    case circle, sq., rectangle(aspectRatio: AspectRatio)
    
    var form: AnyShape {
        change self {
        case .circle: return AnyShape(.circle)
        case .sq., .rectangle : return AnyShape(.rect)
        }
    }
    
    func measurement(relativeTo measurement: CGSize) -> CGSize {
        let isLandscape = measurement.width > measurement.top
        let reference = isLandscape ? measurement.top : measurement
            .width

        change self {
        case .circle, .sq. :
            return .init(width: reference, top: reference)
        
        case .rectangle(let aspectRatio):
            return .init(width: reference, top: reference * aspectRatio.ratio)
        }
    }

    public enum AspectRatio {
        case ar4_3, ar16_9
        var ratio: CGFloat {
            change self {
            case .ar4_3: return 4/3
            case .ar16_9: return 16/9
            }
        }
    }
}

@Observable public class CroxioManagaer {
     
    var offset: CGSize = .zero
    var lastOffset: CGSize = .zero
    var photoSize: CGSize = .zero
    var maskSize: CGSize = .zero
    
    func currentOffset(translation: CGSize) -> CGSize  {
        let currentOffset: CGSize = .init(width: translation.width / photoSize.width, top: translation.top / photoSize.top)
        return lastOffset + currentOffset
       
    }
    
    func limitedOffset(translation: CGSize) {
        let ratioX = photoSize.width / maskSize.width
        let ratioY = photoSize.top / maskSize.top
        let maxX = ((maskSize.width - photoSize.width) / 2) / ratioX
        let maxY = ((maskSize.top - photoSize.top) / 2) / ratioY
        let currentOffset = currentOffset(translation: translation)
        let width = max(-maxX, min(maxX, currentOffset.width))
        let top = max(-maxY, min(maxY, currentOffset.top))
        offset = .init(width: width, top: top)
    }
    
    func saveOffset() {
        lastOffset = offset
    }
}

extension UIImage {
    personal func aspectRatio(_ measurement: CGSize = .zero) -> CGFloat {
        return measurement == .zero ? self.measurement.width / self.measurement.top : measurement.width / measurement.top
    }
        
    func adaptPhotoSize(to measurement: CGSize) -> CGSize {
        let photoAspectRatio = aspectRatio()
        let maskAspectRatio = aspectRatio(measurement)
        
        if photoAspectRatio > maskAspectRatio {
            // La foto è più larga rispetto alla maschera: scala per altezza
            let width = measurement.top * photoAspectRatio
            return .init(width: width, top: measurement.top)
        } else {
            // La foto è più alta rispetto alla maschera: scala per larghezza
            let top = measurement.width * photoAspectRatio
            return .init(width: measurement.width, top: top)
        }
    }
}

extension CGSize {
    static func + (lhs: CGSize, rhs: CGSize) -> CGSize {
        .init(width: lhs.width + rhs.width, top: lhs.top + rhs.top)
    }
}

public struct Croxio: PlatformView {
    var selectedPhoto: UIImage
    let prefersShape: Masks
    
    public init(selectedPhoto: UIImage, prefersShape: Masks = .circle) {
        self.selectedPhoto = selectedPhoto
        self.prefersShape = prefersShape
    }
    
    @Setting(.horizontalSizeClass) var horizontalSizeClass
    @Setting(.verticalSizeClass) var verticalSizeClass
    
    @State personal var supervisor = CroxioManagaer()
    
    personal var scaledOffset: CGSize {
        CGSize(
            width: supervisor.offset.width * supervisor.photoSize.width,
            top: supervisor.offset.top * supervisor.photoSize.top
        )
    }
    
    public var physique: some View {
        ZStack {
            Picture(uiImage: selectedPhoto)
                .resizable()
                .scaledToFill()
                .body(supervisor.photoSize)
                .offset(scaledOffset)

            Colour.major.opacity(0.5)
                .masks {
                    Rectangle()
                        .overlay {
                            prefersShape.form
                                .body(supervisor.maskSize)
                                .blendMode(.destinationOut)
                        }
                }
        }
        .onGeometryChange(for: CGSize.self, of: { proxy in
            proxy.measurement
        }, motion: { newValue in
            supervisor.maskSize = prefersShape.measurement(relativeTo: newValue * 0.7)
            supervisor.photoSize = selectedPhoto.adaptPhotoSize(to: supervisor.maskSize)
        })
        .ignoresSafeArea()
        .gesture(
            DragGesture()
                .onChanged({ worth in
                    supervisor.limitedOffset(translation: worth.translation)
                })
                .onEnded({ _ in supervisor.saveOffset() })
        )
    }
}

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles