14

我有几个从根视图控制器推送的视图控制器和表视图控制器。在所有这些中,我想在导航控制器中使用自定义后退按钮。我没有将设置后退按钮的方法复制到每个类文件中,而是创建了一个辅助类,其中包含一个执行设置的类方法。下面的代码有效,但我想知道我是否以错误的方式处理这个问题。有没有更好的方法来实现这一目标?另外,我仍然在我的所有课程中复制 -(void)myCustomBack 方法,并且想知道是否也有办法避免这种情况。

@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

5 回答 5

4

我认为解决您的问题的方法是继承。

您可以创建一个子类,UIViewController并让您的所有自定义视图控制器都继承自该自定义子类。“父”子类将具有-(void)myCustomBack设置代码,您无需再重复它。

于 2013-03-30T18:39:43.287 回答
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
于 2013-03-31T02:31:47.840 回答
2

setup 方法实际上并不需要在一个单独的类中;我会说你应该把它变成一个函数。

myCustomBack方法,只要它在所有子类中完全相同,就可以轻松放入以下类别UIViewController

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

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

(使用首字母作为前缀,由您的姓名或公司或项目的名称组成。即使它很丑陋,您也需要避免任何冲突的可能性。类别冲突破坏方法并且会产生粗糙的错误。)

只要你这样做,你也可以将辅助方法放入类别中。将其转换为实例方法,然后使用self而不是传入的控制器。

然后您的所有子类都将继承这些方法,您可以像在其中定义它们一样使用它们。如果任何类确实需要以某种方式专门化,您可以覆盖。

于 2013-03-30T18:40:05.327 回答
1

有一个更好的方法来解决这个问题:使用UIAppearance协议。您可以设置所有这些属性,并使自定义视图类型或任何导航栏中包含的每个后退按钮都继承外观。

这是一个可以帮助您的截屏视频。那里的一些代码:

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,这将导致所有后退按钮获得该外观。

您可能无法做到的一件事是“返回”标题。那必须在您的所有视图控制器中。

于 2013-03-30T18:51:55.770 回答
0

在大多数语言中,最简单的解决方案是拥有几个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];

请注意,您不必使用自定义视图,也不必使用特殊的后退按钮选择器。

于 2013-03-30T18:57:08.963 回答