검색결과 리스트
iPhone에 해당되는 글 8건
- 2013.02.16 [iPhone] 아이폰 앱 디자인 실수: 문맥에 대한 간과
- 2013.01.25 [iPhone] iOS6 회전 지원하기
- 2013.01.23 [iPhone] UIView 애니메이션과 코어 애니메이션(CoreAnimation)
- 2013.01.22 [Mask 레이어 활용] 이미지 일부만 보여주기 (2)
- 2012.11.12 2011년 스마트폰 사용자 통계
- 2011.03.20 Objective-C 훑어보기 (2)
- 2011.03.15 애플리케이션 응답성 향상을 위해 동시성 사용하기
- 2011.02.13 OpenGL ES 사용설정
글
[iPhone] 아이폰 앱 디자인 실수: 문맥에 대한 간과
Smashing Magazine 사이트에 아이폰앱 디자인시 범하는 실수에 대한 글이 있어 번역해보았습니다. 좋은 내용이네요 ^^b
(발번역이지만 이해해 주세요 ^^)
원문: iPhone Apps Design Mistakes : Disregard Of Context by Alex Komarov
아이폰 앱들의 디자인 실수 : 컨텍스트를 간과한다.
- 아이폰은 훨씬 큰 그림의 일부일 뿐이다. 인간과 환경요소들 얼마나 잘 풀어내는냐가 앱의 성공요소를 결정한다.
너무나 자주 아이폰 개발자들은 고객과는 동떨어진 제품을 만들어낸다.
- 정말로 호소력있는 앱을 창조하기 위해서는, 앱의 메커니즘에만 집중하는 행위를 멈춰라. 멀리떨어져서 보아라.
- 사람을 감싸고 있는 복잡한 환경적인 요소들 뿐만 아니라 애플리케이션을 사용하는 사람들을 이해하라.
- 이러한 디자인 과제들의 문맥을 더 잘 이해하기 위해서 우리는 몇몇 수준에서 인간과 환경적인 요소들에 주목할 것이다.
레벨1, 당신은 고객들이 사랑하는 앱을 만들기 위해 여기에 있다.
멀리 떨어져서 보아라
레벨1 - 앱자체
- 많은 개발자들이 그들의 앱을 바라보는 관점이다. 당신의 앱이 어떻게 보여야 하고, 왜 고객들이 그것에 관심을
주목할 것인지에 대한 비전을 가지고 있다. 그러나 제품에만 몰두하여 바라본다면 잘못된 문맥 속에 놓고
잘못된 목적과 잘못된 사용자들을 위해 설계하게 될것이다.
- 이것이 멀리 떨어져서 보아야 하는 이유이다.
레벨2, 한명의 사람이 이 앱을 사용하고 있다.
- 그 사용자는 특정한 목적과 과제를 가지고 있다. : 이 부분에서 가장 두드러지고 가장 무시되는 몇가지에 대해서 알아볼것이다.
- 아이폰에 존재하는 인간적인 요소들. 기본적인 인체공학과 시각적인 한계, 공통적인 디자인 실수에 대해서 이야기 할 것이다.
레벨 3. 그 사람은 특정한 환경속에서 이 앱을 사용하고 있다.
- 뒤로 물러나라. 그러면 이 앱은 복잡한 사회 환경속에 일부라는 것을 보게 될것이다. 앱은 사람들 사이의 커뮤니케이션하고,
사람들이 더 큰 목적을 달성하는 것을 돕는 데에 있어서 상대적으로 적은 역할을 맡고 있다.
- 이곳이 사회적 컴포넌들이 동작하는 장소이다. 네트워킹과 커뮤니티, 소셜 기반의 웹사이트와 같은…
- 애플리케이션들과 많은 다른 것들이 환경과 문맥을 창조하는…그 환경속에서 애플리케이션들은 사용되어질 것이다.
레벨4. 환경은 더 큰 문화의 일부이다.
- 다른 문화들간에 독특한 니즈를 해결하는 당신의 능력이 제품의 성공에 영향을 미칠것이다.
그것을 무시하는 것은 너무 비용이 크며, 만일 앱이 세계적으로 팔릴 것이라면 특히 더 그렇다.
환경은 글로벌 네트워킹의 일부임을 이해하는 것이 중요하다.
- 지역문화 뿐만이 아니라 세계적인 성공을 얻을 앱을 창조하기 위해서는 문화적인 차이, 트렌드, 메타포를 인식해야 한다.
레벨2, 사람의 니즈와 한계를 이해하라.
"두번 측정하고, 한번 잘라라" 는 실제로도 효과적인 전략이다. 아이폰 개발자로서 한걸음 뒤로 물러나 코딩을 시작하기 전에
아래와 같은 질문들에 답할 수 있어야 한다.
- 누가 당신의 애플리케이션들을 사용할 것인가?
- 그 사용자의 기능요구사항은 무엇인가?
- 그 사람의 제한(한계)는 무엇인가?
이 질문에 대한 답들이 당신의 관점을 넓혀주고, 당신 고객의 니즈를 해결하는데 도움을 줄것이다.
모든 인간적인 요소 전문인들은 단지 이것에 전념한다.
기본적인 인체공학
- 아이폰과 관련하여 물리적, 인지적, 인체공하적인 진실들이 몇가지 있다.
1. 우리의 손가락들은 마우스 포인터가 아니다.
- 대다수의 탭가능한 객체들이 너무 작아서 사용하기를 좌절시키는 인터페이스를 사용한다.
- 구글맵앱보다 2배 적은 핀들을 사용해서, 태핑이 매우 어렵다.(iFitness) 손가락이 3개 이상의 핀영역을 차지하기 때문에..
- 결국 영역을 반복해서 태핑하게 되고 랜덤으로 핀이 활성화되어 원치 않는 결과를 보게 된다.
인체공학적인 문제들을 해결하기 위한 몇가지 방법이 있다.
1) 버튼과 다른 탭가능한 객체들을 더크게 만들어라.
2) 더크게 만드는 것이 불가능하다면 버튼 그 자체보다 더 크게 클릭 가능하게 영역을 확장해라
3) 각 화면에서 옵션의 수를 줄이고, 선택의 프로세스를 순차적이게 만들어라.
4) 인터페이스 안에서 다중 터치 제스처를 구현해라.
예를 들자면, 두손가락 줌제스처를 사용한것이 머슬 그룹을 더 쉽게 선택할 수 있게 해줄것이다.
2. 불행하게도 우리는 수퍼 영웅이 아니다.
- 앱 디자이너들은 시각적인 제약사항들에 대해 고려해야 한다. 모바일 폰들은 일반적으로 컴퓨터보다 조명 조건이
좋지 않은 장소에서 사용되어진다.
- 덜컹거리는 버스 기차에서, 햇빛 비추는 거리에서 걸으면서 앱을 사용하는 사람들을 생각해보아라.
기술이 유용하고, 완변하게 실행될 지라도 사람들은 무슨 일이 벌어지는지 알기가 힘들어진다면 앱 사용을 꺼리게 될것이다.
- 여기 몇가지 시각적인 한계를 고려하지 않은 잠재적으로만 유용한 앱이 몇가지 있다.
[너무 어무운 색만을 사용해서 앱을 디자인 하지 말아라.]
TweetDeck
여기 몇가지 실수를 피할수 있는 방법들이 있다.
1) 반드시 필요한 요소들만 선택해라. 그것을 더 크게 만들고, 다른 모든것들은 제거하라.
만일 필요하다면 더 많은 옵션을 위해 추가적인 화면을 만들어라. [화면에 덜 필수적인 아이콘들은 제거하라.]
2) 아이폰에서의 픽셀 화면 크기는 컴퓨터 화면보다 작다는 것을 기억해라.
시뮬레이터에서 보는 스크린샷은 아이폰에서는 실제로 더 작다.
레벨3, 사용자의 환경에 특화된 문제(과업)들을 이해하라.
목적과 환경
- 당신의 앱은 사용자가 더 큰 목적 달성을 돕는데 상대적으로 더 적은 역할을 한다.
- 사람들이 어떤 목적을 가지고 있고 그들이 그것들을 달성하기 위해 필요한 것을 더 잘 이해할 수록,
당신은 그들의 니즈를 더 많이 만족하는 앱을 만들수 있다.
- 모바일폰은 종종 시끄럽고 집중을 저해하는 환경속에서 사용된다.
도시를 통과하는 간단한 산책만 하더라도 시끄러운 요소들이 많다.
- 다음 예제를 보아라. 어떤 목소리 메모앱이 더 역할을 잘 할 것 같은가? (Apple Voice vs iTalk)
애플의 보이스 메모가 더 멋져 보이지만, iTalk가 평균적인 사용자들의 목적과 환경을 더 잘 해결하고 있다.
생각해 보아라. 왜 사람들은 노트를 쓰는 것보다 목소리를 녹음하는 것을 더 선호하는가?
오디오 형식은 단순한 텍스트보다 장점이 거의 없다. 검색을 할수도 없고, 텍스트 만큼 쉽게 수정과 보완을 할수 없다.
대부분의 시나리오에서는 정보를 교환하는 관점에서 텍스트가 훨씬 더 편리한 형식이다.
그렇다면 왜… 더 중요하게는 언제 사람들은 목소리 메모를 사용하는가? 언제 그들이 타이핑 할 수 없는가?
가장 흔한 때는 운전하고 있을 때이다. 운전하면서 타이핑 하는 것이 그렇지 않는 경우보다 사고의 위험이 23배 높다고 한다.
이러한 경우에 어떤 앱이 더 사용하기 쉬운가? 크고 빛나는 마이크와 작은 녹음 버튼을 가진 앱은 누르기 불편하지 않을까?
반면 화면 절반 크기의 녹음 버튼을 가진 것은? 당연히 후자이다.
사용자가 녹음이 활성화 됐다는 것을 확인하게 하는 것도 역시 중요하다. 어떤 인터페이스가 디바이스 상태를 더 잘 알리고 있는가? 당신이 녹음을 완료하고 싶을 때는 어디를 택해야 하는가?
전박적으로 어떤 지다인이 더 잘 동작하는 가에 기초하면, iTalk의 승리이다. 애플 보이스 메모는 친구의 폰을 구경할때는
멋져보이지만 실제환경에서는 유용하지 않다.
모바일 폰들, 네트워킹과 커뮤니티
- 의심의 여지없이 모바일폰은 소셜 도구 중에 하나이다. 머 많은 사람들을 관련시킬수록 더 많은 경험들이 발생한다.
생각해보아라. 오직 하나의 폰만 가지고 있다면, 별로 유용하지 않을 것이다. 유투브, 페이스북, 트위터는 우리들은 사회적인
존재임을 이해하고 만들어진 서비스이다.
- 우리는 공유하기를 원한다. 사회적인 인터렉션을 위탁한 설계가 얼마나 극적으로 모바일 세계를 변화시키는지 상상해보아라.
외견상으로 보이는 정보를 공유하고 획득하는 반복적인 방법들에 사람들은 압도당한다. 그것들에 대처하기 위해서 디자이너들은
애플리케이션을 가능한한 효과적으로 만들기 위해 아이폰 플랫폼을 잘 이해해야 한다.
Bump : 단순히 부딪히는 제스터를 통해 연락처 정보를 교환함.
Mover : 쉽게 정보(사진?)을 전달 할 수 있음.
Loopt : 내 주변에 있는 사용자들을 알 수 있음.
레벨4. 환경은 거대한 문화의 일부이다.
다른 문화간의 독특한 니즈를 해결하는 당신의 능력이 당신 앱의 성공에 영향을 미칠 것이다. 그것들을 무시하는 것은 비용이
너무 크고, 특히 앱을 세계를 대상으로 판매할 경우 더욱 그렇다. 지다인은 지역적인 문제들에 적응되야 한다.
사용성 전문가 제이콥 닐슨은 이렇게 이야기 했다.
"ATM 기 전에는 왜 그렇게 큰 버튼을 가졌는지 이해하지 못했다. 2월의 스톡홀름에서 즉시 이해할 수 있었다.
두꺼운 장갑을 끼고도 누르는 것이 가능하다."
시스템은 사용자의 문화적인 특성에 부합해야 한다. 이것은 공격적인 아이콘을 피하는 것 이상의 의미를 갖는다.
비지니스가 수행되는 방식을 수용하고, 다양한 나라에서 사람들이 소통하는 방식을 이해해야 한다.
결론
훌륭한 앱을 디자인 하는것은 쉬운 일이 아니다.
하지만 사용자의 니즈를 이해하려는 당신은 노력은 보상받을 것이다.
'아이폰' 카테고리의 다른 글
| [iOS] 익스텐션 (Extension) (0) | 2015.08.18 |
|---|---|
| [iPhone] 아이폰앱 디자인 정석(TapWorthy) (1) | 2013.07.07 |
| [iPhone] 아이폰 앱 디자인 실수: 문맥에 대한 간과 (0) | 2013.02.16 |
| [iPhone] iOS6 회전 지원하기 (0) | 2013.01.25 |
| [iPhone] UIView 애니메이션과 코어 애니메이션(CoreAnimation) (0) | 2013.01.23 |
| [Mask 레이어 활용] 이미지 일부만 보여주기 (2) | 2013.01.22 |
설정
트랙백
댓글
글
[iPhone] iOS6 회전 지원하기
iOS6.0 부터 회전을 지원하는 delegate 메소드가 조금 변경되었습니다.
iOS6.0 업데이트 후 회전이 올바로 동작하지 않는 것을 보고 적잖이 당황했었습니다.
관련내용을 찾아보니 의외로 어렵지 않게 6.0에서도 회전에 대응할 수 있었습니다~
그럼 6.0 이상 및 하위버전에서 회전을 올바로 지원하기 위한방법에 대해서 알아봅시다
홈 버튼을 기준으로 왼쪽으로 회전, 오른쪽으로 회전, 거꾸로 뒤집었을 때 등 각 방향을 지칭하게 됩니다!
먼저 기존에는 회전을 지원하기 위해 아래와 같은 스텝을 거쳤습니다.
1. Window에 View 추가
[self.window addSubview:viewController.view]
2. UIViewController 에 지원 회전방향 delegate 구현
// 자동회전 지원하는 방향
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationPortrait ||
interfaceOrientation == UIInterfaceOrientationLandscapeLeft ||
interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
3. UIViewController 에서 회전하기 전/후 호출되는 delegate 구현
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
// 회전하기 전에 호출됩니다.
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
// 회전 후에 호출됩니다.
}
shouldAutorotateToInterfaceOrientation의 UIInterfaceOrentation 파라미터 타입은 다음과 같이
enum 타입 상수로 선언되어 있습니다.
typedef NS_ENUM(NSInteger, UIInterfaceOrientation) {
UIInterfaceOrientationPortrait = UIDeviceOrientationPortrait,
UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown,
UIInterfaceOrientationLandscapeLeft = UIDeviceOrientationLandscapeRight,
UIInterfaceOrientationLandscapeRight = UIDeviceOrientationLandscapeLeft
};
iOS 6.0 에서는 무엇을 바뀌었을까요?
iOS6.0에서는 1번과 2번 스텝이 변경되었습니다.
1. Window에 rootViewController 추가
self.window.rootViewController = viewController;
기존에는 Window의 View를 추가했지만, iOS6.0 부터는 반드시 Window의 rootViewController로 지정해야 합니다.
2. UIViewController 에 지원 회전방향 delegate 구현
// 자동회전 지원 유무
- (BOOL) shouldAutorotate {
return YES;
}
// 지원하는 회전방향
- (NSUInteger)supportedInterfaceOrientations {
return (1 << UIInterfaceOrientationPortrait) | (1 << UIInterfaceOrientationLandscapeLeft) | (1 << UIInterfaceOrientationLandscapeRight);
}
기존에 2가지 역할을 하던 메소드가 자동회전 유무와 회전하는 방향을 반환하는 메소드로 각각 분리되었습니다.
또 지원하는 회전방향의 경우, NSUInterger 반환값으로 변경되었는데 이 값은 지원하는 회전방향의 비트가 셋팅된
비트 플래그 값입니다.
typedef NS_OPTIONS(NSUInteger, UIInterfaceOrientationMask) {
UIInterfaceOrientationMaskPortrait = (1 << UIInterfaceOrientationPortrait),
UIInterfaceOrientationMaskLandscapeLeft = (1 << UIInterfaceOrientationLandscapeLeft),
UIInterfaceOrientationMaskLandscapeRight = (1 << UIInterfaceOrientationLandscapeRight),
UIInterfaceOrientationMaskPortraitUpsideDown = (1 << UIInterfaceOrientationPortraitUpsideDown),
UIInterfaceOrientationMaskLandscape = (UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight),
UIInterfaceOrientationMaskAll = (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft |
UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskPortraitUpsideDown),
UIInterfaceOrientationMaskAllButUpsideDown = (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft |
UIInterfaceOrientationMaskLandscapeRight),
};
1을 UIInterfaceOrentation 상수값 만큼 왼쪽으로 시프트해주면, 해당하는 방향의 비트를 셋팅할 수 있지요.
또 한가지 중요한 사항은, 커스텀 UINavigationController와 UITabBarController를 사용한 경우(상속해서)
이 커스텀 클래스의 회전 지원 delegate 메소드에서는 topViewController의 회전지원 delegate 메소드로
위임해야 한다는 것입니다. 아래와 같이 말이죠!
...
- (BOOL) shouldAutorotate {
return [topViewController shouldAutorotate];
}
...
다음은 iOS6.0 이상 및 미만에서 회전을 올바로 처리하기 위한 코드를 정리한 것입니다.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
...
// iOS6.0 이상
NSString *currentVersion = [[UIDevice currentDevice] systemVersion];
NSLog(@"%@", currentVersion);
if ([currentVersion compare:@"6.0" options:NSNumericSearch] != NSOrderedAscending) {
self.window.rootViewController = self.viewController;
} else {
// 하위버전
[self.window addSubview:self.viewController.view];
}
[self.window makeKeyAndVisible];
return YES;
}
#pragma mark - 회전지원 iOS6.0 이상
// 자동회전 지원유무
- (BOOL) shouldAutorotate {
return YES;
}
// 회전방향 지원유무
- (NSUInteger)supportedInterfaceOrientations {
return (1 << UIInterfaceOrientationPortrait) |
(1 << UIInterfaceOrientationPortraitUpsideDown) |
(1 << UIInterfaceOrientationLandscapeLeft) |
(1 << UIInterfaceOrientationLandscapeRight);
}
#pragma mark - 회전지원 iOS6.0 미만
// 회전방향 지원유무
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft ||
interfaceOrientation == UIInterfaceOrientationLandscapeLeft ||
interfaceOrientation == UIInterfaceOrientationLandscapeRight ||
interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown
);
}
#pragma mark - 회전 델리게이트
// 공통
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
// 회전하기 전에 호출됩니다.
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
// 회전 후에 호출됩니다.
}
소스코드 다운로드
'아이폰' 카테고리의 다른 글
| [iPhone] 아이폰앱 디자인 정석(TapWorthy) (1) | 2013.07.07 |
|---|---|
| [iPhone] 아이폰 앱 디자인 실수: 문맥에 대한 간과 (0) | 2013.02.16 |
| [iPhone] iOS6 회전 지원하기 (0) | 2013.01.25 |
| [iPhone] UIView 애니메이션과 코어 애니메이션(CoreAnimation) (0) | 2013.01.23 |
| [Mask 레이어 활용] 이미지 일부만 보여주기 (2) | 2013.01.22 |
| [번역] 사용자 인터페이스 설계의 원리 (0) | 2012.06.24 |
설정
트랙백
댓글
글
[iPhone] UIView 애니메이션과 코어 애니메이션(CoreAnimation)
아이폰에서는 애니메이션을 쉽게 구현할 수 있는 수단들을 제공한다
UIView의 위치 이동, 크기변경, 회전, 페이드인/아웃 등과 간단한 애니메이션은 UIView 애니메이션을
사용해서 구현할 수 있다. UIView 클래스에 애니메이션을 위한 메서드들이 존재하며,
iOS 4.0 부터는 블럭방식의 애니메이션 메소드를 제공해서 코드단에서 편리하게 구현할 수 있다.
CoreAnimation은 CALayer 단에 적용되며, UIView 애니메이션 효과를 구현할 수 있을 뿐만 아니라
좀더 복잡하고 세밀한 애니메이션 효과를 줄 수 있다. 하지만 UIView 애니메이션보다는 코딩량이 좀더 많고 번거롭다
간략히 UIView 애니메이션과 코어 애니메이션을 사용하는 방법에 대해서 알아보자
다음은 UIView를 사용하여 구현한 푸시 애니메이션(네비게이션 푸시가 아니라, 버튼이 움푹 눌리는 듯한 효과)과
CoreAnimation을 사용하여 구현한 플립 애니메이션(y축을 기준으로 뒤집어 지는 듯한 효과)이다
1. UIView 애니메이션을 사용한 푸시효과
구현방식은 터치가 발생하면 x, y축 스케일(scale)을 0.3초 동안 0.9로 축소하고
다시 0.3 초 동안 1.0으로 되돌아 오는 효과를 적용했다. UI 요소가 눌리는 듯한 효과를 줄 수 있으며, 인터렉티브한
느낌을 줄 수 있어서 자주 사용하는 효과중에 하나이다.
[UIView animateWithDuration:0.3 animations:^(void) {
self.transform = CGAffineTransformMakeScale(0.9, 0.9);
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.3 animations:^(void) {
self.transform = CGAffineTransformIdentity;
}];
}];
animations 블럭에서 속성을 변경하는 코드가 비동기 방식으로 (메인쓰레드에서) 애니메이션되는 방식이다.
위 코드는 가로, 세로 Scale을 각각 0.9로 변환하는 애니메이션을 0.3초 동안 수행하고,
애니메이션이 완료(completion) 하면 원래 스케일로 복원하는 애니메이션을 다시 0.3초 동안 수행한다.
CGAffineTransform 즉 아핀변환은 벡터에서 등장하는 용어로 변환을 행렬을 사용해서 나타낸 것이라는 정도만 알아두자.
2. CoreAnimation을 사용한 플립효과
CoreAnimation 은 UIView가 아닌 CALayer에 적용되며, 애니메이션할 CALayer의 property를 지정하고
애니메이션 상태를 좀더 세밀하게 제어할 수 있는 속성을 제공한다.
플립 애니메이션을 구현하는 동안 주의할 점은 y축을 기준으로 회전을 하면 이미지가 좌우가 뒤집어 지는
현상이 발생한다는 것이다. 레이어를 회전시켰기 때문에 뒤집어 지는 것이다.
이문제는 먼저 90도를 회전 시키고, -90로 뒤집은 상태에서 다시 나머지 회전을 수행하는 방식을
사용하면 해결 할 수 있다.
- (void)flip {
// 90도 회전
CABasicAnimation *rotateY = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
rotateY.beginTime = 0.0;
rotateY.toValue = [NSNumber numberWithFloat:radians(90)];
rotateY.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
rotateY.autoreverses = NO;
rotateY.repeatCount = 1;
rotateY.removedOnCompletion = NO;
rotateY.duration = 0.4;
rotateY.fillMode = kCAFillModeForwards;
// -90도로 뒤집은 상태에서 나머지 회전
CABasicAnimation *rotateY2 = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
rotateY2.beginTime = 0.4;
rotateY2.fromValue = [NSNumber numberWithFloat:radians(-90)];
rotateY2.toValue = [NSNumber numberWithFloat:radians(0)];
rotateY2.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
rotateY2.autoreverses = NO;
rotateY2.repeatCount = 1;
rotateY2.removedOnCompletion = NO;
rotateY2.duration = 0.4;
rotateY2.fillMode = kCAFillModeForwards;
CAAnimationGroup *group = [CAAnimationGroup animation];
group.animations = [NSArray arrayWithObjects:rotateY, rotateY2, nil];
group.duration = 0.8;
group.autoreverses = NO;
group.repeatCount = 1;
group.removedOnCompletion = NO;
group.fillMode = kCAFillModeForwards;
group.delegate = self;
[self.layer addAnimation:group forKey:nil];
}
CAAnimationGroup은 동시에 여러 애니메이션을 복합적으로 적용할 때 사용하며, CABasicAnimation의
beginTime 속성을 사용해서 애니메이션 시작 시점을 조정할 수 있다. 총 0.8초 동안의 시간동안 처음 0.4초 동안
90도 회전하고, 0.4초 후 -90도 뒤집어진 상태에서 0도로 0.4초 동안 회전시켜 마치 카드가 자연스럽게
뒤집어 지는 듯한 플립효과를 구현하였다
거의 대부분의 애니메이션은 UIView 애니메이션으로 구현할 수 있지만
UI/UX에 특화된 좀더 재미나고 멋진 효과를 가진 앱을 개발하고 싶다면 코어 애니메이션 사용을 주저하지 말자!
소스코드
'아이폰' 카테고리의 다른 글
| [iPhone] 아이폰 앱 디자인 실수: 문맥에 대한 간과 (0) | 2013.02.16 |
|---|---|
| [iPhone] iOS6 회전 지원하기 (0) | 2013.01.25 |
| [iPhone] UIView 애니메이션과 코어 애니메이션(CoreAnimation) (0) | 2013.01.23 |
| [Mask 레이어 활용] 이미지 일부만 보여주기 (2) | 2013.01.22 |
| [번역] 사용자 인터페이스 설계의 원리 (0) | 2012.06.24 |
| 수동으로 UI 컨트롤에 이벤트 전달 (0) | 2011.11.13 |
설정
트랙백
댓글
글
[Mask 레이어 활용] 이미지 일부만 보여주기
마스크 레이어를 활용하여 이미지의 일부부만 노출시키는 예제를 작성해 보았다.
핵심은 마스크 레이어를 사용하면 터치 이벤트를 수신할 수 없기 때문에
상위에 터치 이벤트를 수신하여 마스크 레이어 단에 이벤트를 전달해주는 투명뷰를
덮는 것 !
간단한 예제인데 fx의 설리와 크리스탈을 배경 이미지로 사용하니 재미있는 예제가 됐다.
(나도 이제 나이 들었나봐 ㅠㅜ 바라만 봐도 행복하구나 ㅋ)
아래는 예제를 실행한 사진이다.
자! 이제 어떻게 예제를 구현했는지 알아보자!
구현방식을 간단히 그림으로 나타내 보면 아래와 같다.
SBTouchView 를 완전히 투명하게 해서는 안된다. 완전히 투명할 경우에는 터치 이벤트를 수신하지 못하기 때문에
투명도를 0.1로 하는 꼼수를 발휘했다. SBTouchView는 터치 이벤트를 단순히 nextResponder 에게 전달하고,
SBMaskedView가 그 이벤트를 받게되고, 마스크 영역을 이동시킨다.
구현 절차는 아래와 같다.
1. 마스크 레이어 설정
maskLayer = [[CAShapeLayer layer] retain]; maskLayer.backgroundColor = [UIColor whiteColor].CGColor; pathRect = CGRectMake(1, 1, 118, 118); UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:pathRect]; maskLayer.path = path.CGPath; maskLayer.fillColor = [UIColor blackColor].CGColor;
핵심은 레이어의 배경색을 흰색으로 처리하고, 마스킹 시킬 영역(Path)만 검정색으로 칠하는 것입니다.
2. 배경레이어에 마스크 설정
// 배경이미지 (크리스탈, 설리 이미지) CALayer *bgLayer = [CALayer layer]; UIImage *bgImage = [UIImage imageNamed:@"christal.jpeg"]; bgLayer.frame = [self frameForImage:bgImage]; bgLayer.contents = (id)bgImage.CGImage; bgLayer.mask = maskLayer; [self.layer addSublayer:bgLayer];
배경(이미지) 레이어의 mask 속성에 마스크 레이어를 설정합니다.
3. 터치뷰를 설정
// 터치 이벤트를 잡을 투명뷰 SBTouchView *touchView = [[[SBTouchView alloc] initWithFrame:self.bounds] autorelease]; [self addSubview:touchView];
// SBTouchView
@implementation SBTouchView
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.1];
}
return self;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[[self nextResponder] touchesBegan:touches withEvent:event];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
[[self nextResponder] touchesCancelled:touches withEvent:event];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[[self nextResponder] touchesEnded:touches withEvent:event];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[[self nextResponder] touchesMoved:touches withEvent:event];
}
4. 터치 이벤트를 수신하여 마스크 레이어 이동 시키기
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint point = [touch locationInView:self];
if (CGRectContainsPoint(pathRect, point)) {
touchBegan = YES;
touchPoint = point;
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
if (touchBegan) {
UITouch *touch = [touches anyObject];
CGPoint point = [touch locationInView:self];
CGPoint destPoint = CGPointMake(pathRect.origin.x + (point.x - touchPoint.x),
pathRect.origin.y + (point.y - touchPoint.y));
pathRect.origin.x = destPoint.x;
pathRect.origin.y = destPoint.y;
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:pathRect];
maskLayer.path = path.CGPath;
touchPoint = point;
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
touchBegan = NO;
}
터치 영역이 마스크 레이어의 영역일 경우, 마스크 레이어의 위치를 이동시킵니다.
소스 다운받기
이상 마스크 레이어 사용법을 알아보면서 간단한 예제도 만들어 보았다.
아이폰을 하면서 항상 느끼는 거지만...UI 프로그래밍이 생각보다 재밌다는 것!
'아이폰' 카테고리의 다른 글
| [iPhone] iOS6 회전 지원하기 (0) | 2013.01.25 |
|---|---|
| [iPhone] UIView 애니메이션과 코어 애니메이션(CoreAnimation) (0) | 2013.01.23 |
| [Mask 레이어 활용] 이미지 일부만 보여주기 (2) | 2013.01.22 |
| [번역] 사용자 인터페이스 설계의 원리 (0) | 2012.06.24 |
| 수동으로 UI 컨트롤에 이벤트 전달 (0) | 2011.11.13 |
| NSNotification (1) | 2011.04.29 |
설정
트랙백
댓글
글
2011년 스마트폰 사용자 통계

