본문 바로가기
Xcode/IOS

SwiftUI) TOCropViewController와UIViewControllerRepresentable

by 후르륵짭짭 2023. 5. 29.
728x90
반응형

맛있게 먹은 감자 고로케

안녕하세요. 후르륵짭짭입니다.

이전 부터 생각한 프로젝트가 있었는데, 마음만 먹고 사실 제대로 작업한 적이 없었습니다.

하지만 이제는 시간도 생겼고 약속도 했기 때문에 만들어보려고 합니다.

그래서 핵심 기능 중에 하나인 이미지 편집 라이브러리인 TOCropViewController와

SwiftUI에서 이것을 사용하는 방법에 대해 작성해보려고 합니다. 

 

** UIViewControllerRepresentable ** 

SwiftUI에서 UIKit ViewController를 적용할 때 필요한 Adapter 같은 역할을 하는 친구 입니다.

UIViewControllerRepresentable에는 아래 두개의 Protocol을 준수 해줘야합니다.

 

첫번째로 makeUIViewController는 UIKit view에 대한 초기 설정을 하는 곳 입니다.

예를들어 아래와 같이 사용할 수 있습니다.

func makeUIViewController(context: Context) -> CropViewController {
        let viewController = CropViewController(croppingStyle: .default, image: selectedImage)
        viewController.aspectRatioPreset = .presetSquare //편집 사이즈
        viewController.rotateButtonsHidden = true // 회전 작동 여부
        viewController.toolbarPosition = .top
        viewController.doneButtonTitle = "Done"
        viewController.cancelButtonTitle = "Back"
        viewController.doneButtonColor = .blue
        viewController.cancelButtonColor = .red
        viewController.delegate = context.coordinator
        return viewController
    }

그리고 context는 UIViewControllerRepresentableContext라는 Struct를 가지고 있습니다.

그리고 여기에 coordinator라는 것이 존재하는데, 이는 View에 특정 기능을 넣어주기 위한 객체를 의미한다.

func makeCoordinator() -> ImageCropCoordinator {
        ImageCropCoordinator(parent: self)
}

class ImageCropCoordinator : NSObject , CropViewControllerDelegate{

        var parent : CropViewControllerRepresentable

        init(parent: CropViewControllerRepresentable) {
            self.parent = parent
        }

        func cropViewController(_ cropViewController: CropViewController, didFinishCancelled cancelled: Bool) {
            self.parent.dismiss()
        }

        func cropViewController(_ cropViewController: CropViewController, didCropToImage image: UIImage, withRect cropRect: CGRect, angle: Int) {
            self.parent.croppedImage = image
            self.parent.dismiss()
        }

        func cropViewController(_ cropViewController: CropViewController, didCropToCircularImage image: UIImage, withRect cropRect: CGRect, angle: Int) {
            self.parent.croppedImage = image
            self.parent.dismiss()
        }
    }

위와 같이 makeCoordinator에 반환 값을 임의로 만든 객체를 넣어준다.

그리고 해당 객체에 Delegate를 추가할 수도 있고 여러가지 기능을 할 수 있게 된다.

func makeUIViewController(context: Context) -> CropViewController {
        let viewController = CropViewController(croppingStyle: .default, image: selectedImage)
        ,,, 생략 ,,,
        viewController.delegate = context.coordinator
        return viewController
    }

이렇게 Delegate를 넣어준다. 그러면  ImageCropCoordinator에서 해당 역할을 수행한다.

 

그리고 마지막으로 updateUIViewController 라는 것이 존재하는데, 이것은 View의 상태값이 변경 될 때 마다 호출이 된다.

struct CropViewControllerRepresentable : UIViewControllerRepresentable {

    let selectedImage : UIImage
    @Binding var croppedImage : UIImage?

    @Environment(\.dismiss) private var dismiss

    ,,, 생략 ,,,

    //Binding으로 된 State가 변경 될 때 호출 된다.
    func updateUIViewController(_ uiViewController: CropViewController, context: Context) {

    }

    class ImageCropCoordinator : NSObject , CropViewControllerDelegate{

        var parent : CropViewControllerRepresentable

        init(parent: CropViewControllerRepresentable) {
            self.parent = parent
        }

        ,,, 생략 ,,,

        func cropViewController(_ cropViewController: CropViewController, didCropToCircularImage image: UIImage, withRect cropRect: CGRect, angle: Int) {
            self.parent.croppedImage = image
            self.parent.dismiss()
        }
    }

}

따라서 위의 예시를들면 croppedImage가 변경될 때 updateUIViewController가 호출이 된다.

 

** TOCropViewController **

