연습/swift개발

4.2 뷰는 어떻게 만들까

TimeSave 2022. 1. 20. 21:52

 

좋아, 뷰는 어떻게 만들까?

 

대부분은 뷰를 스토리보드에서 드래그 해오는 방식으로 만들꺼야

 

만약 너희가 너만의 커스텀한 것을 그리는 커스텀 뷰가 있다면

 

오늘 같이 얼굴을 그리는 뷰 말이야

 

얼굴 뷰는 뷰일 것이고 이렇게 생겼을거야

 

눈이 2개 있고 웃는 얼굴이야

 

여기에 두개골도 그리고

 

이런 걸 그리고자 할 때 오브젝트 팔레트에는 얼굴 뷰라는게 없어

 

스토리보드로 드래그해 올 수 없는거지

 

그렇다면 어떻게 스토리보드에 얼굴 뷰를 집어 넣을 수 있을까?

 

답은 일반화된 뷰를 끌어온 다음에

 

일반화된 뷰는 어떤 상속도 받지 않은 UIView야

 

그리고나서 일반화된 뷰를 identity inspector에서 수정할거야

 

이건 다음 강의 데모에서 보여줄건데 이 뷰의 클래스를 바꿔서

 

UIView의 자식 클래스로 만들거야

 

그 자식 클래스에 그림을 그리는 모든 코드를 집어넣을거야

 

얼굴을 그리는 코드 말이야

 

뷰를 코드상에서 생성하는 일을 굉장히 드물어

 

UIView의 생성자를 호출하는 이 방법을 사용하는데

 

coder를 인자로 받는 게 아니라

 

frame을 인자로 받는 생성자를 사용한다는 걸 명심해

 

물론 UIView를 인자 없이도 생성할 수 있어

 

하지만 매우 작은 UIView가 생성이 되겠지

 

따라서 나중에 frame을 지정해줘야 할거야

 

뷰를 코드로 생성하는건 이렇게 하는거야

 

여기에 나는 20, 20, 100, 50짜리 직사각형을 만들었는데

 

(20, 20) 좌표에서 너비 100, 높이 50인 직사각형을 만든 것이지

 

그 아래엔 뷰를 만드는건데 이 뷰는 UILabel이고

 

UILabel은 UIView를 상속받은 하위뷰(자식뷰)야

 

UIButton, UIStackView도 마찬가지야

 

이 모든 것들은 UIView에서 상속을 받은 자식 클래스들이야

 

그래서 UIView의 자식 클래스를

 

frame을 이용한 생성자로 만드는 중이야

 

그리고 여기에 Label의 텍스트까지도 지정해줬어

 

그 다음에 이렇게 적을건데, 뷰는..

 

일단 이 코드는 ViewController 안에 있다고 하자

 

이건 최상위에 있는 뷰에 addSubview(label)을 해주면

 

화면 위에 바로 나타나게 되지

 

밑에 화면에 보이는게 (20, 20)에

 

너비 100 높이 50인 label 직사각형이야

 

이게 다야

 

코드로 뷰를 추가하는 건 매우 간단하지

 

addSubview( ) 면 되니까

 

이제 커스텀 뷰(Custom View)를 공부할 차례야

 

왜 UIView의 자식뷰인 커스텀 뷰를 만드는 걸까?

 

당연하게도 미소짓는 얼굴을 그리기 위해서지

 

따라서 얼굴을 그리려면 너만의 커스텀 뷰가 필요해

 

거기에 집거나 옆으로 미는 모션을 인식하게 해야할 수도 있지

 

그건 다음주에 할거야

 

그래서 얼굴에 그런 것들을 해줄려면 커스텀 뷰가 꼭 필요해

 

오늘은 어떻게 얼굴을 그리는 지에 대해서 알아보자

 

어떻게 그리냐고?

 

매우 쉬워

 

UIView를 상속받은 다음에 drawRect( )라는 메소드 하나만

 

Override(오버라이드)해주면 그릴 수 있어

 

drawRect는 하나의 인자만 받는데 이건 최적화를 위한 인자야

 

이건 시스템이 뷰 어느 부분을 그리게 하고 싶은지를 말해

 

뷰의 전체를 모두 그리길 바랄 수도 있겠지만

 

눈만 그리고 싶을 수도 있지

 

이걸 무시하고 모든 걸 다 그릴 수도 있지

 

그렇게도 할 수 있고

 

아니면 효율적으로 눈만 그리고 싶다면 눈만 그려도 무관해

 

이 인자는 전적으로 최적화를 하기 위한 인자이고

 

원한다면 무시해도 상관없어

 

drawRect 메소드를 절대 호출해서는 안 돼

 

이 메소드를 호출한 코드가 너희 과제물에 있으면

 

내가 직접 가서 손목을 때려주겠어

 

이 메소드는 무슨 상황이든지 예외없이 절대로 호출돼서는 안 돼

 

시스템, 즉 iOS가 drawRect( )를 호출할거거든

 

너희가 이걸 호출하지 않아

 

그렇다면 얼굴이 그려지게 할려면 어떻게 하지?

 

이걸 그리고 싶다면, 예를 들어 눈이 감겨진 걸 그리고 싶다면

 

뷰에 이 setNeedsDisplay() 메소드를 호출하면 돼

 

이 메소드는 시스템에게 이렇게 말해

 

"이 뷰는 다시 그려질 필요가 있어" 라고 말야

 

그럼 뷰는 미래 적절한 시점에 drawRect 를 대신 호출해줄거야

 

