2013 이전/iOS개발

[iOS 개발] UIButton title, image 위치 정리

hagulu 하구루2017.02.25 16:32

UIButton을 사용하다 보면 title, image등을 버튼위에 올려서 사용하게 된다. 

그런데 이들이 깔끔하게 배치되지 않을때가 많다.

UIButton의 titleLabel의 frame을 직접 적용해도 변화가 없을 것이다.
그래서 대부분 포기하고 버튼 위에 따로 View를 올리는 경우가 있는데,
이럴 경우 버튼 state 마다 위에 올린 뷰를 수동으로 바꿔 주어야 한다.
특히, UIControlStateHighlighted 를 처리하려면 소스가 지저분해지고 번거러워 질 수 밖에 없다.  
다행히도 이들을 배치할 수 있는 방법은 존재한다.
일단 image, title의 Alignment를 정해줄수 있는데 아래와 같이 가능하다.
  [btn setContentHorizontalAlignment:UIControlContentHorizontalAlignmentLeft];
    [btn setContentVerticalAlignment:UIControlContentVerticalAlignmentBottom];
각각 가로 세로의 정렬을 관리할수 있다.
해당 메소드는 UIControl에 포함된 메소드로 이를 상속 받은 UI들은 모두 사용할 수 있다.
위와 같이 배치를 하면 어느정도 원하는 모양을 가질 수 있지만, 아직 부족하다고 느낄수 있다.
좀더 세밀한 보정이 필요할때 아래와 같이 가능하다.
    [btn setContentEdgeInsets:UIEdgeInsetsMake(0, 10, 0, 0)];
    [btn setImageEdgeInsets:UIEdgeInsetsMake(0, 10, 0, 0)];
    [btn setTitleEdgeInsets:UIEdgeInsetsMake(0, 10, 0, 0)];
각각 Image와 Title의 EdgInsets을 지정해 줄 수 있는데, EdgeInsets은 각각 top, left, bottm, right 를 나타내고,
이를 통해서 위치 조정이 가능하다.
EdgeInsets의 자세한 내용은 해당 링크를 참조하기 바란다.

그리고 두개를 모두 같이 보정하고 싶을때는, contentEdgeInsets를 조정해 주면 된다.

이를 이용하면 버튼을 휠씬 간편하고 깔끔하게 관리 할 수 있게 된다.
간단하지만, 모르고 넘어가서 고생을 할 수있는 부분이다.
이것 때문에 지저분해진 소스가 있다면 지금 바로 수정해 보기 바란다.


신고

댓글

댓글쓰기 폼

2013 이전/iOS개발

[iPad 개발] PopoverController contentSize 문제

hagulu 하구루2017.02.25 16:32

PopoverController 를 사용하다보면 사이즈 때문에 골머리를 썩을 경우가 많을 것이다.

일단 가장 평범한 방법은 해당 PopoverController에 들어갈 해당 UIViewController에
- (CGSize)contentSizeForViewInPopover {
    return CGSizeMake(320, 480);
}
위 처럼 해당 하는 함수를 override 해주면 리턴하는 사이즈로 PopoverController 사이즈를 조절 해준다.
하지만 여기도 문제점이 하나 있다.
navigationController를 사용할때 push나 pop을 하게 되면 늘어나기는 하지만 줄어 들지는 않는다.
구글링을 통해서 얻게된 방법인데, 일종의 꼼수라고 볼수 있겠다.
- (void) forcePopoverSize 
{
    CGSize currentSetSizeForPopover = self.contentSizeForViewInPopover;
    CGSize fakeMomentarySize = CGSizeMake(currentSetSizeForPopover.width - 1.0f, 
                                          currentSetSizeForPopover.height - 1.0f);
    self.contentSizeForViewInPopover = fakeMomentarySize;
}


- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    [self forcePopoverSize];
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    CGSize currentSetSizeForPopover = self.contentSizeForViewInPopover;
    self.contentSizeForViewInPopover = currentSetSizeForPopover;
}

위 처럼 ViewController에 해당하는 함수에 위 내용을 추가만 해주면 된다.
모두 ViewController 멤버를 사용하는 것이니, 바로 가져다 붙여 써도 잘 적용될것이다.
해당 메소드 이름을 정확히 확인하고 적용 바란다.
처음에 잘못 보고 적용을 해서 삽질을 했엇다. ㅠㅠ

각 viewController에 위사항을 적용하면, 언제 그랫냐는 듯이 pop, push 간에 PopoverController크기가 늘었다 줄었다 한다.

