codesquad-members-2024 / swift-drawing

iOS 세번째 프로젝트
0 stars 1 forks source link

KAI - 속성 변경 동작 #3

Closed joho2022 closed 6 months ago

joho2022 commented 6 months ago

🎯주요 작업

📚학습 키워드

탭 제스처 인식기

스크린샷 2024-03-20 오후 10 32 47

UIGestureRecognizer 하위클래스

하위 클래스를 통해 여러 제스처를 인식할 수 있다.

  1. UITapGestureRecognizer : 싱글탭 또는 멀티탭 제스처
  2. UIPinchGestureRecognizer : 핀치(Pinch) 제스처
  3. UIRotationGestureRecognizer : 회전 제스처
  4. UISwipeGestureRecognizer : 스와이프(swipe) 제스처
  5. UIPanGestureRecognizer : 드래그(drag) 제스처
  6. UIScreenEdgePanGestureRecognizer : 화면 가장자리 드래그 제스처
  7. UILongPressGestureRecognizer : 롱 프레스(long-press) 제스처

예시 코드

override func viewDidLoad() {
        super.viewDidLoad()
        let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(viewTapped(_:)))
        view.addGestureRecognizer(tapGestureRecognizer)

        setupView()
}

@objc func viewTapped(_ sender: UITapGestureRecognizer) {
        let location = sender.location(in: view)
        let selectedPoint = Point(x: location.x, y: location.y)
}

iOS의 표준 제스처

  1. Tap : 컨트롤을 활성화하거나 항목을 선택한다.
  2. Drag : 아이템을 좌우 또는 화면을 드래그할 수 있다.
  3. Flick : 빠르게 스크롤하거나 화면을 넘길 수 있다.
  4. Swipe : 이전 화면으로 돌아가거나 테이블 뷰에서 숨겨진 삭제 버튼을 표시한다.
  5. Double tap : 이미지 또는 콘텐츠를 확대하거나 다시 축소한다
  6. Pinch : 이미지를 세밀하게 확대하거나 다시 축소한다.
  7. Touch and hold : 커서 지정을 위한 확대보기 표시, 컬렉션 뷰의 경우 재배치할 수 있는 모드로 진입
  8. Shake : 실행 취소 또는 다시 실행 얼럿을 띄운다.

💻고민과 해결

func contains(_ point: Point) -> Bool {
       let horizontalRange = point.x..<(point.x + size.width)
       let verticalRange = point.y..<(point.y + size.height)

     return horizontalRange.contains(point.x) && verticalRange.contains(point.y)
 }

사각형의 point가 포함되어 있는지를 판단하는 것인데, 계속 true값만 반환함

→ 매개변수의 point로 비교했음, self를 붙여서 해결한다.

스크린샷 2024-03-20 오후 10 14 41

[ 회색배경은 버그를 잘 나타내기 위해 임의로 설정함 ]분명 사각형이 생성되는데 색이 보이질 않음

→ rgb값을 255로 나눠주지 않아서 발생한 버그

→ iOS에서 UIColor를 사용하여 색상을 지정할 때, 색상의 각 RGB 컴포넌트는 0.0에서 1.0 사이의 값을 사용한다.

탭제스처로 location으로 좌표를 반환하여 Plane과 비교하는 고민

DrawingViewController에서 구현할려고 하였으나, main뷰컨트롤러에서 Setting뷰컨트롤러 너비를 뺀 너비안에서 생성하는 것이 더 적합하다고 판단하였다. DrawingViewController 삭제함.

터치가 될 때 사각형 테두리에 선을 표시해서 인지하도록 구현하기

버튼은 세팅뷰컨트롤러에 있고, 사각형 정보는 메인뷰컨트롤러에 있는데 뷰 컨트롤러간에 정보를 공유하는 방법

메인뷰컨트롤러에서 클로저를 통해 사각형 배경색과 투명도를 변경하는 이벤트를 전달한다

세팅뷰컨트롤러의 인스턴스에 접근하여 클로저를 설정하면 된다.

 private func setupOpacityAction() {
        settingsPanelViewController.onOpacityChangeRequested = { [weak self] newOpacity in
            guard let self = self,
                  let selectedRectangleView = self.selectedRectangleView else {
                self?.logger.error("선택된 사각형이 없습니다.")
                return
            }

            let rectangleModel = plane.rectangles.first { $0.uniqueID.hashValue == selectedRectangleView.tag }

            rectangleModel?.setOpacity(newOpacity)

            selectedRectangleView.alpha = CGFloat(newOpacity.rawValue) / 10.0
            logger.info("변경된 투명도는 \(Double(newOpacity.rawValue) / 10.0)")
        }
    }

클로저는 자신이 캡처(capture)한 모든 것에 대한 강한(strong) 참조를 기본으로 가진다. 그래서 [weak self] 구문을 사용하여 클로저가 self를 약하게 참조한다.

이로써, MainViewControllerSettingsPanelViewController 사이에 순환 참조가 발생하는 것을 방지한다.

🤔결과

속성변경 최종결과

📚추가학습

Plane은 struct가 적당하였는가?

사각형을 관리하는 역할이기 때문에 클래스에 비해 변경하는 행위로부터 사각형 데이터를 보호하는 측면에서 더 적합하다고 생각한다.

내가 생각하는 클래스는 접근과 수정이 많이 요구될 때 사용하는 것이기 때문이다.

뷰 요소를 let으로 변수 선언부에 선언하는 것과 init에서 생성하는 것과 어떤 차이가 있을까?

let으로 변수 선언부에 선언하면 접근성과 재사용이 쉽고, 가독성이 좋다고 생각하고,

init으로 생성하면 인스턴스를 생성하는 순간 구성요소가 설정된 상태로 만들어지기 때문에 개발하는 사람은 추가적인 설정없이 바로 사용할 수 있는 장점이 있다고 생각한다.