2013-03-30 69 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

相关问题