하지만 여기도 문제는 있다.
ViewController 사이의 사이즈 크기가 차이가 많이 나면 정신없이 움직여서 산만한 느낌이 든다.
이 기능이 꼼수를 통해서만 이루어 지는걸 봐서는 정신 없게 움직이는것을 방지하기 위해 그렇지 않을까 싶다.

때문에, 이 소스의 적용은 상황에 따라 잘 적용해야 할 것이다.


신고

댓글

댓글쓰기 폼

2013 이전/iOS개발

[iOS 개발] 안정적이고 flexible 한 UITableViewCell UI 구현하기

hagulu 하구루2017.02.25 16:31

UITableView 를 이용할때 Cell을 Customize 하여 사용하는 경우가 많을 것이다.

 이렇게 사용할때  Cell의 크기에 따라 Cell의 구성요소의 위치와 크기가 다르게 구성하는 경우가 많을 것이다.
 하지만 각각의 Cell을 UI사이즈나 위치가 변경할때 마다 각각의 Cell의 위치나 크기를 매번 새로 적용해주게 되면 여러 문제가 발생할 수가 있다.
 이때, 해당 Cell의 frame만 가지고 구성요소의 위치를 지정해 주게 되면 여러 문제에 봉착하게 된다.

 그래서 Cell을 구성할떄 위치와 크기에 변화가 필요한 것들은 모두  각 UIView에 AutoresizingMask를 적용하여 사용해야 한다. 전체 View가 유기적으로 AutoresizingMask를 적용하지 않아서 전체 적으로 static하게 구성하더라도, Cell은 적어도 AutoresizingMask를 통해서 구성해야 한다.
 Cell의 frame을 이용해서 계산하여 UIView의 위치를 배치하면, 최초 구동시나, 회전하여 구동할때 등 문제가 발생하게 된다.

 그리고 한가지 더 중요한 점이 Cell에서 구성되는 UIView를 Cell의 self에 바로 addSubview하는 경우가 많은데, 꼭! self.contentView에 addSubview 를 해주는 것이 좋다. Grouped UITableView에서 는 cell안에 표시되려면 꼭 필요한 부분이고, Plain이라고 하더라도 적용해 주어야한다. 그렇지 않으면 AutoresizingMask하는 부분이 의도한 대로 진행되지 않을 것이다. 따라서 특정한 경우가 아니라면 꼭 contentView에 addSubview를 해주어야 한다.
 어찌보면 당연한 것이지만, 쉽게 생각하고 무시하고 진행하는 경우가 있기때문에, 이 두 부분은 꼭 기억하고 UIView를 관리 하기 바란다.


신고

댓글

댓글쓰기 폼

2013 이전/iOS개발

[iOS 개발] UIPopoverController 의 EKEventEditViewController 키보드 문제

hagulu 하구루2017.02.25 16:31

iOS5에서 PopoverController위에 EKEventEditViewController를 올려서 사용하다 보면 cancel 버튼이나 done 버튼을 통해서 나왔을때는 문제가 없지만,


UIPopoverController의 바깥 공간을 선택했을때는 UIPopoverController가 사라져도 키보드가 내려가지 않는 문제가 발생한다.

해당 viewController의 view에 endEditing: 을 이용해 보아도 변화가 없다.

구글링을 통해서 일본사이트에서 해결 방법을 찾았다.

일본어는 번역기로도 꽤 읽을 만한 내용이 나온다.

해당 내용은 참고한 사이트에서 문제점을 수정하고 정리한 소스이다.
- (BOOL)popoverControllerShouldDismissPopover:(UIPopoverController *)popoverController {

    EKEventEditViewController *ev = (EKEventEditViewController *)self.popoverController.contentViewController;
    for (UIView* view in [[ev navigationBar] subviews])
    {
        if ([NSStringFromClass([view class]) isEqualToString: @"UINavigationButton"])
        {
            UIButton* btn = (UIButton*)view;
            
            for (UIBarButtonItem* buttonItem in [btn allTargets])
            {
                id target = [buttonItem target];
                SEL sel = @selector(cancel:);
                
                if ([target respondsToSelector: sel])
                {
                    [target performSelector:sel];
                    
                    NSLog(@"target = %@", NSStringFromClass([target class]));
                    NSLog(@"action = %@", NSStringFromSelector(sel));
                    
                }
            }
        }
    }
    
    return YES;   
}

위 소스 처럼 UIPopoverController의 delegate인 "popoverControllerShouldDismissPopover:" 에 추가해주면 된다.

위 소스 내용은 UIPopoverController가 바깥쪽을 선택하여 사라지기 직전에 EKEventEditViewController의 navigation item중에서 selector가 cancel:인 item을 찾아서 cancel: 를 실행해주는 방식이다.

