2013-03-30 6 views
14

루트보기 컨트롤러에서 밀어 넣는 여러 개의보기 컨트롤러와 테이블보기 컨트롤러가 있습니다. 이 모든 것들은 네비게이션 컨트롤러에서 커스텀 뒤로 버튼을 사용하고 싶습니다. 각 클래스, 파일에 내 뒤로 단추를 설정하는 메서드를 복사하는 대신 설치를 수행하는 클래스 메서드로 도우미 클래스를 만들었습니다. 아래의 코드는 작동하지만 잘못된 방향으로 가고 있는지 궁금합니다. 이것을 달성하기위한 더 좋은 방법이 있습니까? 또한, 나는 여전히 모든 클래스에서 - (void) myCustomBack 메서드를 복제하고 있으며이를 방지하는 방법이 있는지 궁금해하고 있습니다.Objective C의 클래스에서 메서드를 공유하는 가장 좋은 방법은 무엇입니까?

@interface NavBarBackButtonSetterUpper : NSObject 
+ (UIButton *)navbarSetup:(UIViewController *)callingViewController; 
@end 

@implementation NavBarBackButtonSetterUpper 

+ (UIButton *)navbarSetup:(UIViewController *)callingViewController 
{ 
    callingViewController.navigationItem.hidesBackButton = YES; 

    UIImage *backButtonImage = [[UIImage imageNamed:@"back_button_textured_30"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 13, 0, 5)]; 

    UIButton *backButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 50, 30)]; 

    [backButton setBackgroundImage:backButtonImage forState:UIControlStateNormal]; 

    [backButton setTitle:@"Back" forState:UIControlStateNormal]; 
    backButton.titleLabel.font = [UIFont fontWithName:@"AmericanTypewriter-Bold" size:12]; 
    backButton.titleLabel.shadowOffset = CGSizeMake(0,-1); 

    UIView *customBackView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 50, 30)]; 
    [customBackView addSubview:backButton]; 

    callingViewController.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:customBackView]; 

    return backButton; 
} 
@end 



@interface MyCustomTableViewController : UITableViewController 
@end 

@implementation MyCustomTableViewController 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    UIButton *backButton = [NavBarBackButtonSetterUpper navbarSetup:self]; 

    [backButton addTarget:self action:@selector(myCustomBack) forControlEvents:UIControlEventTouchUpInside]; 
} 

- (void)myCustomBack 
{ 
    [self.navigationController popViewControllerAnimated:YES]; 
} 
@end 


@interface MyCustomViewController : UIViewController 
@end 

@implementation MyCustomViewController 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    UIButton *backButton = [NavBarBackButtonSetterUpper navbarSetup:self]; 

    [backButton addTarget:self action:@selector(myCustomBack) forControlEvents:UIControlEventTouchUpInside]; 
} 

- (void)myCustomBack 
{ 
    [self.navigationController popViewControllerAnimated:YES]; 
} 
@end 

답변

4

답장을 보내고 올바른 방향으로 나를 가리켜 주셔서 감사합니다. 나는 다른 클래스에서 사용할 메소드가 포함 된 UIViewController 카테고리를 만들었다. 이렇게하는 더 우아한 방법이 있다면, 제안을 듣게되어 기쁩니다. 이것은 내가 함께 갔다.

// UIViewController+BackButtonSetup.h 

@interface UIViewController (BackButtonSetup) 
- (void)backButtonSetup; 
- (void)myCustomBack; 
@end 


// UIViewController+BackButtonSetup.m 

@implementation UIViewController (BackButtonSetup) 

- (void)backButtonSetup 
{ 
    self.navigationItem.hidesBackButton = YES; 

    // A Bunch of code to set up the custom back button 

    [backButton addTarget:self action:@selector(myCustomBack) forControlEvents:UIControlEventTouchUpInside]; 

} 

- (void)myCustomBack 
{ 
    [self.navigationController popViewControllerAnimated:YES]; 
} 

@end 


// MyCustomTableViewController.m 

#import "UIViewController+BackButtonSetup.h" 

@implementation MyCustomTableViewController 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    [self backButtonSetup]; 
} 
@end 


//MyCustomViewController.m 

#import "UIViewController+BackButtonSetup.h" 

@implementation MyCustomViewController 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    [self backButtonSetup]; 
} 
@end 
+0

좋은 선택. 이 패턴은 나에게 매우 도움이되었고 나는 결코 그것을 사용하는 것을 후회하지 않았다. 이것이 첫 번째 질문임을 알기 때문에 체크 표시를 클릭하여 대답을 표시해야합니다. 조쉬 캐스 웰 (Josh Caswell)이나 자신의 대답이 내 견해로는 좋은 선택이 될 것이지만, 그것은 분명히 혼자의 결정입니다. 좋은 첫 번째 질문, 행운을 기원하며 계속 기여할 수 있기를 바랍니다. –

