2013-03-30 8 views
14

У меня есть несколько контроллеров представлений и контроллеров табличного представления, которые я выталкиваю из своего контроллера корневого представления. Во всех этих случаях я бы хотел использовать пользовательскую кнопку возврата в навигационном контроллере. Вместо того, чтобы копировать метод для настройки моей кнопки возврата в каждый класс, файл, я создал вспомогательный класс с методом класса, который выполняет настройку. Ниже приведен код, но мне интересно, не ошибаюсь ли я в этом. Есть ли лучший способ достичь этого? Кроме того, я все еще дублирую метод myCustomBack (void) во всех своих классах и задаюсь вопросом, есть ли способ избежать этого.Каков наилучший способ совместного использования методов в классах 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

Хороший выбор. Эта модель мне очень понравилась, и я никогда не сожалел об этом. Поскольку я замечаю, что это ваш первый вопрос, вы должны пометить ответ как принятый, нажав галочку. Либо Джош Касуэлл, либо ваш собственный ответ сделали бы хороший выбор на мой взгляд, но это ваше решение в одиночку, очевидно. Хороший первый вопрос, надеюсь, что вы продолжаете вносить свой вклад, удачи. –

+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. Часть кода оттуда:

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

В большинстве языков упрощенное решение состоит в том, чтобы иметь несколько классов 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

Спасибо за это - Да, я использую протокол 'UIAppearance' для всех моих других' UIBarButtonItem'', и я использую его для своих кнопок на других контроллерах представлений. Проблема заключается в том, что вы не можете изменить название кнопки «Назад», не используя пользовательский вид. – Dylan

+0

Ну, вы не можете изменить заголовок на значок, но вы можете изменить заголовок. Заголовок - это свойство 'title' предыдущего контроллера в стеке. – Sulthan

+0

Правильно, я мог бы изменить заголовок контроллера корневого представления на 'viewDidDisappear', а затем сбросить его на' viewWillAppear', но это кажется немного «взломанным», но я полагаю, что мой текущий подход также «взломан». Но если бы я решил использовать образ вместо названия, мне все равно нужно было бы использовать нестандартное представление. – Dylan

Смежные вопросы