어찌보면 꼼수라고 할 수 있어서 정답이라고는 말할 수 없을것 같다.

혹시 좀더 깔끔한 답을 알게 된다면 다시 포스팅 해보도록 하겠다.


신고

댓글

댓글쓰기 폼

2013 이전/iOS개발

[iOS 개발] 현재 view의 모든 text editing 중단하기

hagulu 하구루2017.02.25 16:30

textfeild 나 textView 등 text를 editing 하는 view를 만들다 보면

키보드등 여러 문제로 골머리를 썩은 경험이 있을것이다.

특히, resignFirstResponder를 통해서 해당 editing을 그만 두려고 해야할때,

cell위에 사용하거나 여러 view가 중첩되어 해당 view의 객체를 컨트롤 하기 힘든경우가 발생할 수 있다.

이때 해당하는 뷰의 모든 subview들의 editing을 그만 두도록 한번에 처리 할수 있는 메소드가 있다.

[targetView endEditing:YES];

위 처럼 해당 뷰의 메소드를 호출하게되면 모든 subview들에 있는 editing이 멈추게 된다.

editing 때문에 올라와 있던 키보드들도 내려가게 된다.


신고

댓글

댓글쓰기 폼

2013 이전/iOS개발

[iOS 개발] 유용한 각종 UI controller open source 정리 사이트

hagulu 하구루2017.02.25 16:26

iOS에서 쓰이는 기본적인 UI 컨트롤러 외에 좀더 편리한 Custom controller 를 구현하고자 한다면 다음 사이트를 먼저 찾아보고 해보기 바란다.



해당 사이트는 custom으로 만들어 놓은 각종 컨트롤들이 open source로 공개되어 정리되어 있다.
iOS 뿐아니라 Max OSX까지도 올려져 있다. 꽤나 많은 자료가 있고, 최근 유행하는 Custom controller들이 많이 올라와 있어서 아주 유용할것이다. 그리고 라이센스 별로 나누어져 있어서 이부분에서도 사용이 편리할 것이다.


신고

댓글

댓글쓰기 폼

2013 이전/iOS개발

[iOS 개발] 지역에 맞게 날짜 표기 하기

hagulu 하구루2017.02.25 16:26

글로벌하게 앱을 배포하려 하다 보면 날짜 형식을 표시하는데 문제가 생긴다.


일반적으로 우리나라의 표기 방식은

"2012년 10월 5일 금요일" 이런식으로 표시 된다.

하지만 미국의 경우는

"Friday October 5, 2012" 로 표기 순서와 방식이 다르다

그외에 또 다른 나라는 그 나라만의 표기 방식이 있다.

하지만 이를 지원하기 위해 모든 지역의 표기 방식을 찾아서 따로 처리 할 수는 없는 노릇이다.


다행이도 이를 쉽게 적용할 수 있는 method가 존재한다.

위와 같이 날짜를 표기 할때 NSDateFomatter를 사용하게 될 것이다.

기본적인 사용법은 따로 언급하지 않겠다.

한국의 표기 법대로 위의 경우라면

"yyyy MMMM d EEEE" 정도가 될 것이다.
이것을 현재 디바이스에 설정된 지역의 표기 방식으로 한방에 변환 시켜주는 함수가 있다.

간단한 예제를 보여 주겠다.
    NSString *dateFormatString = @"yyyy MMMM d EEEE";
    dateFormatString = [NSDateFormatter dateFormatFromTemplate:dateFormatString options:0 locale:[NSLocale currentLocale]];
    
    NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
    [dateFormat setDateFormat:dateFormatString];
    
    NSLog(@"%@", [dateFormat stringFromDate:[NSDate date]]);
위 예제를 수행하게 되면 위에 언급했던 방식으로

한국은 "2012년 10월 5일 금요일" 미국은 "Friday October 5, 2012"로 표시 된다.

위에서 보는것처럼 우리나라의 표시 방식으로 포멧을 스트링으로 만들고 이것을 아래 메소드를 통해서

만든 포멧 스트링과 현재 로케일 정보를 넣어 주면 해당 지역에 맞는 포멧 스트링을 리턴해 준다

dateFormatFromTemplate:dateFormatString:options:locale:

미국의 경우 "EEEE, MMMM d, yyyy"로 변환이 되고한국의 경우 "yyyy년 MMMM d일 EEEE"으로 변환이 된다.

미국의 경우 순서가 바뀌었고,

