2013-03-30 136 views
14

我有幾個視圖控制器和表視圖控制器,我從根視圖控制器推。在所有這些中,我想在導航控制器中使用自定義後退按鈕。而不是複製方法來設置我的後退按鈕到每個類,文件中,我創建了一個輔助類和一個類方法來完成設置。下面的代碼工作,但我想知道如果我以錯誤的方式去做。有沒有更好的方法來實現這一目標?另外,我仍然在所有類中複製 - (void)myCustomBack方法,並且想知道是否有辦法避免這種情況。目標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 

(使用的首字母縮略詞爲前綴,從您的名稱進行,或者公司或者項目的名字,儘管它很醜,但是你需要避免任何碰撞的可能性,類別衝突的方法會產生瑣碎的bug。)

只要你這樣做,你就可以也把輔助方法也放到了類別中。將它變成一個實例方法,只需使用self而不是傳入的控制器。

然後你所有的子類都會繼承這些方法,你可以像使用它們一樣定義它們。如果任何類需要以某種方式專門化,則可以覆蓋。

1

有更好的方法去做這件事:使用UIAppearance協議。您可以設置所有這些屬性,並讓每個後退按鈕包含在自定義視圖類型或任何導航欄中,以繼承外觀。

Here's a screencast that will help you。一些從那裏的代碼:

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

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

注意,CustomNavigationBar類可以只是UINavigationBar,這將導致所有後退按鈕來獲取外觀。

你可能無法做到的一件事是「返回」標題。這將不得不在你所有的視圖控制器中。

+0

哦,在我回答完之前你確實回答了。 – Sulthan

+0

我沿着這條道路走下去的原因是我可以改變後退按鈕的標題,或將其改爲「家」圖像,而不是有標籤。不幸的是它不能用'UIBarButtonItem'來實現。我只能通過使用自定義視圖來做到這一點。我爲所有其他按鈕和導航欄本身使用了「UIAppearance」協議。 – Dylan

0

在大多數語言中,easist解決方案是使用靜態(類)方法來創建幾個Utils類。

在的OBJ-C中,常見的方式是使用類別。

在您的示例中,在UIBarButtonItem上創建類別,例如, UIBarButtonItem (CustomizedButtons)與方法+(UIBarButton*)customBackButton會好得多。

然而,有一個簡單的方法。 您可以修改所有的後退按鈕的外觀在同一個地方,讓我們來看一個例子

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

相關問題