https://github.com/TimOliver/TOCropViewController

 

GitHub - TimOliver/TOCropViewController: A view controller for iOS that allows users to crop portions of UIImage objects

A view controller for iOS that allows users to crop portions of UIImage objects - GitHub - TimOliver/TOCropViewController: A view controller for iOS that allows users to crop portions of UIImage ob...

github.com

정말 단순한 이미지 편집 라이브러리 입니다. 

정말 간단하게 기본적인 이미지 편집기능을 제공하는데, 나름 쫌 쓸만해 보였다.

let viewController = CropViewController(croppingStyle: .default, image: selectedImage)

위 방법으로 ViewController를 생성해준다.  그리고 각종 필요한 것을 설정해주면 된다.

croppingStyle은 기본 사각형과 원 두개 설정이 가능하다.

viewController.aspectRatioPreset = .presetSquare //편집 사이즈
viewController.rotateButtonsHidden = true // 회전 작동 버튼 숨김 여부
viewController.toolbarPosition = .top // 설정 버튼 위치
viewController.doneButtonTitle = "Done" // 완료 버튼 title
viewController.cancelButtonTitle = "Back" // 취소 버튼 title
viewController.doneButtonColor = .blue // 완료 버튼 색
viewController.cancelButtonColor = .red // 취소 버튼 색
viewController.allowedAspectRatios = [.preset16x9, .preset3x2, .preset4x3] //편집 사이즈
viewController.showActivitySheetOnDone = true // 공유하기 여부

제대로 된 값을 확인하기 위해서는 CropViewControllerDelegate 를 사용해야한다.

// 취소 버튼을 눌렀을 경우
func cropViewController(_ cropViewController: CropViewController, didFinishCancelled cancelled: Bool) {
    self.parent.dismiss()
}

// Default(사각형)의 완료 버튼을 눌렀을 경우
func cropViewController(_ cropViewController: CropViewController, didCropToImage image: UIImage, withRect cropRect: CGRect, angle: Int) {
    self.parent.croppedImage = image
    self.parent.dismiss()
}

// circle(원)의 완료 버튼을 눌렀을 경우
func cropViewController(_ cropViewController: CropViewController, didCropToCircularImage image: UIImage, withRect cropRect: CGRect, angle: Int) {
    self.parent.croppedImage = image
    self.parent.dismiss()
}

 

** 참고 사이트  **

https://ios-development.tistory.com/1043

 

[iOS - SwiftUI] 튜토리얼 - 13. SwiftUI에서 UIKit 사용 방법 (UIViewRepresentable, UIViewControllerRepresentable)

SwiftUI에서 UIkit 사용 방법 - UIView UIViewRepresentable 프로토콜을 구현하면 SwiftUI에서 UIView 사용 가능 @available(iOS 13.0, tvOS 13.0, *) @available(macOS, unavailable) @available(watchOS, unavailable) public protocol UIViewRepresen

ios-development.tistory.com

https://velog.io/@j_aion/SwiftUI-UIViewControllerRepresentable

 

[SwiftUI] UIViewControllerRepresentable

Use UIViewControllerRepresentable to convert UIKit controllers to SwiftUI | Advanced Learning UIViewController를 SwiftUI 환경에서 사용할 수 있도록 커스텀 컴포넌트를 구현한다.

velog.io

https://www.youtube.com/watch?v=XPcuAg0Xctw          

 

SwiftUI Gesture : 

https://daesiker.tistory.com/55

 

SwiftUI Gesture

swiftUI에는 다양한 Gesture를 보다 쉽게 구현할 수 있도록 도와준다. Gesture를 감지하는 변수를 GestureState 키워드를 통해 바인딩을 하여 변수가 true일 때만 guesture를 실행하는 식으로 Gesture를 제공하

daesiker.tistory.com

 

Alert : 

https://www.hohyeonmoon.com/blog/swiftui-tutorial-alert/

 

SwiftUI Alert 띄우기 | Hohyeon Moon

SwiftUI에서 Alert 창을 띄우는 법에 대해 알아봅니다

www.hohyeonmoon.com

 

AppDelegate를 SwiftUI에 적용하는 방법 : 

https://medium.com/hcleedev/swift-swiftui-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90-appdelegate-scenedelegate-%EB%A7%8C%EB%93%A4%EA%B8%B0-4fa2d85191e

 

Swift: SwiftUI 프로젝트에 AppDelegate, SceneDelegate 만들기

AppDelegate와 SceneDelegate 만드는 법, 그리고 그 두 파일 없이도 대응하는 법을 알아보자

medium.com

 

728x90
반응형

댓글