Mar 31
alonesiphone animation, ios, iPad, iphone, transform, transition, view, view transition
요즘은 치매끼가 있는지.. 예전에 삽질해서 처리한 것에 대해서 또 반복해서 삽질하고 있고 또 같은 방법으로 해결하고 있네요 -_-; 각설하고 본문으로 들어가면..

Camera+의 경우는 각 UI들이 transition animation을 통해서 타나나거나 사라집니다. 최근에 2.2 업데이트에서도 transition animation이 더 추가된 것에 대해서 TUAW에서 다룰 만큼 ( Camera + 2.2 adds Clarity feature, UI improvements, more , 워낙 유명하고 Top 10에 머물러 있어 그럴 수도 있겠지만).
Transition Animation 중에 하나로 뷰를 나타나게 할 때, 가운데 작은 뷰에 알파를 0.1 정도 준 상태에서, 원래 크기로 만들고 알파도 1.0으로 해주는 (나름 패드 같은데서 보면 좋아보이는) transition을 생각할 수 있을 것입니다.
문제 점 – view frame으로 animation을 처리할 때
[1] 간단하게 생각하면 animation 전에 view frame을 작게 하고 알파도 낮춘 다음에 animation commit에서 frame도 돌려놓고 알파도 돌리면 될 것은데..
sub view들의 크기가 변하지 않는 문제가 생길 것입니다.
[2] 그래서 아래와 같이 base view에 autoresizeSubviews를 YES로 해주고
self.view.autoresizesSubviews = YES;
[3] Sub view들의 autoresizingMask를 처리해주고 시도 해 볼 것입니다.
self.view.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin |UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;
[4] 하지만.. 문제는 float 때문인지.. sub view들의 비율이 맞지가 않습니다. (패드 같은데서는 많이 어긋나는 경우도 있죠)
해결 책
View frame을 이용히지않고 view의 transform을 이용해서 축소했다가 확대하면 코드도 짧고 깔끔하게 처리됩니다.
물론 autoresizeSubviews나 autoresizingMask는 손댈 필요가 없겠죠.
[1] Animation 전에 대상 뷰의 transform을 아래와 같이 축소 시키고
view.transform = CGAffineTransformMakeScale(0.1, 0.1);
[2] Animation에서 다음과 같이 복구를 시켜주면 깔끔하죠
view.transform = CGAffineTransformMakeScale(1.0, 1.0);
Mar 30
alonesiphone apple, ios, iPad, iphone, Mac, Tool, xcode, xcode4, 아이폰
실행을 하면, 항상 아래 쪽의 Debug Area (콘솔창같은)가 올라오고, 좌측의 Navigator가 바뀝니다.
( -_-; 항상 Shift + Cmd + Y로 콘솔 내리기가 짜증나죠)
설정을 찾아보니 아래와 같이 “Behaviors”에서 Run 시의 행동을 설정할 수 있었습니다.
즉, 아래 “Run generates output”에서 “Show navigator”와 “Show Debug Area”의 체크를 풀어 주면 됩니다.

