CLOSE SEARCH

UIKit Dynamics #3 – UICollisionBehavior

UICollisionBehavior를 사용하면 Dynamic Item 사이의 충돌 효과를 쉽게 구현할 수 있습니다. 복잡한 물리수식을 계산할 필요없이, 충돌 영역과 충돌을 처리할 Dynamic Item만 지정해 주면됩니다.

Collision Items

UICollisionBehavior가 충돌 효과를 적용하는 Dynamic Item들은 반드시 UIDynamicItem 프로토콜을 구현해야 합니다. 이 아이템들은 초기화 시점에 initWithItems: 메소드를 통해 추가되거나, 그 이후에 addItem: 메소드를 통해 추가될 수도 있습니다. removeItem: 메소드를 통해 원하는 아이템을 제거할 수도 있으며, 이 경우 제거된 아이템은 충돌 대상에서 즉시 제외됩니다.

 

Boundary

UIKit Dynamics는 기본적으로 무한대의 영역을 가집니다. 이것은 경계가 없는것과 마찬가지이므로, 실제로 앱에 적용할 때는 화면 영역(또는 필요한 영역)에 맞게 경계를 설정해 주어야 합니다.

경계를 설정하는 가장 쉬운 방법은 UIDynamicAnimator의 ReferenceView를 경계로 설정하는 것입니다. 간단히 translatesReferenceBoundsIntoBoundary 속성의 값을 YES로 설정하기만 하면 됩니다. 하지만 Dynamic Animator를 생성한 방식에 따라서 UICollisionBehavior가 인식하는 경계가 달라지기 때문에 주의해야 합니다. ReferenceView로 생성한 경우에는 해당 뷰의 영역을, Collection View를 사용한 경우에는 Collection View Layout의 영역을 경계로 인식합니다. 그 외의 경우에는 인식할 수 있는 영역이 없기 때문에 속성의 값을 YES로 설정한다고 하더라도 경계가 정상적으로 설정되지는 않습니다.

setTranslatesReferenceBoundsIntoBoundaryWithInsets: 메소드를 사용하면 UICollisionBehavior가 인식하는 경계에 원하는 크기만큼 확대 또는 축소된 영역을 경계로 지정할 수도 있습니다.

앞에서 설명한 두가지 방식은 사각영역을 경계로 지정하지만, UIBezierPath의 형태로 표현가능한 모든 영역을 경계로 지정하거나 두 점사이를 잇는 직선을 경계로 지정할 수도 있습니다. addBoundaryWithIdentifier:forPath: 메소드는 UIBezierPath로 표현된 영역을 경계로 추가하고, addBoundaryWithIdentifier:fromPoint:toPoint: 메소드는 두 점을 잇는 직성을 경계로 지정합니다. 메소드 이름에서도 알 수 있듯이 UICollisionBehavior에는 다수의 경계를 추가할 수 있습니다. 각 메소드의 첫번째 파라미터로 전달되는 문자열은 각 경계를 구분하는 식별자이며, boundaryWithIdentifier: 메소드를 통해 원하는 경계를 언제라도 얻을 수 있습니다. 그리고 removeBoundaryWithIdentifier: 메소드를 통해 경계를 제거하거나, removeAllBoundaries 메소드로 모든 경계를 제거할 수도 있습니다.

 

Collision Mode

UICollisionBehavior에 추가된 Dynamic Item은 기본적으로 서로 충돌하며, 경계가 지정되어 있는 경우에 경계와도 충돌합니다. 충돌 모드는 collisionMode 속성을 통해 변경할 수 있고, 기본값인 UICollisionBehaviorModeEverything 외에  UICollisionBehaviorModeItems와 UICollisionBehaviorModeBoundaries를 사용할 수 있습니다. UICollisionBehaviorModeItems는 아이템 사이의 충돌만을 처리하고, 지정된 경계는 무시합니다. 반대로 UICollisionBehaviorModeBoundaries는 아이템과 경계와의 충돌은 처리하지만, 아이템 사이의 충돌은 무시합니다.

[one_half]

UICollisionBehaviorModeEverything

collisionmode_everything

[/one_half]

[one_half_last]

UICollisionBehaviorModeBoundaries

collisionmode_boundaries

[/one_half_last]

 

UICollisionBehaviorDelegate

