Drawing with canvasview

1 답변 글타래를 보이고 있습니다
  • 글쓴이
    • 은지짱
      참가자
      • 글작성 : 13
      • 답글작성 : 7

      Drawing with CanvasView 🎨

      캔버스에 그림을 그려보자 ✍️

      📌 Make CanvasView

      class Canvas: UIView {
      
      override func draw(_ rect: CGRect){
      ...
      }
      
      override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
      ...
      }
      
      override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
      ...
      }
      
      }
      
      override func loadView(){
      self.view = canvas
      }
      
      override func viewDidLoad() {
      super.viewDidLoad()
      canvas.backgroundColor = .white
      }
      
      • loadView 란??

      loadView : viewController.view 를 생성하는 곳이다. (아직 self.view 가 만들어지지 않음)
      viewDidLoad 에 작성한다면 아래와 동일하다.

      override func viewDidLoad(){
      view.addSubview(canvas)
      canvas.frame = view.frame
      }
      

      <br/>

      📌 Line Model

      struct Line {
      let storkeWidth: Float
      let color: UIColor
      var points: [CGPoint]
      }
      
      var lines = [Line]()
      

      Line 구조체는 stokeWidth, color points[] 정보를 가지고 있다.
      각각 정보는 선의 굵기, 색깔, 위치 정보를 나타낸다.

      <br/>

      📌 Draw Line

      1. touchesBegan
      override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
      lines.append(Line.init(storkeWidth: strokeWidth, color: strokeColor, points: []))
      }
      

      touchesBegan 은 첫 터치할 때 호출되는 메소드이다.
      linesline 을 append 해준다. (위치정보 points 는 빈 배열이다.)

      1. touchesMoved
      override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
      guard let point = touches.first?.location(in: nil) else { return }
      
      guard var lastLine = lines.popLast() else { return }
      lastLine.points.append(point)
      lines.append(lastLine)
      
      setNeedsDisplay()
      }
      

      touchesMoved 는 손가락의 움직임을 추적하는 메소드이다.
      point 는 현재 터치 위치 정보를 나타낸다.
      지금 선을 그리고 있는 lastLinepoints 배열에 point 를 append 한다.

      • setNeedsDisplay() 란?

      View 의 컨텐츠가 변하면 이 View 가 변했다는 사실을 시스템에 알려준다.

      1. Draw Line
      override func draw(_ rect: CGRect) {
      
      super.draw(rect)
      
      guard let context = UIGraphicsGetCurrentContext() else
      { return }
      
      lines.forEach { (line) in
      
      ...
      
      for (i,p) in line.points.enumerated() {
      if i==0{ // first index
      context.move(to: p)
      } else {
      context.addLine(to: p)
      }
      }
      context.strokePath()
      }
      }
      

      lines 를 foreach 로 돌며 line 을 그려준다.
      i 는 index, p 는 point 를 의미한다. move()addLine()을 사용해 라인을 그려준다.

      <br/>

      📌 Undo & Clear

      func undo(){
      _ = lines.popLast()
      setNeedsDisplay()
      }
      
      func clear(){
      lines.removeAll()
      setNeedsDisplay()
      }
      

      undo 는 선 한 개를 그리기 취소하고, clear 는 모든 정보를 초기화한다.

      <br/>

      📌 Setting Color & Width

      @objc fileprivate func handleColorChange(button: UIButton){
      canvas.setStrokeColor(color: button.backgroundColor ?? .black)
      }
      
      @objc fileprivate func handleSliderChange(){
      canvas.setStrokeWidth(width: slider.value)
      }
      

      위 메소드를 색상 변경 버튼과 UISlider에 addTarget 시켜준다.

      • fileprivate 이란?

      자체 정의 소스 파일에 대한 엔티티 사용을 제한한다.
      해당 세부 정보가 전체 파일 내에서 사용 될 때 특정 기능의 구현 세부 정보를 숨길 수 있다. (같은 모듈 내에서도 같은 소스 파일 안에서만 사용이 가능하다.)

      fileprivate var strokeColor = UIColor.black
      fileprivate var strokeWidth: Float = 1
      
      func setStrokeWidth(width: Float){
      self.strokeWidth = width
      }
      
      func setStrokeColor(color: UIColor) {
      self.strokeColor = color
      }
      

      전역 변수로 설정해둔 stokeColor, strokeWidth 값을 update 해 준다.

      context.setStrokeColor(line.color.cgColor)
      context.setLineWidth(CGFloat(line.storkeWidth))
      

      draw() 메소드에서 선을 그릴 때 원하는 색상과 굵기를 지정해준다.
      이제 최종 완성 ‼️‼️

      <br/>

      📌 screenshots

    • 야곰
      키 마스터
      • 글작성 : 37
      • 답글작성 : 580

      멋진 튜토리얼이네요! 좋아요!
      아쉬운 점은 맨 마지막 스크린샷 이미지가 안보이네요 ㅠ_ㅠ

      의견 : 이 튜토리얼을 처음 따라하는 사람이라면 메서드를 어디에 작성해야 하는지 모를것 같아요. 맨 위의 코드의 Canvas 클래스의 코드가 닫혀있는데, 그 다음 코드부터 그냥 메서드만 써두니 그 메서드가 Canvas 클래스 안에 작성해야 하는 것인지, 밖에다 해야하는 것인지 잘 모르겠습니다. 저도 처음에 띠용 했네요 ㅎㅎ

      질문 : undo 메서드에서 _ = lines.popLast() 라고 해줬는데 _의 의미는 무엇일까요? 꼭 그렇게 해주지 않고 lines.popLast() 해주면 안될까요?

1 답변 글타래를 보이고 있습니다
  • 답변은 로그인 후 가능합니다.

logo landscape small

사업자번호 : 743-81-02195
통신판매업 신고번호 : 제 2022-충북청주-1278 호
고객센터 : 카카오톡채널 @yagom