Infographic by- GO-Gulf.com Web Design Company
'앱개발로그' 카테고리의 다른 글
| [Android] 안드로이드앱 개발 도전기 (2) | 2013.03.31 |
|---|---|
| 2011년 스마트폰 사용자 통계 (0) | 2012.11.12 |
| BlackBerry Architecture (0) | 2011.04.26 |
설정
트랙백
댓글
글
Objective-C 훑어보기
Objective-C 언어는 C 언어 기반위에 객체지향적인 요소를 가미한 언어로서, 객체지향 언어의 원류인 Smalltalk 에서
그 개념을 많이 차용했다고 한다. 이 포스팅에서는 언어의 구체적인 설명은 하지않고, 간략히 어떤 언어 요소들이
있는지만 알아보겠다.
1. Objective-C 에서 클래스 정의
#import "SuperClass.h"
@interface NewClass : SuperClass {
int instanceVariable;
}
- method;
- methodWithParameter:param;
@end
@implementation NewClass
- method {
return (nil);
}
- methodWithParameter:param {
return (nil);
}
2. Object Pointers
SpecificClass * specificObject; id anyObject;id 타입은 void * 형 포인터로 어떤 객체 포인터도 할당하거나 할당받을 수 있다.
3. Sending Messages
[object method]; [object methodWithParam:param];
objective-c에서는 메시지를 호출한다고 하기 보단, 객체에게 메세지를 보낸다고 한다.
3. Naming Method
다음과 같은 형식을 따른다.
- valuePrepositionParameter:parameter - objectForKey:key - stringByAppendingString:string; - numberFromString:string;
- (id)objectForKey:(id)aKey; - (NSMenuItem)itemWithTag:(NSInteger)aTag; - (unichar)characterAtIndex:(NSUInteger)index; - (NSString*)stringByAddingPercentEscapeUsingEncoding:(NSStringEncoding)encoding; - (void)runInNewThread; - (void)addAttribute:(NSString*)name value:(id)value range:(NSRange)aRange;
5. Method Selectors
SEL selector = @selector(fontWithFamily:traits:weight:size)
6. Instance Variable
isa 인스턴스 변수
Properties
라는 인스턴스 변수에 대해 @property int tag; @synthesize tag;를 선언되면 컴파일러는
- (int)tag
getter 와 setter를 기술하는 것은 프로그래머의 몫이다. 즉 @synthesize를 통해 자동생성하거나, 프로그래머가 직접 구현해줘야 한다. 그렇지 않으면 컴파일 에러가 발생할 것이다.
Property Attributes
| Attribute | Description |
| readonly | getter 만을 생성한다. readwrite 속성과 상반된다. |
| readwrite | 디폴트 값이며, getter 와 setter 를 모두 생성한다. |
| copy | setter 에서 인자를 인수변수에 저장할 때, 인자의 복사본을 저장한다. 객체 포인터 타입에만 유효한 속성이다. (primitive 타입은 항상 복사되기 때문) 리시버가 센더의 인자값을 변경하지 못하게 할 때 사용한다. |
| assign | 인스턴스 변수에 레퍼런스 카운팅 없이 단순 할당한다. 가비지 컬렉션이 존재하는 환경에서 참조를 유지하고 싶거나, 인자값이 변경불가능할 때 사용한다. |
| retain | assign과 유사하며, 가비지 컬렉션이 없는 Managed memory 환경에서 객체의 참조 카운터를 증가 시킨다. |
| getter=name | 지정한 name 이름으로 getter 를 생성한다. getter와 setter의 표준 패턴을 위반해서 Key-Value Coding 과 같은 기술들이 인식할 수 없게 될수도 있기 때문에 사용에 주의해야한다. |
| setter=name | 지정한 name 이름으로 setter 를 생성한다. |
| nonatomic | 디폴트로 생성된 setter 는 atomic 속성을 갖는다. 락을 사용하여 thread-safe 하지만, 상당한 오버헤드를 수반한다. 쓰레드의 개입이 없을 경우, 명시적으로 nonatomic 으로 선언하여 performance 를 높이는게 좋다. |
7. Class Methods
@interface RandomSequece : NSObject {
long long int seed;
}
+ (NSNumber*)number;
+ (NSNumber*)string;
- (NSNumber*)nextNumber;
- (NSString*)string;
@end
...
NSNumber *n = [RandomSequence number];
NSString *s = [RandomSequence string];
@interface Classy : NSObject {
+ (void)greeting;
+ (NSString*)salutation;
}
@end
@implementation
+ (void)greeting {
NSLog(@"%@, world!", [self salutation]);
}
+ (NSString*)salutation {
NSLog(@"Greetings");
}
@end
@interface Classic : Classy
+ (NSString*)salutation;
@end
+ (NSString*)salutation {
return (@"Hello");
}
@end
...
[Classy greeting]; // Logs "Greetings, world"
[Classic greeting]; // Logs "Hello, world!"
[Classic greeting] 은 Classy Class 객체에 메시지를 보내고, [self salutation]은 해당 Cass 클래스 객체에 메시지를 보낸다.
Class 객체에 메시지를 보낸다.
8. Constructing Objects
생성하는 방법을 클래스 설계자가 결정하도록 한다.
@interface RandomSequence : NSObject {
long long seed;
}
- (id)init;
- (id)initWithSeed:(long long)startingSeed;
@end
@implementation RandomSequence
- (id)init {
self = [super init];
if (self != nil) {
seed = 1;
}
return (self);
}
- (id)initWithSeed:(long long)startingSeed {
self = [super init];
if (self != nil) {
seed = startingSeed;
}
return (self);
}
@end
...
RandomSequence *r1 = [[RandomSequence alloc] init];
RandomSequence *r2 = [[RandomSequence alloc] initWithSeed:-43 ];
RandomSequence * r3 = [RandomSequence new];
그것을 isa 변수에 할당한다. 그리고 인스턴스를 모두 0으로 채운뒤, 참조를 반환한다. 이 시점에서 요청된 객체가 존재하지만
아직 초기화는 되지않았다. init 메시는 객체를 초기화를 담당하며, 이메시지가 반환되면 깨체는 사용할 준비가 된 상태가 된다.
9. Writing an init Method
책임이 있다. self 를 변경하는 것은 자바 프로그래머에게는 이상하지만, Class Cluster를 위해 핵심이 되는 부분이다.
때문에 방어적인 프로그램을 위한 것이다. 모든 잘 작성된 생성자는 위의 4가지 조건을 만족해야 한다
- (void)finalize {
if (file != nil) {
[file close];
file = nil;
}
[super finalize]
}
Inner / Anonymous Classes (내부 클래스와 익명클래스)
'Objective-C' 카테고리의 다른 글
| Objective-C 문자열 조작 메서드 (0) | 2011.04.29 |
|---|---|
| 다중인자를 갖는 PerformSelector 메시지 (0) | 2011.03.23 |
| Protocol 과 Category (0) | 2011.03.22 |
| Objective-C 훑어보기 (2) | 2011.03.20 |
| [Cocoa] Cocoa Design Pattern (0) | 2011.03.20 |
| HMAC-SHA1 구현 (0) | 2011.03.03 |
설정
트랙백
댓글
글
애플리케이션 응답성 향상을 위해 동시성 사용하기
1. 애플리케이션에서의 응답성
아이폰, 아이패드를 포함한 모든 애플리케이션의 사용자 인터페이스에 있어서 응답성은 중요한 요소중에 하나이다.
많은 시간을 소비하는 태스크를 사용자 인터페이스가 동작하는 쓰레드에서 수행하면, 해당 태스크가 종료하기 까지
사용자는 어떠한 인터렉션도 행할 수가 없기 때문이다. 트위터의 글목록을 가져와서 보여주는 앱을 생각해보자.
최신글 목록과 사용자 프로필 이미지를 가져오는 동안, 버벅이 되며 먹통이 되면 누가 이 앱을 사용하겠는가?
이 포스팅에서는 Cocoa Touch에서 지원하는 동시성 향상을 방법에 대해서 알아보겠다.
MacOsX와 iOS에서 지원하는 사용자 인터렉션 응답성을 향상시키기 위한 다음과 같은 동시성 방법들이 있다.
NSThread / NSObject가 지원하는 백그라운드/메인 쓰레드, C기반의 POSIX 쓰레드, 비동기 기반의 메소드, NSOperation /NSOperationQueue 등이 있다. 각각의 추상화 수준(사용 용이성)과 복잡성이 다르다. 추상화 수준이 높은 방법일 수록
하드웨어 의존적인 부분을 감추어주고 쉽게 사용할 수 있어서, 비지니스 로직에 더 집중 할 수 있다. 좀더 세밀한 컨트롤과
뛰어난 성능을 원한다면 C 기반의 동시성 API 를 사용하자.
2. NSOperation / NSOperationQueue
웹에서 사진들의 목록을 받아와 이미지와 함께 사진의 이름을 출력하는 플리커 애플리케이션을 생각해보자.
사진들의 목록을 받아오고, 목록에 해당하는 이미지 각각을 로딩하는데 상당한 시간이 소모될 것이다. 이러한 작업을
아이폰 애플리케이션의 메인쓰레드에서 수행할 경우, 애플리케이션은 상당히 버벅거리게 된다. 백그라운드 쓰레드로
이미지를 가져오는 방법을 선택하더라도 성능의 향상은 있겠지만 그 효과는 미미하다.
하나의 이미지를 가져오는 작업에 하나의 쓰레드를 할당하여 완료되면 이미지를 목록을 추가하는 방식이 자연스러운
애플리케이션이 될 것이지만, 몇 개의 쓰레드를 할당하는 것이 성능의 저하를 가져오지 않고 최적의 성능을 낼 것인지는
하드웨어에 의존적이어서 정확히 알 수가 없다. 아이폰에서 제공하는 비동기 방식의 메소드를 사용하여 해결 할 수 있지만,
좀더 추상화 수준이 높으면서 하드웨어 변경에도 코드의 변경이 거의 없는 NSOperation/NSOperationQueue 를 사용해보자.
NSOperatinoQueue 는 내부적으로 최적의 성능을 낼 수는 쓰레드의 개수를 생성하고 관리해 준다.
NSOperation은 NSObject를 상속하고, 하나의 작업단위를 캡슐화하는 추상클래스이다.
3. NSBlockOperation
NSBlockOperation은 Lisp, Ruby와 같은 언어의 클로져와 유사한 Block 이라는 요소를 사용한다. Block은 마치
데이터 스콥을 공유하는 함수와 유사하며, Block으로 지정한 코드를 캡슐화하여 별도 쓰레드로 동작시킨다.
NSOperation / NSInvocationOperation 과 NSOperationQueue를 사용하는 방법도 훌륭하다. 하지만 NSBlockOperation을
사용하면 동일한 성능의 장접을 갖되, 연관된 코드를 한곳에 집중 시킬수 있는 부수적인 장점이 생긴다.
그러나 아이폰 운영체제의 하위 호환성이 떨어지는 것이 단점이다.
블럭은 사용하는 코드는 아래와 같다.
NSBlockOperation의 blockOperationWithBlock 메시지의 인자로 블럭을 정의하여 인자로 전달하였다.
블럭 ^{} 의 내부에서 긴 시간이 소모되는 코드를 수행하고, 작업이 완료되면 MainThread 에서 GUI를 변경하도록 하고 있다.
블럭 내 코드는 별도의 쓰레드에서 실행되기 때문에 자체적인 릴리지 풀을 생성하여 사용해야한다. 마지막으로 블럭에 정의한
작업을 수행하기 위해 NSOperationQueue(workQueue)에 추가하고 있다.
NSBlockOperation *fetchImageOp = [NSBlockOperationblockOperationWithBlock:^{
NSAutoreleasePool *localPool;
@try {
// Autorelease pool 생성
localPool = [[NSAutoreleasePool alloc] init];
// 시간이 소요되는 작업 수행
[selfperformSelectorOnMainThread:@selector(storeImageForURL:) // 메인쓰레드에서 GUI 변경
withObject:result
waitUntilDone:NO];
}
@catch (NSException * exception) {
NSLog(@"Exception: %@", [exception reason]);
}
@finally {
// Autorelease pool 해제
[localPool release];
}
}];
// NSOperationQueue에 추가
[workQueue addOperation:fetchImageOp];
4. 블럭 선언 및 정의하기
다음과 같이 익명으로 정의되어, 메시지의 파라미터로 전달될 수 있다.
int (^cubeIt)(int);// 블럭변수 선언
cubeIt = ^(int num) { return num * num * num; };// 블럭정의
다음과 같이 익명으로 정의되어, 메시지의 파라미터로 전달될 수 있다.
(returnDataType (^) ( parameterType1, parameterType2, ...))blockName
'아이폰' 카테고리의 다른 글
| 애플 푸시 서비스 (0) | 2011.04.07 |
|---|---|
| Sprite Sheet 제작툴 Zwoptex (0) | 2011.03.16 |
| 애플리케이션 응답성 향상을 위해 동시성 사용하기 (0) | 2011.03.15 |
| OpenGL ES 게임 프레임웍 (0) | 2011.02.14 |
| OpenGL ES 사용 (0) | 2011.02.14 |
| OpenGL ES 사용설정 (0) | 2011.02.13 |
설정
트랙백
댓글
글
OpenGL ES 사용설정
#import <UIKit/UIKit.h>
#import <OpenGLES/EAGL.h>
#import <OpenGLES/ES1/gl.h>
#import <OpenGLES/ES1/glext.h>
@interface EAGLView : UIView {
@private
// 백버퍼의 넓이, 높이
GLint backingWidth;
GLint backingHeight;
EAGLContext *context;
// 렌더버퍼, 프레임버퍼 식별자
GLuint viewRenderbuffer, viewFramebuffer;
// 깊이 버퍼, 사용하지 않으면 0
GLuint depthRenderbuffer;
}
- (void)beginDraw;
- (void)finishDraw;
- (void)setupViewLandscape;
- (void)setupViewPortrait;
+ (Class)layerClass {
return [CAEAGLLayer class];
}
- (id)initWithFrame:(CGRect)rect {
if ((self = [super initWithFrame:rect])) {
// Get the layer
CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
eaglLayer.opaque = YES;
eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
if (!context || ![EAGLContext setCurrentContext:context]) {
[self release];
return nil;
}
self.multipleTouchEnabled = YES;
}
return self;
}
- (void)layoutSubviews
{
[EAGLContext setCurrentContext:context];
[self destroyFramebuffer];
[self createFramebuffer];
[self setupViewLandscape];
}
- (BOOL)createFramebuffer {
// 프레임버퍼와, 렌더버퍼를 위한 식별자 값 얻기 (식별자는 GLuint 형 타입)
glGenFramebuffersOES(1, &viewFramebuffer);
glGenRenderbuffersOES(1, &viewRenderbuffer);
// 파이프라인에 바인딩
glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
// 렌더버퍼 메모리 할당
[context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer];
// 렌더버퍼를 프레임버퍼에 연결
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
// 깊이 버퍼도 사용한다면, 위와 동일한 과정으로 생성후 프레임버퍼에 연결
if (USE_DEPTH_BUFFER) {
glGenRenderbuffersOES(1, &depthRenderbuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, backingWidth, backingHeight);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);
}
if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) {
NSLog(@"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
return NO;
}
return YES;
}
- (void)destroyFramebuffer {
glDeleteFramebuffersOES(1, &viewFramebuffer);
viewFramebuffer = 0;
glDeleteRenderbuffersOES(1, &viewRenderbuffer);
viewRenderbuffer = 0;
if(depthRenderbuffer) {
glDeleteRenderbuffersOES(1, &depthRenderbuffer);
depthRenderbuffer = 0;
}
}
- (void)setupViewLandscape
{
// Sets up matrices and transforms for OpenGL ES
glViewport(0, 0, backingWidth, backingHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glRotatef(-90.0f, 0.0f, 0.0f, 1.0f);
// set up the viewport so that it is analagous to the screen pixels
glOrthof(-backingHeight/2.0, backingHeight/2.0, -backingWidth/2.0, backingWidth/2.0, -1.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
// Clears the view with black
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
}
-(void)perspectiveFovY:(GLfloat)fovY
aspect:(GLfloat)aspect
zNear:(GLfloat)zNear
zFar:(GLfloat)zFar
{
const GLfloat pi = 3.1415926;
// Half of the size of the x and y clipping planes.
// - halfWidth = left, halfWidth = right
// - halfHeight = bottom, halfHeight = top
GLfloat halfWidth, halfHeight;
// Calculate the distance from 0 of the y clipping plane. Basically trig to calculate
// position of clip plane at zNear.
halfHeight = tan( (fovY / 2) / 180 * pi ) * zNear;
// Calculate the distance from 0 of the x clipping plane based on the aspect ratio.
halfWidth = halfHeight * aspect;
// Finally call glFrustum with our calculated values.
glFrustumf( -halfWidth, halfWidth, -halfHeight, halfHeight, zNear, zFar );
}
-(void)beginDraw
{
// Make sure that you are drawing to the current context
[EAGLContext setCurrentContext:context];
glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
// make sure we are in model matrix mode and clear the frame
glMatrixMode(GL_MODELVIEW);
glClear(GL_COLOR_BUFFER_BIT);
// set a clean transform
glLoadIdentity();
}
-(void)finishDraw
{
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
[context presentRenderbuffer:GL_RENDERBUFFER_OES];
}
'아이폰' 카테고리의 다른 글
| Sprite Sheet 제작툴 Zwoptex (0) | 2011.03.16 |
|---|---|
| 애플리케이션 응답성 향상을 위해 동시성 사용하기 (0) | 2011.03.15 |
| OpenGL ES 게임 프레임웍 (0) | 2011.02.14 |
| OpenGL ES 사용 (0) | 2011.02.14 |
| OpenGL ES 사용설정 (0) | 2011.02.13 |
| [iPhone] 로깅 프레임웍 cocoalumberjack (0) | 2010.12.21 |
Rotation.zip