티스토리 뷰

Views


UIView의 서브 클래스들을 알아볼 예정입니다.

UI View란  정사각형의 영역입니다.

좌표계를 사용하며 드로잉을 위해 사용됩니다.

터치 이벤트를 처리합니다.

 

계층

계층 구조로 이루어져있습니다.

하나의 상위 View와 여러개의 자식뷰를 가집니다.( 상위뷰는 nil일수도 있습니다. )

superView는 자신이 속한 View를 뜻합니다.

var superview: UIView? // 상위 View
var subviews: [UIView] // 자식 Views

 

계층 관리

주로 XCode Interface Builder를 통하여 뷰 계층을 관리하게 됩니다.

버튼을 추가하거나 스택뷰에 넣거나와 같은 작업들이 수행됩니다.

물론 코드를 통해서도 관리가 가능합니다.

func addSubview(_ view: UIView)// sent to view’s (soon to be) superview
func removeFromSuperview() // sent to the view you want to remove (not its superview)

addSub는 superView가 호출하며, removeFromSuperView는 삭제할 view에서 호출해야합니다.

 

뷰의 최상위 위치

view의 최상위 위치는 Controller의 변수인 var view: UIView 입니다.

이 뷰를 통하여 코드로 모든 서브뷰에 접근이 가능합니다.

물론 Outlet을 통하면 바로 해당 뷰에 접근이 가능합니다.

 

 

UIView의 초기화


SubClass로 관리되면 초기화가 복잡해질수 있으니 가능하면 init 함수를 구현하지 않는게 좋습니다.

기본적으로 제공하는 init 함수는 2가지가 있습니다.

init(frame: CGRect) // initializer if the UIView is created in code
init(coder: NSCoder) // initializer if the UIView comes out of a storyboard

frame를 전달하는 초기화는 코드를 통하여 생성시 호출하는 초기화 함수이며

coder를 전달하는 함수는 스토리보드를 통해 생성시 호출되는 함수입니다.

 

View 구현시 두 초기화 함수 구현이 필요합니다.

func setup() { ... }

override init(frame: CGRect) { // a designated initializer 
      super.init(frame: frame)
      setup() // might have to be before super.init 
}

required init?(coder aDecoder:NSCoder){ //arequired,failableinitializer
      super.init(coder: aDecoder)
      setup()
}

frame을 전달하는 init은 지정된 함수이기 초기화 후 다른 작업을 하기위해선 구현이 필요합니다.

coder를 전달받는 init은 NSCoder 프로토콜을 택하고 있어 구현이 필요합니다.

 

UIView를 초기화하는 다른 방법은 awakeFromNib() 함수를 사용하는 것 입니다.

해당 함수는 인터페이스 빌더 파일에서 나온 뷰에게 호출되는 함수입니다.

코드를 통해 생성(frame을 사용)되는 경우에는 호출되지 않습니다.

 

 

좌표 시스템을 위한 데이터 구조


CGFloat

CG(Core Graphics)은 2D 드로잉을 위한 시스템을 뜻합니다.

드로잉은 부동 소수점 숫자를 좌표로 하는 시스템에서 이뤄지며, CGFloat는 부동 소수점 숫자를 표현합니다.

드로잉을 하는 모든 코드에는 CGFloat가 있기 마련입니다.

 

CGPoint

CGFloat 타입의 x, y 변수를 가지는 구조체입니다.

var point = CGPoint(x: 37.0, y: 55.2)
point.y -= 30
point.x += 20.0

 

CGSize

CGFloat 타입의 width, heigth 변수를 가지는 구조체입니다.

var size = CGSize(width: 100.0, height: 50.0)
size.width += 42.5
size.height += 75

 

CGRect

직사각형을 뜻하며, CGPoint 타입의 origin과 CGSize 타입의 size 변수를 가지는 구조체입니다.

struct CGRect {
   var origin: CGPoint
   var size: CGSize
}

 

 

뷰 좌표 시스템


화면에서 시작 지점

시작 지점(0,0)은 좌상단입니다.

우측으로 갈수록 x 값이 증가하며, 아래로 갈수록 y 값이 증가합니다.

 

좌표계의 단위

좌표계의 단위는 Point를 사용합니다.(Pixel이 아님)

디스플레이에 따라 필셀수의 차이가 큰데 이 처리를 위해 Point를 사용하며

해상도 차이에 따라 1Point는 1~3 픽셀로 표현됩니다.

포인트당 픽셀값은 UIView의 var contentScaleFactor: CGFloat에서 확인 가능합니다.

 

드로잉이 이뤄지는 영역

view의 bound라는 변수영역에서 이루어집니다.( var bounds: CGRect )

