텍스트를 그리는 경우는 어떨까?
우리는 UIBezierPath로 텍스트를 그리지 않아
텍스트는 폰트로 표현되는 UIBezierPath의 모음일 뿐이야
폰트는 UIBezierPath의 모음으로 된 각각의 문자를 정의해
새겨진 문자 말이야
그러니까 우리는 텍스트를 그리는 높은 수준의 방법이 있는거야
여기 문자열이 있으니까 그려보라고 하는 것처럼 말야
UIBezierPath가 그려지는 높은 수준의 방법이지
너흰 분명 UIBezierPath 수준으로 문자를 표현하고 싶지 않겠지
하지만 대부분은 drawRect로도 텍스트를 직접 그리지 않아
이미 익숙한 UILabel을 사용해서 문자를 그려내지
직사각형이 있으면 여기 놓일거고
이 친구 이마에 Hello라고 적고 싶으면
저기에 ULabel을 얹어놓고 Hello라고 하면 되
하지만 drawRect로 텍스트를 그리고 싶다면 어떨까?
이 안에 텍스트를 넣고 싶지만
FaceView에 UILabel을 하위뷰로 얹고 싶지 않다면?
그럴 땐 NSAttributedString 클래스를 사용하면 되
이런 구조로 생성할 수 있는데 보통은 여기에 텍스트를 넘겨줘
AttributedString이라는 건 String은 String인데
각각의 문자는 어떻게 그릴 지에 대한
속성으로 구성된 Dictionary을 가지고 있어
그 속성이란 건 예를 들면 문자의 색상이나
글꼴 같은 것도 분명 있지
배경 색상 같은 것들이지
모든 문자에 대한 설정값이 담긴 Dictionary를 갖고 있는거야
보통은 같은 색상과 글꼴을 가진 문자가 길게 나열되는 형태이지
그래서 모든 문자에 대해 하나의 Dictionary를 갖는게 보통이지
하지만 이게 AttributedString이 작동하는 기본적인 방식이야
일단 AttributedString을 갖게 되면
문자에 대한 Dictionary를 설정하게 되고
drawRect안에서 그려주면 되는데 이렇게 적으면 되
AttributedString인 text에 drawAtPoint 메소드를 호출하고
포인트(CGPoint)값을 주면
텍스트를 왼쪽 상단이 저 포인트가 되는 지점에 그려낼거야
Hello를 여기에 그려내고 싶으면
Hello가 이것처럼 나타날거야
이 지점이 왼쪽 상단 기준점이 되고 텍스트가 이렇게 보이겠지
이해하겠니?
이게 얼마나 클지도 알아낼 수 있어
이 AttributedString의 size 프로퍼티를 사용하면 되지
이렇게 텍스트를 그릴 수 있어
사실 몇가지 이유에서 NSAttributedString를
사용하기 조금 지저분한 점이 있는데
그건 이게 Objective-C 클래스이기때문에 그런 것일 뿐이야
아직은 스위프트로 그렇게 좋은 성능이 나오지 않고 있어
스위프트에서 사용하는 것을 약간 복잡하게 만드는
주요한 두가지 차이점이 있어
하나는 값이 변할 수 있는 특성이 var와 let으로 할 수 없어
보통은 Array에 뭔가를 추가하고 싶다면
Array 타입의 변수 x를 생성하면 변수 var니까 추가할 수 있어
Array 타입으로 상수 x를 생성하면 추가할 수 없겠지
하지만 NSAttributedString에는 해당되지 않는 이야기야
NSAttributedString를 변수 var로 선언해도 값은 바뀔 수 없어
값을 바꿀 수 있는 방법은
NSMutableAttributedString 이라는 다른 클래스를 써야 해
그래서 AttributedString를 만들고
속성에 대한 설정을 하기 시작했다면
NSMutableAttributedString 을 대신 써야 하는 거야
"some string" 값으로 같은 방식으로 해줄 수 있고
이젠 속성들을 설정하거나 뭐든 해줄 수 있는 거야
이게 좀 스위프트에서 이상한 부분 중 하나야
바꿀 수 있는 버전을 따로 써야 한다는 것이지
그건 그렇고 NSAttributedString은 스위프트 String도 아니고
Objective-C의 NSString도 아니야
별개의 것이야
string과 mutableString이라는 프로퍼티가 있는데
이것들로 String이나 NSString을 돌려줄거야
브리징(연결) 같은 걸 사용해서 말이지
하지만 그것 자체로는 String이 아니야
String 타입을 받는 인자로 넘겨줄 수 없어
NSAttributedString은 아에 다른 거야
스위프트에서 NSAttributedString이 까다로운 두번째 이유는
Range(범위)에 대한 것이야
attribute를 설정하고 싶을거야
이런 식으로 설정하면 되
Dictionary가 있는데 여기에 뭐가 들어갈지 잠시후에 말해줄게
또 문자열에 있는 문자의 범위를 설정하려고 할거야
특정 범위의 문자에만 색상이나 글꼴을 설정해 줄 수 있을테니까
여기 들어가는 범위는 Range가 아니라 NSRange야
NSRange는 Range와는 달라
NSRange안에는 index가 있고
기본적으로 범위를 표현하는 구조체로 되어있어
그 범위는 일정 거리를 두고 시작하지
하지만 이 index들은 Objective-C의 NSString에 있어
NSString과 스위프트의 String에는 어떤 차이가 있지?
전에 말했듯이 스위프트의 String은 완전히 유니코드를 따르지
이모지 같은 것들은 다수의 문자가 될거야
NSString의 문자길이는 String의 문자길이와 다를지도 몰라
스위프트의 String은 수많은 유니코드가 있는 반면
NSString은 유니코드 전부를 반드시 다루지 않을지도 모르거든
그래서 근본이 좀 다른거야
일반적인 텍스트가 있는데 그걸 나타내길 주저한다면
너희가 만든 앱을 전세계에서 사용하길 바랄테니까
하지만 유니코드가 없이 긴 문자로만 된 텍스트가 있다면
이모지 같은게 없다면 말야
그럼 Range나 NSRange가 꽤 비슷할 수 있어
그렇지 않다면 범위(range)가 NSString의 range로 되는지
매우 조심해서 확인할 필요가 있어
가지고 있는 스위프트의 String을 받아서
NSString으로 변환하는 거야
자동으로 브리징해주기 때문에 매우 쉽지
그리곤 NSString을 보면서 얼마나 긴지 어디있는지를 보는거지
내가 사과할게
애플사에서 일한 적이 없기때문에 사실 아무 상관은 없지만
이렇게 돌아가는게 사실이야
언제가는 애플이 스위프트에 친화적인 방법을 내놓을거라 믿어
그건 그렇고 숙제에서 이 부분을 내진 않을거니까
너무 걱정하지 마
여기있는 Dictionary에 넣을 속성들엔 뭐가 있을까?
너희가 기대하는 바대로야
foregroundColor는 텍스트의 색깔을 말하고
strokeWidth는 텍스트를 얼마나 두껍게 그려낼건지야
fontAttributeName은 말 그대로 폰트야
UIFont라는 글꼴을 다루는 클래스가 있지
이런 속성들을 Dictionary에 넣어줄 수 있고
너희가 만든 attributedString의 어떤 문자에든 설정할 수 있어
그건 그렇고 Font(폰트,글꼴)에 대해서 이야기 해보자
Font는 iOS에서 엄청 중요해
iOS를 보고 느끼는데 매우 중요한 역할을 하지
여기 모든 종류의 폰트가 있어
볼드체나 헤딩폰트나 시스템 폰트같은게 보이지
이렇게 폰트가 얼마나 중요하게 쓰이는 지를 보라고
그러니까 폰트는 정말 중요해
좋은 앱을 만들고 싶다면 폰트에 신경을 써야 해
그럼 어떻게 내가 원하는 폰트를 선택하거나 가져올 수 있을까?
폰트를 선택하는데 3가지 방법이 있는데
첫번째 방법은 preferredFont라는 걸 사용하는 거야
preferredFont는 사용자의 컨텐츠를 보여줄 때 사용하는 폰트야
캘린더 앱에서 사용자의 일정 같은 것처럼 사용자의 텍스트로 써
날씨 앱이라면 온도가 되겠지
이런 것들이 사용자의 컨텐츠가 되는 부분이야
대부분은 이걸 스토리보드에서 가져오곤 하는데
Atrributed Inspector로 가서 폰트를 선택하고
우린 지금까지 시스템 폰트(System Font)만 썼었지
시스템 폰트를 쓰는 버튼같은 것만 썼으니까
하지만 컨텐츠로는 거기에서 preferredFont를 고를거야
잠시후 preferredFont 스타일에 어떤 것들이 있는지 알아볼거야
코드로는 UIFont의 static 타입 함수를 쓸건데
preferredFontForTextStyle이라는 함수고
어떤 스타일의 폰트를 원하는지를 묻고 UIFont를 반환할거야
텍스트 스타일(TextStyle)이 뭐냐고?
여덜 아홉개가 있는데
예를 들면 Headline, Body, Footnote
UI가 그 시점에 뭐를 하는지에 따라 적정한 스타일을 선택해야 해
Caption 같은 다른 것들도 있어
가끔 Caption과 Footnote의 차이점으로 고민하게 될 수도 있어
미묘한 차이가 있으니까 둘다 써보고 어떤게 최적인지 봐야겠지
멋진 UI를 만들기위해 다양한 preferredFont를 사용하게 될거야
아름다운 폰트들이야
두번째 폰트 종류로 시스템 폰트(system font)가 있어
systemFontOfSize나 boldsystemFontOfSize가 있는데
계산기에도 사용해 볼 수 있겠지
버튼같은 시스템 요소에 사용되지
시스템 폰트는 이런데 사용되는거야
계산기 앱에서 디스플레이의 폰트는 시스템폰트를 사용해선 안되
디스플레이에 들어갈 텍스트는 사용자의 컨텐츠 같은 것이거든
거기엔 preferredFont를 사용해야겠지만
아직 슬라이드를 다 보여주지 않았으니까 한꺼번에 줄일 수 있어
아무튼 그땐 preferredFont를 쓰는게 더 나을거야
또 가끔은 거기에 다른 폰트를 쓰고 싶을 수도 이겠지
특정한 폰트를 쓰고 싶을 수도 있을테니까
특정한 폰트를 쓰기위한 세번째 방법은
예를 들어 계산기의 디스플레이 텍스트를
LED 부속 같은 모양으로 하고 싶을 수 있지
옛날 스타일의 재밌는 모양의 계산기 있잖아
LED 모양으로 된 디스플레이 말이지
그래서 우린 폰트를 LED 폰트로 만들려는 거야
그럴 땐 UIFont하고 특히 UIFontDescriptor를 잘 봐야 하는데
특정한 폰트 패밀리에서 특정한 폰트를 선택하는 법을 제공하지
예를 들어 LED 폰트 패밀리가 되겠지
정리하면 폰트엔 3가지 방법이 있는거야
preferred과 system 그리고 커스터마이징한 폰트 이렇게 말야
이미지를 그리는 과정을 알아보자
텍스트를 그리기위해 UILabel이 있었던 것처럼
이미지를 그리려면 UIImageView가 필요해
이미지를 넣고 싶다면
예를 들어 이 친구 이마에 이미지를 넣고 싶다면
여기에 UIImage를 두고 내가 넣고 싶은 이미지를 넣어주면 되
내가 만든 페이스뷰의 하위뷰로 넣는 것이지
이렇게 하는 게 여러 방법 중 하나야
하지만 UIImage를 drawRect안에 그려넣고 싶다면
텍스트랑 매우 비슷해
일단 UIImage를 가져올거야
가져오는 방법엔 여러가지가 있는데
가장 많이 쓰는 방식은 파일 이름으로 가져오는 거야
Images.xcassets에 이미지를 넣어 놓고
지금까지 supporting file에 옮겨났던거 기억하지
Images.xcassets 라고 말야
이미지를 거기로 드래그해서 넣고 이름을 준 다음에
UIImage(named: 이미지 이름)라고 하면 UIImage를 가져오지
이미지를 가져오는데 실패할지도 모르니까 이건 옵셔널이야
이미지를 드래그해서 넣는 것을 까먹는다던지 뭐든 말이지
일단 이미지를 가져왔으면
그건 그렇고 다른 방법으로도 UIImage 객체를 생성할 수 있어
파일이나 인터넷에서 가져온 이미지 데이터로도 가능하지
Core Graphics로 이미지를 그려내는 것도 가능해
일단 이미지를 가져왔으면 이렇게 변수 image가 있을거고
텍스트를 한 것과 동일하게 그려줄 수 있어
drawAtPoint는 왼쪽 상단을 기준으로 하고
drawInRect는 이미지를 그리긴 하는데
Rect에 맞춰서 비율을 조정할거야
또 drawAsPatternInRect로 타일을 까는 효과를 줄 수 있어
Rect를 받아서 직사각형 안을 타일 형태로 채울거야
이 코드들이 drawRect에 있을 것들이야
뷰에서 마지막 내용인데
bounds가 바꼈을 때 다시 그려내는 상황을 보자
뷰의 bounds가 바뀌면 이 안에 얼굴은 어떻게 될까?
이 얼굴이 세로 화면에서 이렇게 보인다고 했을 때
기기를 돌리면 뷰의 bounds가 이렇게 가로 화면으로 바뀌겠지
너흰 얼굴이 다시 그려져도 똑같이 보일거라고 생각할지도 몰라
하지만 그렇지 않아
얼굴은 이렇게 보이게 될거야
이렇게 가로로 길게 늘어날거야
왜냐하면 bounds를 바꿨을 때 기본 설정이
다시 그려내지 않기 위해
모든 비트의 크기를 조정하는 걸로 되어 있어
너희가 생각하듯이 퍼포먼스에 관련된 거야
훨씬 간단한 방식이지
비트를 일단 늘려놓고 다시 그려달라고 요청하면 되니까
이런건 UIIView의 contentMode라는 프로퍼티로 고칠 수 있어
contentMode의 값으로 컨텐트를 이동시킬 수 있지
왼쪽, 오른쪽, 위, 아래, 오른쪽 위, 왼쪽 위 등으로 말야
컨텐트를 늘리는 게 아니라 새 bounds의 장소로 이동하는 거야
크기를 조정할 수 도 있는데 기본값은 ScaleToFill이야
영역을 채우기 위해 늘리는 행동 등을 하지
아니면 아예 다시 그려버릴 수도 있겠지 (Redraw)
UIContentMode를 Redraw라고 설정하면
drawRect를 다시 호출할거야
자주 그렇게 하고 싶어질거야
거의 항상 Redraw를 쓰고 싶을지도 모르고
데모에서 한번 써볼거니까 그때 보면 되
'연습 > swift개발' 카테고리의 다른 글
4.6 얼굴앱 - 스토리보드 연결 (0) | 2022.01.20 |
---|---|
4.5 얼굴앱-얼굴형 (0) | 2022.01.20 |
4.3 그림을 그려보자 (0) | 2022.01.20 |
4.2 뷰는 어떻게 만들까 (0) | 2022.01.20 |
4.1 화면의 기본, 뷰를 알아보자 (0) | 2022.01.20 |