+0

@CarlVeazey - 감사합니다! 이것이 나의 첫 번째 질문이기 때문에, 나는 대답을 표시하기위한 적절한 에티켓에 대해 여전히 조금 확신하지 못하고있다. 나는 카테고리를 만드는 방법을 연구하고 연구하는 동안 모든 대답을 읽고 모두 고려했습니다. 또한, 나는 응답을 기다리고 싶었고 문제에 대한 가능한 더 나은 해결책을 원했습니다. 그러나이 시점에서 나는 내가 가진 것이 잘 작동한다고 생각합니다. – Dylan

4

나는 귀하의 문제에 대한 해결책이 상속이라고 생각합니다.

UIViewController의 하위 클래스를 만들고 모든 사용자 지정보기 컨트롤러가이 사용자 지정 하위 클래스에서 상속받을 수 있습니다. "부모"하위 클래스는 설치 코드와 함께 -(void)myCustomBack을 가지므로 더 이상 반복하지 않아도됩니다.

+0

이것은. 카테고리 나 프로토콜을 사용할 수도 있지만이 경우 서브 클래 싱이 가장 쉬운 방법 인 것 같습니다. 개체에 따라 구현이 변경된 경우에만 메서드를 재정의해야합니다. – user2000809

+2

이것은 뷰 컨트롤러와 테이블 뷰 컨트롤러를 모두 서브 클래스 화해야한다는 의미이므로 중복 코드가 여전히 남아 있습니다. – Andreas

+0

'UIViewController'와'UITableViewController' 둘 다에 대한 서브 클래스를 만들어야합니까? 나는 여전히 두 곳에서 코드를 복제 할 것이다. – Dylan

2

설치 방법은 실제로 별도의 클래스에있을 필요는 없습니다. 나는 당신이 그 일을해야한다고 말하고 싶습니다.

myCustomBack 방법은, 한 정확히 모든 서브 클래스에서 같은의로, 쉽게 UIViewController에 범주에 넣을 수 있습니다

@interface UIViewController (DylanBack) 
- (void)DylanCustomBack; 
@end 

@implementation UIViewController (DylanBack) 
- (void)DylanCustomBack 
{ 
    [self.navigationController popViewControllerAnimated:YES]; 
} 
@end 

이 (접두사에 대한 두문자를 사용하거나 당신의 이름에서 만든 , 또는 회사 또는 프로젝트의 이름. 비록 추한 사람이라도 충돌 가능성을 피할 필요가 있습니다. 카테고리 충돌은 불법적 인 방법으로 인해 험난한 버그를 만듭니다.)

이 작업을 수행하는 동안 또한 도우미 메서드를 범주에 추가하십시오. 그것을 인스턴스 메소드로 변환하고 전달 된 컨트롤러 대신 self을 사용하십시오.

그러면 모든 하위 클래스가 메소드를 상속하며 사용자가 정의한 것처럼 하위 클래스를 사용할 수 있습니다. 클래스 중 하나라도 특수화해야하는 경우 재정의 할 수 있습니다.

1

더 좋은 방법이 있습니다. UIAppearance 프로토콜을 사용하십시오. 이러한 모든 속성을 설정하고 사용자 정의보기 유형 또는 탐색 모음에 포함 된 모든 뒤로 단추가 모양을 상속 받도록 할 수 있습니다.

Here's a screencast that will help you. 거기에서 코드의 일부 : 그 CustomNavigationBar 클래스는 단지 모양을 얻기 위해 모든 다시 버튼을 일으킬 것이다, UINavigationBar 될 수 있음을

UIImage *back = [UIImage imageNamed:@"nav-backbutton.png"]; 
back = [back stretchableImageWithLeftCapWidth:ArrowLeftCap topCapHeight:0]; 

[[UIBarButtonItem appearanceWhenContainedIn:[CustomNavigationBar class], nil] 
       setBackButtonBackgroundImage:back 
            forState:UIControlStateNormal 
           barMetrics:UIBarMetricsDefault]; 

참고.

당신이 할 수없는 한 가지는 "뒤로"제목입니다. 모든 뷰 컨트롤러에 있어야합니다.

+0

오, 내 대답을 끝내기 전에 대답 해 줬어. – Sulthan

+0