현재 쓰고 있는 좌표계의 원점과 사이즈를 나타냅니다.

뷰마다 서로 다른 좌표계를 갖고 있습니다.

 

다른 변수들 

var center: CGPoint // the center of a UIView in its superview’s coordinate system
var frame: CGRect // the rect containing a UIView in its superview’s coordinate system

두 변수는 슈퍼뷰 좌표계 기준으로 계산됩니다.

frame은 Drawing과는 전혀 상관이 없습니다.

frame은 슈퍼뷰에서 어디에 위치하고 있는지를 나타냅니다.(현재 뷰가 아닌 슈퍼뷰의 좌표계 기준)

 

Bound vs Frame


frame과 center의 view의 위치를 변경할 때 사용합니다.

위 두 변수는 Drawing과는 무관합니다.

frame.size와 bound.size는 항상 동일한게 아닙니다.

회전시 frame.size가 더 커질수 있습니다.

frame은 다이아몬드 영역으로 모두 포함해야하기 때문에 더 커집니다.

 

 

뷰 생성


인터페이스 빌더 통한 추가

자신만의 View 클래스를 만든 후 어떻게 적용할까요

일반 View를 인터페이스 빌더를 통해 추가합니다.

View를 드래그&드랍으로 추가합니다.

추가된 View를 선택한 뒤 Identity Inspector에서 class타입을 자신의 클래스로 변경합니다.

UIView가 아닌 자신의 클래스 이름을 입력해 줍니다.

 

코드에서 추가

frame을 사용하는 초기화 함수를 사용합니다.

파리미터가 없다면 GCRect.zero를 사용하게 됩니다.

let newView = UIView(frame: myViewFrame)

let newView = UIView() // (frame will be CGRect.zero)

예시)

라벨이 좌상단 기준 20,20에 그려집니다.

 

커스텀 뷰


언제 UIView의 서브 클래스를 작성할까요?

자신이 원하는 드로잉을 하고 싶을때

자신이 원하는 터치 이벤트를 다룰때

 

드로잉을 어떻게 할 수 있을까요?

UIView를 상속 받고 draw(CGRect) 함수를 override 합니다.

override func draw(_ rect: CGRect)

rect는 최적화를 위한 영역입니다.(Bound의 부분영역)

 

외부에서 draw(CGRect) 함수를 직업 호출해서는 안됩니다!

draw 작업은 iOS 시스템에서 처리하기 때문에 해당 함수를 직접 호출해서는 안됩니다.

Drawing이 필요한 경우에는 아래 함수들을 호출해줍시다.

setNeedsDisplay()
setNeedsDisplay(_ rect: CGRect) // rect is the area that needs to be redrawn

 

draw(CGRect) 함수내에서 그리기

드로잉 컨텍스를 가져와 그리거나 UIBezierPath 클래스를 사용합니다.

 

Core graphic 컨셉

1. UIGraphicsGetCurrentContext() 함수를 통하여 컨텍스트를 가져옵니다.

2. 경로를 생성합니다.(직선, 곡선등)

3. 속성을 설정합니다.(선 색상, 채우기 색상, 선 굵기등)

4. 위 정보를 통하여 선 그리기나 채워넣기 중 하나를 하게됩니다.

 

UIBezierPath

컨텍스트와 거의 동일합니다.

직선이나 곡선, 채우기 동작을 위한 함수를 지원합니다.

 

 

경로 그리기


1. UIBezierPath를 생성합니다.

let path = UIBezierPath()

 

2. 시작 지점을 정하고 선이나 곡선을 추가합니다.

path.move(to: CGPoint(80, 50))
path.addLine(to: CGPoint(140, 150))
path.addLine(to: CGPoint(10, 150))

 

3. 경로를 닫습니다.

path.close()

 

4. 속성을 지정합니다.

UIColor.green.setFill() // note setFill is a method in UIColor, not UIBezierPath
UIColor.red.setStroke()  // note setStroke is a method in UIColor, not UIBezierPath
path.linewidth = 3.0 // linewidth is a property in UIBezierPath, not UIColor

 

5. 채우기 및 선을 그립니다.

path.fill() // fill is a method in UIBezierPath
path.stroke() // stroke method in UIBezierPath

완성 화면

 

Drawing


UIBezierPath를 통하여 일반 도형 추가도 가능합니다.

let roundedRect = UIBezierPath(roundedRect: CGRect, cornerRadius: CGFloat)
let oval = UIBezierPath(ovalIn: CGRect)
... and others

 

드로잉을 UIBezierPath의 경로로 자르기

addClip()

 

Hit 탐지

특정 좌표가 영역에 포함되는지 확인이 가능합니다.

 

func contains(_ point: CGPoint) -> Bool // returns whether the point is inside the path
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함