Mar 29
alonesiphone apple, ios, iPad, iphone, NSArray, NSDictionary, NSPropertyListSerialization, 아이폰
NSUserDefaults를 이용해서 NSString 기반으로 앱의 데이터를 저장하는 것은 손쉽지만, NSDictionary나 NSArry 등의 데이터를 저장하기는 불편할 것입니다.
NSPropertyListSerialization을 이용하는 방법을 주로 사용했었는데요, NSDictionary의 writeToFile:automatically과 dictionaryWithContentsOfFile: 을 이용해서 좀 더 직관적으로 하는 것도 좋을 것 같아서 포스팅 해봅니다.
[1] NSDictionary의 writeToFile:automatically과 dictionaryWithContentsOfFile: 이용
저장할 때는 writeToFile:automatically을 불러올 때는 dictionaryWithContentsOfFile: 을 이용하면 될 것입니다.
그리고 NSString의 stringByExpandingTildeInPath을 이용해서 Documents의 path도 쫌 더직관적으로 얻어 오면 다음과 같은 코드가 만들어질 것입니다.
[저장하기]
-(void)saveDic:(NSMutableDictionary*)aDic ForKey:(NSString*)aKey {
if( aDic == nil || aKey == nil ) {
return;
}
NSString* dataPath = [[NSString stringWithFormat:@"~/Documents/%@", aKey] stringByExpandingTildeInPath];
[aDic writeToFile:dataPath atomically:YES];
}
[불러오기]
-(NSMutableDictionary*)loadDicForKey:(NSString*)aKey {
if( aKey == nil ) {
return nil;
}
NSString* dataPath = [[NSString stringWithFormat:@"~/Documents/%@", aKey] stringByExpandingTildeInPath];
return [NSMutableDictionary dictionaryWithContentsOfFile:dataPath];
}
[사용 예]
NSPropertyListSerialization 의 사용에도 마찬가지지만, (실수에 의한) memory leak을 막기 위해서 데이터를 가지고 있는 object는 property로 처리하는 것이 좋은 것 같습니다.
// dictionaryWithContentsOfFile 이용
NSString* testKey = @"testKey";
self.dataDic = [self loadDicForKey:testKey];
if( self.dataDic ) {
NSLog(@"testKey (first): %@", self.dataDic);
}
[self.dataDic setObject:[NSArray arrayWithObjects:@"a", @"b", @"c", nil] forKey:@"abc"];
[self saveDic:self.dataDic ForKey:testKey];
self.dataDic = nil;
self.dataDic = [self loadDicForKey:testKey];
if( self.dataDic ) {
NSLog(@"testKey (second): %@", self.dataDic);
}
[2] NSPropertyListSerialization 이용
아래 코드에 주석으로 표기 했지만, propertyListFromData:mutabilityOption:format:error: 이나 dataFromPropertyList:format:error: 등은 곧 decprecate될 것이라고 하니 대체되는 method를 사용해야할 것입니다.
그리고 , [1]에서도 이야기 했지만, 데이터를 받는 객체는 property로 처리해줘야 memory leak을 깔끔하게 없앨 수 있겠죠.
[저장 및 불러오기]
-(NSMutableDictionary*)restoreDataForKey:(NSString*)aKey {
if( aKey == nil ) {
return nil;
}
NSString *finalPath = nil;
NSData *plistData;
NSError *error;
NSPropertyListFormat format;
// normal
finalPath = [self getFilePathForkey:aKey];
plistData = [NSData dataWithContentsOfFile:finalPath];
NSMutableDictionary* tempDic = nil;
if( plistData ) {
/*
// propertyListFromData will be deprecated soon.
dataDic = [NSPropertyListSerialization propertyListFromData:plistData
mutabilityOption:NSPropertyListMutableContainers
format:&format
errorDescription:&error];
*/
tempDic = [NSPropertyListSerialization propertyListWithData:plistData options:NSPropertyListMutableContainers format:&format error:&error];
}
if(tempDic == nil) {
tempDic = [[[NSMutableDictionary alloc] init] autorelease];
}
return tempDic;
}
-(void)storeData:(NSMutableDictionary*)aDic ForKey:(NSString*)aKey {
if( aDic == nil || aKey == nil ) {
return;
}
NSString *finalPath = nil;
NSData *xmlData;
NSError *error;
// normal
if(aDic != nil ) {
finalPath = [self getFilePathForkey:aKey];
/*
dataFromPropertyList will be deprecated soon.
xmlData = [NSPropertyListSerialization dataFromPropertyList:aDic
format:NSPropertyListXMLFormat_v1_0
errorDescription:&error];
*/
xmlData = [NSPropertyListSerialization dataWithPropertyList:aDic format:NSPropertyListXMLFormat_v1_0 options:0 error:&error];
if(xmlData) {
//NSLog(@"No error creating XML data.");
[xmlData writeToFile:finalPath atomically:YES];
}
else {
NSLog(@"%@", error);
[error release];
}
}
}
[사용 예]
// NSPropertyListSerialization 이용
testKey = @"testKey2";
self.dataDic2 = [self restoreDataForKey:testKey];
if( self.dataDic2 ) {
NSLog(@"testKey2 (first): %@", self.dataDic2);
}
[self.dataDic2 setObject:[NSArray arrayWithObjects:@"aa", @"bb", @"cc", nil] forKey:@"aabbcc"];
[self storeData:self.dataDic2 ForKey:testKey];
self.dataDic2 = nil;
self.dataDic2 = [self restoreDataForKey:testKey];
if( self.dataDic2 ) {
NSLog(@"testKey2 (scond): %@", self.dataDic2);
}
Mar 28
alonesUncategorized apple, camera, fx, image, image processing, ios, iPad, iphone
Camera+ 는 (이 글을 쓰는 순간에도) 미국 유료 전체 순위 5위에 꾸준히 머물러 있습니다.
Camera+는 기능도 기능이지만 UI가 너무 매력적이어서 자주 거론하고 배울려고 하고 있습니다.
글을 본지는 조금 되었는데, 너무 좋아서 소장하고 있다가 포스팅합니다. ^^;;
(특히 iPhone에서는) 개발자와 디자이너가 (또 기획자가) 긴밀하게 개미처럼 소통해야하는지 느끼게 하는 글인 것 같습니다.
(베르나르의 소설 개미에서 개미들은 더듬이를 통해서 생각을 완전 공유한다고 합니다. )
이 글은 Camera+를 개발한 팀에서 FX 효과를 어떻게 만들었는지 9단계에 걸친 자세한 설명과 동영상, 코드 예제까지 아주 친절하게 썼습니다.
과연 저렇게 자신들의 노하우를 공개할 수 있을까? 라는 생각이 들게 합니다. 그만큼 자신감이 있고 또 공유를 통한 더 발전을 꾀하기 위해서겠죠.
아래와 같은 멋진 FX를 만드는 과정입니다 (자세한 것은 원문을 보시고 여기는 간단히 정리만 하겠습니다)