한국의 경우 "년" "일" 이라는 포멧을 넣지 않았지만 우리나라에 맞춰서 들어가는것을 알 수 있다.
("월"은 EEEE포멧일경우 자동으로 들어 간다)

이것을 이용하면 글로벌하게 배포될 앱의 날짜 포멧의 문제는 한방에 해결되게 된다.

참고로 위 메소드에 현재 로케일은 아래 그림에 표시된 부분의 설정에 따르게 된다. 


 .     


신고

댓글

댓글쓰기 폼

2013 이전/iOS개발

[iOS 개발] iCloud keyValue Data Storage 사용

hagulu 하구루2017.02.25 16:20

유니버셜 앱을 개발하여 배포할때 각 앱의 설정을 연동할때 유용하게 사용할 수 있는

 
iCloud keyValue Data Storage를 소개 해보려고 한다.

앱 내에서 iCloud 연동을 위한 설정은 아래 포스팅을 통해 진행하면 된다.


설정이 다되면 이를 이용하는 것은 매우 간단하다.

NSUserDefault를 이용해 본 사용자라면 보자 마자 이해 할 수 있을것이다.

NSUbiquitousKeyValueStore 라는 클래스를 통해서 쉽게 사용 할수 있다.


 NSUbiquitousKeyValueStore* store = [NSUbiquitousKeyValueStore defaultStore];
        
        [store setBool:YES forKey:@"kUsrDefAskDeleting"];

        [store synchronize];
보는 것처럼 간단하게 defaultStore 메소드를 통해서 keyValue를 셋할수 있는 객체를 얻어 올수 있고,
 
해당 객체에 set 메소드를 통해서 BOOL 변수 뿐 아니라
- (void)setString:(NSString *)aString forKey:(NSString *)aKey;
- (void)setData:(NSData *)aData forKey:(NSString *)aKey;
- (void)setArray:(NSArray *)anArray forKey:(NSString *)aKey;
- (void)setDictionary:(NSDictionary *)aDictionary forKey:(NSString *)aKey;
- (void)setLongLong:(long long)value forKey:(NSString *)aKey;
- (void)setDouble:(double)value forKey:(NSString *)aKey;
- (void)setBool:(BOOL)value forKey:(NSString *)aKey;
위 메소드를 통해서 여러 형태의 객체를 저장할 수 있다.
 
그리고 모든 저장 절차가 끝나면

synchronize 메소드를 호출해 주면 된다.

synchronize를 호출했다고 해서, 해당 하는 내용이 iCloud로 바로 전송이 되어지는 것은 아니다.

해당 메소드를 호출하면 해당하는 내용이 즉시 파일에 저장이 된다.

이후 iCloud로 전송이 되는것은 시스템이 알아서 해준다.

즉, iCloud로 싱크 시키는것을 명시적으로 해줄 수 있는 방법은 없다.

그렇다고, 그 iCloud로 싱크되는 시점이 늦지는 않으니 걱정하지 않아도 될것이다.

네트워크가 안정적인 환경에서 테스트 해보았을때 30초 안에는 적용이 되어 다른 디바이스에 전달되는것을 확인 하였다.

이제 변경된 사항을 iCloud로 부터 받아 보는 방법을 보겠다.

이도 매우 간단하다.
 NSUbiquitousKeyValueStore *keyStore = [NSUbiquitousKeyValueStore defaultStore];
        
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector: @selector(ubiquitousKeyValueStoreDidChange:)
                                                     name: NSUbiquitousKeyValueStoreDidChangeExternallyNotification
                                                   object:keyStore];
    
        [keyStore synchronize];

위 와 같은 방법으로 notification을 등록해 준후에 해당 메소드를 구현해주기만 하면 된다.

-(void) ubiquitousKeyValueStoreDidChange: (NSNotification *)notification
{
    // Get the list of keys that changed.
    NSDictionary* userInfo = [notification userInfo];
    NSNumber* reasonForChange = [userInfo objectForKey:NSUbiquitousKeyValueStoreChangeReasonKey];
    NSInteger reason = -1;
    
    // If a reason could not be determined, do not update anything.
    if (!reasonForChange)
        return;
    
    // Update only for changes from the server.
    reason = [reasonForChange integerValue];
    if ((reason == NSUbiquitousKeyValueStoreServerChange) ||
        (reason == NSUbiquitousKeyValueStoreInitialSyncChange)) {
        // If something is changing externally, get the changes
        // and update the corresponding keys locally.
        NSArray* changedKeys = [userInfo objectForKey:NSUbiquitousKeyValueStoreChangedKeysKey];
        NSUbiquitousKeyValueStore* store = [NSUbiquitousKeyValueStore defaultStore];
        NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
        
        // This loop assumes you are using the same key names in both
        // the user defaults database and the iCloud key-value store
        for (NSString* key in changedKeys) {
            id value = [store objectForKey:key];
            [userDefaults setObject:value forKey:key];
        }
    }
}