왜 이런 식으로 하냐고?

 

잘 생각을 해보면 뷰는 자식 뷰도 있고

 

부모 뷰도 있을 수 있는 환경 안에 있단 말이지

 

뷰끼리 겹쳐지기도 하는 등의 여러가지 일들이 일어나고 있어

 

그런데 너희가 그걸 한꺼번에 실행해놓고

 

그 중 하나의 뷰만 다시 그릴 수는 없는거야

 

그 중에는 투명해서 서로 비치는 뷰도 있을 수 있기 때문에

 

시스템이 이것을 통합적으로 관리해야 해

 

또 성능 문제도 있어

 

눈을 감게 하거나 인상을 쓰거나

 

콧물을 흘리는 것 같은 얼굴에 변화를 줄 수 있겠지

 

이 모든 것들이 한꺼번에 바뀔텐데

 

모든 걸 매번 다시 그리고 싶지는 않을거야

 

하나가 바뀌면 모든 게 바뀔 때까지 기다렸다가

 

한꺼번에 새로운 얼굴을 그리는거지

 

그건 시스템이 결정하는 사안이야

 

이건 setNeedsDisplayInRect( ) 메소드야

 

인자로 받는 직사각형 부분만 그리게 해주는 메소드야

 

따라서 이건 setNeedsDisplay( )의 최적화된 버전인 셈이지

 

예를 들어 눈만 바뀌는 걸 알면 눈 영역만 호출을 해주면 되겠지

 

이게 뷰를 다시 그리는 방법이야

 

drawRect( )는 어떻게 실행할까?

 

drawRect( )가 있는데 이걸 어떻게 실행할까에 대한 문제인데

 

여기에는 2가지 방법이 있어

 

하나는 객체지향이 아닌 C언어 같은 방법이 있어

 

스위프트에서는 전역함수로 처리하는 방식인데

 

이걸 Core Graphics라고 불러

 

또 UIBezierPath 클래스를 사용하는 객체지향 방법이 있지

 

두 방법 모두 밑단에서는 Core Graphics를 사용하기때문에

 

Core Graphics 개념을 조금 설명하고

 

UIBezierPath에 어떻게 적용이 되는지 보게 될거야

 

Core Graphics의 개념은 매우 간단해

 

첫번째로 그릴 수 있는 Context가 필요해

 

이 Context는 화면 위의 그림일 수도 있고

 

drawRect에 필요할 Context가 될거야

 

하지만 다른 Context를 가질 수도 있어

 

프린터를 위해 그리거나

 

화면을 벗어나는 곳에 그릴 때 필요한 Context 이지

 

모두가 그려질 Context이기 때문에 이걸 먼저 해주어야하지

 

만약 C언어와 같은 함수를 사용할거라면

 

drawRect 안에서 UIGraphicsGetCurrentContext( )

 

라는 메소드를 사용하게 될거야

 

drawRect에 알맞는 Context를 가져오기위해서지

 

그리고 두번째 할 일은 경로(path)를 만드는거야

 

이 경로들은 호나, 직선, 직사각형, 원 등으로 되어 있고

 

너희가 만든 경로들을 함께 모아놓으면

 

그게 화면에 그려지는 거야

 

경로를 만들고

 

그 뒤에 이 경로를 그리는 데 필요한 속성들을 설정해줘

 

예를 들어 선 색상이나 텍스트를 작업하고 있다면 폰트나

 

질감을 느끼게 한다면 텍스쳐라든지

 

선의 굵기라던지 선의 끝 마무리 같은 것들이지

 

이런 속성들을 모두 설정해주고 경로를 그어주는거야(stroke)

 

이건 경로가 있는 곳에 선을 그리거나

 

경로로 닫힌 영역에 정해진 색이나 텍스쳐로 채우는 것을 뜻 해

 

이게 iOS에서 화면에 그리는 기본적인 개념이야

 

UIBezierPath 클래스도 모든 걸 같은 방식으로 처리해

 

다만 UIBezierPath는 자동으로 Context을 처리할 수 있어서

 

Context에 대해선 따로 걱정할 필요가 없어

 

UIBezierPath에는 그리는 메소드 여러 개가 있어

 

lineto, arcs 같은 것처럼 말야

 

별개의 함수가 있는게 아니라

 

너가 알고 있는 그 전역 함수들이지

 

UIColor는 선을 긋거나 색을 채울 때 쓰여

 

UIColor 클래스에 대해선 앞으로 더 이야기 할거야

 

stroke( )와 fill( )은 UIBezierPath에서 지원하는 메소드들이지

 

따라서 UIBezierPath는 Core Graphics 내용 모두를

 

하나의 멋진 클래스로 캡슐화한다고 생각하면 되

 

너희가 원하는 것들은 모두 지원하기때문에 매우 유용하지

 

뭐든 그리고 싶다면 UIBezierPath으로 할 수 있어

 

색, 폰트, 텍스트, 이미지 빼고 말야

 

이 4가지는 UIBezierPath에 들어 있지는 않지만

 

나머지 그리는 것과 관련된 것은 모두 들어 있어

 

'연습 > swift개발' 카테고리의 다른 글

4.5 얼굴앱-얼굴형  (0) 2022.01.20
4.4 텍스트를 넣으려면  (0) 2022.01.20
4.3 그림을 그려보자  (0) 2022.01.20
4.1 화면의 기본, 뷰를 알아보자  (0) 2022.01.20
시작  (0) 2022.01.20