Step 1: Concept
일반 사진 중에서 멋지게 잘 찍은 (또는 오래되어서 그 자체로 멋진 FX가 가미된) 사진을 선택합니다.
Step 2: First draft of the formula
포토샵으로 iPhone의 사진을 이용해서 color, contrast, tone등을 조절하면서 Step1에서 선택한 사진과 유사한 효과를 낼 수 있는 공식을 도출해 봅니다.
Step 3: Testing
공식을 만들고 나면 수백 장의 iPhone 사진으로 테스트를 해봅니다. 그리고 결과가 좋지 않으면 다시 Step 2로 돌아갑니다.
Step 4: In-app testing
코드로 Draft 버전의 FX code를 만들어서 App 내에서 테스트를 해봅니다.
Step 5: Wolfgang creates textures
이 부분에서 저도 좋은 아이디어를 얻었는데요, 포토샷을 이용한 공식 이외에도 이미지 위에 올린 Texture Layer를 만들어 봅니다.
(비디오를 보시면 바로 이해가 가십니다)
Step 6: Finalizing the FX formula in Photoshop
Step5의 texture를 적용하면서 포토샵의 공식을 조정해서 최종 본을 만들어 냅니다.
Step 7: Karl codes magic
FX로 사용할 코드를 만들어 냅니다.
Step 8: Karl optimization
코드 최적화를 통해서 성능 최적화를 합니다.
(이 부분은 사진 관련 앱을 해본 저로써는 정말 동감하는 부분입니다)
Step 9: Ship it!
최종으로 앱에 반영하겠죠. ㅜㅜ 예제 코드도 첨부해주는 Camera+에 감사할 따름이죠.
[후기]
이와 같은 과정은 디자이너 혼자, 개발자 혼자, 또는 같이라도 긴밀한 협업 없이는 힘들 것입니다.
포토샵으로 공식을 만들고, 수백장의 아이폰 사진으로 테스트하고, 코드로 만들고, 또 테스트하고, Texture를 만들고, 또 공식을 보정하고, 또 테스트하고, 코드를 만들고, 최적화하고…
고, 고, 고,….. 그런 긴 과정에서 하나의 멋진 FX를 만들어내고 있습니다.
Camera+를 보면 딱 짚어서 말하기 힘든 UI의 부드러움과 사용의 편리함을 보면, 그들의 이런 노력과 열정은 앱 전반에 있는 것 같습니다.
(e.g. Indicator 하나를 돌릴 때도 indicator가 작아진 상태에서 커지는 애니메이션을 통해서 indicator가 타나난다든지..)
Mar 28
alonesiphone App, camera, ios, iPad, iphone, n device, n screen, 애플
iPhone, iPad, 갤스, 갤탭 등으로 N Screen이 많이 이야기 되어지고 있습니다.
발상의 전환인 앱이 하나 있네요. Color ( http://itunes.apple.com/us/app/color/id427763573?mt=8 ) 입니다.

Color는 최초 앱을 시작하면 자신이 그룹을 하나 만들 수 있고,
위치 기반으로 금방에서 찍은 사진들을 아주 미려한 UI로 함께 보여줍니다.
사진에 댓글도 달 수 있고, 라이크도 보낼 수 있습니다. 무엇 보다도 간단하게 주위의 사진들을 볼 수 있어서 너무 좋네요.
(테스트를 해보는 중에도 주위 사무실에서 사진들이 막 올라오네요
)
UI도 배울게 많은 것 같습니다 (Camera+ UI를 처음 접했을 때의 감동이었습니다)



Ref: http://i.tuaw.com/2011/03/24/dreams-teams-and-the-color-app/
Older Entries