내가이 길을 갔던 이유는 뒤로 버튼의 제목을 변경하거나 라벨이있는 대신 '홈'이미지로 변경할 수 있기 때문입니다. 불행히도'UIBarButtonItem'으로는 불가능합니다. 필자는 사용자 정의보기를 사용하여이 작업을 수행 할 수있었습니다. 나는 다른 모든 버튼과 탐색 바에'UIAppearance' 프로토콜을 사용하고 있습니다. – Dylan

0

대부분의 언어에서 이단적인 해결책은 정적 (클래스) 메소드를 사용하는 여러 개의 Utils 클래스를 갖는 것입니다.

Obj-C에서 일반적인 방법은 범주를 사용하는 것입니다.

귀하의 예에서 UIBarButtonItem에 카테고리를 생성하십시오. 방법 +(UIBarButton*)customBackButtonUIBarButtonItem (CustomizedButtons)이 훨씬 더 좋을 것입니다.

그러나 더 간단한 방법이 있습니다. 당신은 이제 예를 들어 당신이 사용자 정의보기 및 특별한 뒤로 버튼 선택기를 사용하지 않아도

NSDictionary* titleAttributes = [NSDictionary dictionaryWithObjectsAndKeys: 
            [UIFont titilliumBoldWithSize:14.0f], UITextAttributeFont, 
            [UIColor colorWithIntegerRed:181 green:201 blue:210], UITextAttributeTextColor, 
            [UIColor clearColor], UITextAttributeTextShadowColor, 
            [NSValue valueWithUIOffset:UIOffsetMake(1.0f, 1.0f)], UITextAttributeTextShadowOffset, 
            nil]; 

NSDictionary* titleAttributesHighlighted = [NSDictionary dictionaryWithObjectsAndKeys: 
               [UIFont titilliumBoldWithSize:14.0f], UITextAttributeFont, 
               [UIColor whiteColor], UITextAttributeTextColor, 
               [UIColor clearColor], UITextAttributeTextShadowColor, 
               [NSValue valueWithUIOffset:UIOffsetMake(1.0f, 1.0f)], UITextAttributeTextShadowOffset, 
               nil]; 

[[UIBarButtonItem appearance] setTitleTextAttributes:titleAttributes forState:UIControlStateNormal];  
[[UIBarButtonItem appearance] setTitleTextAttributes:titleAttributesHighlighted forState:UIControlStateHighlighted]; 

[[UIBarButtonItem appearance] setTitlePositionAdjustment:UIOffsetMake(0.0f, 1.0f) forBarMetrics:UIBarMetricsDefault]; 

UIImage* backButtonImage = [UIImage imageNamed:@"navigation_button_back_bg"]; 
UIImage* backButtonImageHighlighted = [UIImage imageNamed:@"navigation_button_back_bg_highlighted"]; 

UIEdgeInsets backButtonCapInsets; 
backButtonCapInsets.top = 0.0f; 
backButtonCapInsets.bottom = backButtonImage.size.height; 
backButtonCapInsets.left = 14.0f; 
backButtonCapInsets.right = 5.0f; 

backButtonImage = [backButtonImage resizableImageWithCapInsets:backButtonCapInsets]; 
backButtonImageHighlighted = [backButtonImageHighlighted resizableImageWithCapInsets:backButtonCapInsets];  

[[UIBarButtonItem appearance] setBackButtonBackgroundImage:backButtonImage 
                forState:UIControlStateNormal 
               barMetrics:UIBarMetricsDefault]; 

[[UIBarButtonItem appearance] setBackButtonBackgroundImage:backButtonImageHighlighted 
                forState:UIControlStateHighlighted 
               barMetrics:UIBarMetricsDefault]; 

참고 보자, 한 곳에서 다시 모든 버튼의 모양을 수정할 수 있습니다.

+0

감사합니다. - 예. 다른 모든 UIBarButtonItem에 대해'UIAppearance' 프로토콜을 사용하고 있습니다. 다른보기 컨트롤러의 뒤로 버튼에이 프로토콜을 사용하고 있습니다. 문제는 사용자 지정보기를 사용하지 않고 뒤로 단추의 제목을 변경할 수 없다는 것입니다. – Dylan

+0

음, 제목을 아이콘으로 변경할 수는 없지만 제목을 변경할 수는 있습니다. 제목은 스택에있는 이전 컨트롤러의'title' 속성입니다. – Sulthan

+0

그래, 난 viewDidDisappear'에 루트보기 컨트롤러의 제목을 바꿀 수 있고'viewWillAppear'에 리셋했는데, 조금 "해킹 된 것 같아 보이지만 내 현재 접근법 또한"해킹 "이라고 생각한다. 그러나 제목 대신 이미지를 사용하도록 선택한 경우 사용자 지정보기를 사용해야합니다. – Dylan

관련 문제