UICollisionBehavior는 충돌이 발생할 때마다 자신의 델리게이트에 충돌과 관련된 정보를 알려줍니다. 이 델리게이트는 UICollisionBehaviorDelegate 프로토콜을 구현해야 합니다. 델리게이트를 통해 Dynamic Item끼리 충돌했을 때와 Dynamic Item과 경계가 충돌했을 때 원하는 동작을 추가할 수 있습니다.

 

Sample : Falling Boxes

sample_falling_boxes

 

이 예제는 화면을 터치할 때마다 새로운 박스를 화면에 추가합니다. 박스에는 UIKit Dynamics #2 에서 살펴본 UIGravityBehavior를 적용해서 위에서 아래쪽으로 자연스럽게 떨어지도록 구현하고, UICollisionBehavior로 각 박스가 뷰 경계내에서 서로 충돌하도록 구현하고 있습니다.

Code1은 기본적인 초기화 코드를 보여줍니다. 5번라인은 화면을 터치할 때마다 사각형을 추가하기 위해 Tap Gesture Recognizer를 생성하고 현재 뷰에 추가해줍니다. 9번라인은 최초에 화면에 표시할 3개의 박스를 배열로 선언합니다. 11번~12번 라인은 UIDynamicAnimator와 UIGravityBehavior 객체를 생성합니다. UIGravityBehavior 객체를 생성할 때 앞에서 선언한 배열을 사용해서 박스에 중력효과가 적용되도록 해줍니다. 14번 라인은 가장 중요한 UICollisionBehavior 객체를 생성합니다. UIGravityBehavior 객체와 마찬가지로 3개의 박스에 충돌 효과를 적용하고 있습니다.

15번 라인에서는 translatesReferenceBoundsIntoBoundary 속성을 통해 레퍼런스 뷰의 영역을 충돌 경계로 지정하고 있습니다. 레퍼런스 뷰는 UIDynamicAnimator를 생성할 때 파라미터로 전달한 뷰로 여기에서는 현재 뷰컨트롤러의 뷰입니다. 따라서, UICollisionBehavior의 충돌 경계는 현재 뷰의 영역과 동일하므로, UIGravityBehavior 효과가 적용된 Dynamic Item들은 화면 하단에서 멈추게 되고, 충돌 효과도 이 영역 내에서만 발생합니다. 만약, 충돌 경계가 없다면 UIKit Dynamics #2에서 설명한 것처럼 박스들이 무한정 아래쪽으로 이동할 것입니다.

17~18라인에서는 각 Behavior들을 UIDynamicAnimator에 추가해서 중력&충돌 효과가 바로 적용되도록 하고 있습니다.

Code2는 탭 제스처를 처리하는 핸드러 메소드를 보여줍니다. 이 핸들러에서는 탭이 발생한 위치에 박스가 있는지 확인하고, 박스가 있는 경우 해당 박스를 화면에서 제거하는 메소드를 호출하고, 빈 영역을 탭한 경우에는 새로운 박스를 추가하는 메소드를 호출합니다.

Code3에서는 화면에 새로운 사각형을 추가합니다. 14번 라인까지의 코드는 임의의 크기와 색상을 사용해서 박스를 생성하고 뷰에 추가해주고 있습니다. 여기에서 중요한 코드는 16~17번 라인의 코드입니다. 여기에서는 새로 추가한 박스를 UIGravityBehavior와 UICollisionBehavior에 각각 추가해주고 있습니다. 이렇게 추가된 박스에는 두개의 효과가 즉시 적용되어 애니메이션이 실행됩니다. 이처럼 실행중에 언제라도 Dynamic Item을 UIDynamicBehavior에 추가할 수 있으며, UIDynamicAnimator는 즉시 애니메이션을 수행하게 됩니다.

Code4는 Code3과 반대로 지정된 뷰를 UIGravityBehavior와 UICollisionBehavior에서 제거합니다.



이처럼 현실적인 충돌효과를 손쉽게 구현할 수 있지만, UICollisionBehavior는 다른 UIDynamicBehavior에 비해 비교적 많은 CPU 자원을 소모하므로, 앱의 반응성에 영향을 주지 않도록 신중하게 사용해야 합니다.

Filed under: Apple WWDC 2013, iOS