위 처럼 구현을 하였는데, 이는 apple developer page에서 그대로 가져다 쓴것이다.


NSUserDefault를 통해서 셋팅을 관리 한다면 그대로 가져다 써도 무방할 것이다.

 해당 내용은 그렇게 어렵지 않으므로 추가 적인 설명은 생략 하겠다. 


 사용이 간단하니 한번씩 앱에 적용해 보는 것도 나쁘지 않을 것으로 보인다.


신고

댓글

댓글쓰기 폼

2013 이전/iOS개발

[iOS 개발] 간단한 animation 처리

hagulu 하구루2017.02.25 16:20

iOS를 통한 개발에 animation은 꽤나 중요한 부분이다.

 
iOS 특성상 부드러운 animation이 앱을 좀더 고급스럽게 만들어 주는데
iOS를 이를 위해 아주 간단하게 animation을 쉽게 구현할수 있도록 해 놓았다.
animation 전과 후의 View의 상태만 정해주면 그이외의 작업들은 모두 알아서 해준다.
예제 코드를 보면서 설명을 해 보겠다.
        CGRect rect = targetView.frame;
        rect.origin.x = 300;
        targetView.frame = rect;
        
        [UIView beginAnimations:nil context:nil]; 
        [UIView setAnimationDelegate:self];
        [UIView setAnimationDuration:0.3];
        [UIView setAnimationRepeatCount:1];

        rect = targetView.frame;
        rect.origin.x = 0;
        targetView.frame = rect;
        
        [UIView commitAnimations];

위 의 예제대로 수행을 하면 해당하는 targerView는 x좌표 300의 위치에서 x좌표 0의 위치로 자연스럽게 animation이 변화 하게 된다.

 CGRect에 대한 설명은 따로 하지 않겠다.
 animation을 시켜주는 부분이 중요하다.
  
 [UIView beginAnimations:nil context:nil]; 

해당 부분은에서 주목해야할 부분은 첫번째 파라 미터이다.

나중에 delegate를 통해서 animation이 시작하거나 끝나는 때에 여러 작업을 할때
각기 다른 animation들을 구분하는데 이용된다. 일종의 animation key이다.
  
       [UIView setAnimationDuration:0.3];
        [UIView setAnimationRepeatCount:1];

위의 첫번째 메소드는 animation이 진행되는 시작이다 이를 길게 하면 animation 이 느려지고 짧게 하면 animation이 빨라 진다.

두번쨰 라인의 메소드는 보이는 그대로 반복 횟수이다. 해당 animation이 몇번 반복될지 설정해 주는 것이다.
  
     [UIView commitAnimations];

마지막으로 animation을 마무리 지어 주도록 하는 메소드이다.


이를 해주지 않으면 이후의 모든 frame등의 변화가 animation되는 경의로운 현상을 보게 될것이다.

 재미 삼아 한번 확인해 보는것을 추천한다.

이를 이용해 view의 alpha 값으로 fade 효과도 이용할수 있으며

CGRect를 잘활용하여 위치나 크기 등을 animation으로 쉽게 이용 가능하다.


신고

댓글

댓글쓰기 폼

2013 이전/iOS개발

[iOS 개발] UITableView 기본 delegate, datasource

hagulu 하구루2017.02.25 16:19

UITableView 를 사용하다 보면 항상 기본적인 delegate와 datasource의 소스들을 다른 소스에서 긁어서 쓰고 있다.

이참에 항상 쓰는 소스만 정리해서 올려 놓으려고 한다.
#pragma mark -
#pragma mark tableview delegate

// 섹션의 갯수
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    // Return the number of sections.
    
    return 1;
}

// 각 섹션당 로우의 갯수
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    // Return the number of rows in the section.
    
    return 5;
    
}

// 각 셀 그리기
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    static NSString *CellIdentifier = @"CalendarCell";
    
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
        
            
    }
    
    
    return cell;
}


// 셀이 선택 되었을때 수행할 내용 
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    
     
}


// 각셀의 높이 
-(CGFloat) tableView : (UITableView *) tableView heightForRowAtIndexPath : (NSIndexPath *)indexPath{
    
    return 45;    
}


신고

댓글

댓글쓰기 폼

hagulu.com

.....

VISITED

Today : 103

Total : 119,814

Lately Comment