将按钮添加到 UINavigationBar 的子类

Add buttons to subclass of UINavigationBar

我正在子类化 UINavigationBar。在我的导航栏中,我想添加一个后退按钮。最终我想要一个标题,一个自定义按钮和 uicollectionview 看起来像这样:

我在 UINavigationBar

的子类中添加按钮时遇到问题

AppDelegate:

 NFVDContentTableViewController *contentTVC = [[NFVDContentTableViewController alloc] initWithNibName:nil bundle:nil];
 UINavigationController *contentNavCtr = [[UINavigationController alloc] initWithNavigationBarClass:[NFVDContentNavigationBar class] toolbarClass:[UIToolbar class]];
 contentNavCtr.viewControllers = @[contentTVC];

在我的子类 UINavigation Header 文件中:

@interface NFVDContentNavigationBar : UINavigationBar <UINavigationBarDelegate>

@end

在我的子类 UINavigationBar 实现文件中:

@implementation NFVDContentNavigationBar

/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
    // Drawing code
}
*/

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {

    }
    return self;
}

- (void)awakeFromNib {

    [super awakeFromNib];

    UINavigationItem* ni = [[UINavigationItem alloc] init];
    UIButton *leftButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 38.0f, 29.0f)];
    [leftButton setImage:[UIImage imageNamed:@"reveal-icon"] forState:UIControlStateNormal];
    [leftButton addTarget:nil action:@selector(menuItemPressed:) forControlEvents:UIControlEventTouchUpInside];
    [leftButton setContentMode:UIViewContentModeScaleAspectFit];
    [leftButton setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin];
    UIBarButtonItem *b =[[UIBarButtonItem alloc] initWithCustomView:leftButton];

    ni.leftBarButtonItem = b;
    self.items = @[ni];

}

- (CGSize)sizeThatFits:(CGSize)size{

    CGSize newSize = [super sizeThatFits:size];

    DLog(@"NewSize: %@", NSStringFromCGSize(newSize));

    CGRect mainScreen = [UIScreen mainScreen].bounds;

    if([UIView viewOrientationForSize:mainScreen.size] == ViewOrientationPortrait){

        return CGSizeMake(newSize.width, 100);

    }else if([UIView viewOrientationForSize:mainScreen.size] == ViewOrientationLandscape){

        return CGSizeMake(newSize.width, 44);

    }

    return CGSizeZero;

}

- (void)layoutSubviews {
    [super layoutSubviews];
}

@end

这很难做到,因为 UIViewController 带有自己的 UINavigationItems,请参阅 UIViewController header 文件中的文档:

NS_CLASS_AVAILABLE_IOS(2_0) @interface UIViewController : UIResponder <NSCoding, UIAppearanceContainer, UITraitEnvironment, UIContentContainer> {
    @package
    UIView           *_view;
    UITabBarItem     *_tabBarItem;
    UINavigationItem *_navigationItem;

您必须重写 UIViewController 的这个功能,这是可能的,但需要您子 class UIViewController,然后强制应用中的所有视图控制器成为子class子的子classed view controller,所以这是困难的方法,我会展示它的代码,但它有点紧张并且有很多代码,但我就是这样做的。无论如何,更好的选择是在 UIViewController 的 ViewDidLoad 中执行此操作:

- (void)viewDidLoad
{
    [super viewDidLoad];
    UIBarButtonItem * tester = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"reveal-icon"] style:UIBarButtonItemStylePlain target:self action:@selector(menuItemPressed:)];
    [[self navigationItem] setRightBarButtonItem:tester];
}

您仍然可以子class UINavigationBar,但不要将它用作子class来尝试覆盖已经挂钩到 UIKit 默认的 UIViewController 的 barbuttonitems,如果您想对此感到疯狂,那么这里是您如何子 class 一个 UIViewController 的开始,它有很多代码:

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];

    if (self == nil)
        return nil;

    if (self) {
        _showsNotifications = false;
        _showsAddFriends = false;
    }
    _notificationsBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage resizeImage:[UIImage imageNamed:@"YOUR IMAGE NAME"] height:27] style:UIBarButtonItemStylePlain target:nil action:nil];
    _addFriendsBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"YOUR IMAGE NAME"] style:UIBarButtonItemStylePlain target:self action:@selector(addFriendsPressed)];
}

您看,您将更改 UIViewController 中 UINavigationItems 的内部结构的自定义视图控制器 Bool 属性添加。然后,使用此方法需要您在 viewcontroller 的 INIT 中调用并设置这些 bool 值,这些 viewcontroller 是此自定义 viewcontroller 的子class,请这样做:

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self)
    {
        [self setShowsAddFriends:false];
        [self setShowsNotifications:false];
    }
    return self;
}

然后在subclassed UIViewController中,让bool switches能够实际切换。

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    if (_showsNotifications) {
        [[self navigationItem] setRightBarButtonItem:_notificationsBarButtonItem];
    }
    if (_showsAddFriends) {
        [[self navigationItem] setRightBarButtonItem:_addFriendsBarButtonItem];
    }
}

大功告成,复杂吗?有点,但这就是你如何使用尽可能多的自定义导航项按钮来模板化项目,完整代码大约有 1k 行代码,但这就是它的核心,subclass UIViewController,set bool properties在 header 中,在您的 subclass 中设置这些 bool 属性,以便使用此 subclass 作为其 parent class 的 UIViewControllers 可以调用这些 bool setter 属性在 "init" 中,然后您就可以切换并选择您喜欢的导航项。此外,为了确保您的视图控制器维护您为它们设置的项目,请确保您还在视图控制器中的 viewWillAppear 中声明了这些项目设置,这些视图控制器使用您的 UIViewController 的自定义 subclass 作为您的 parent 视图。祝你好运,祝你有美好的一天。

事实上,我只是给你看代码,为什么?因为我很无聊,而且与下周的两个应用程序发布有太多关系。所以,这里是您需要查看的文件,请记住这些文件非常简单:

CCUSTViewController.m

//******CCUSTViewController.m****
//this is the implementation file for the subclass of UIViewController

#import "CCUSTViewController.h"
#import "CCUSTFriendsViewController.h"
#import "CCUSTActivitiesViewController.h"

@interface CCUSTViewController ()
@end

@implementation CCUSTViewController
{
    UIBarButtonItem * _notificationsBarButtonItem;
    UIBarButtonItem * _addFriendsBarButtonItem;
}

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self == nil)
        return nil;
    if (self) {
        _showsNotifications = false;
        _showsAddFriends = false;
    }
    _notificationsBarButtonItem = [[UIBarButtonItem alloc] initWithImage::[UIImage imageNamed:@"your imate"] style:UIBarButtonItemStylePlain target:self action:@selector(showNotificationsPressed)];
    _addFriendsBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"your imate"] style:UIBarButtonItemStylePlain target:self action:@selector(addFriendsPressed)];
    return self;
}
- (void)showNotificationsPressed
{
    CCUSTActivitiesViewController * tobePushed = [CCUSTActivitiesViewController new];
    [self navigationController] pushViewController:tobePushed animated:true];
}

- (void)addFriendsPressed
{
    CCUSTFriendsViewController * tobePushed = [CCUSTFriendsViewController new];
    [self navigationController] pushViewController:tobePushed animated:true];
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    if (_showsNotifications) {
        [[self navigationItem] setRightBarButtonItem:_notificationsBarButtonItem];
    }
    if (_showsAddFriends) {
        [[self navigationItem] setRightBarButtonItem:_addFriendsBarButtonItem];
    }
}

@end

CCUSTViewController.h

#import <UIKit/UIKit.h>

@interface CCUSTViewController : UIViewController

@property (nonatomic) BOOL showsNotifications;
@property (nonatomic) BOOL showsAddFriends;

@end

然后,这是一个使用新导航栏项目切换器的子classes 视图控制器的示例:

CCCUSTHomeViewController.h

#import "CCUSTViewController.h"

@interface CCCUSTHomeViewController : CCUSTViewController
@end

CCCUSTHomeViewController.m

// CCCUSTHomeViewController.m
#import "CCCUSTHomeViewController.h"
#import "CCCUSTHomeView.h"

@interface CCCUSTHomeViewController () 
@end

@implementation CCCUSTHomeViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self)
    {
        [self setShowsAddFriends:TRUE];
        [self setShowsNotifications:TRUE];
    }
    return self;
}

-(void)loadView 
{
    [self setView:[CCCUSTHomeView new]];
}

-(CCCUSTHomeView*)contentView 
{
    return (id)[self view];
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self setTitle:@"HOME"];
}

-(void)viewWillAppear:(BOOL)animated 
{
    [super viewWillAppear:animated];
    [self setShowsAddFriends:TRUE];
    [self setShowsNotifications:TRUE];
}
@end

哦,是的,您需要将相同的代码从 init 添加到 ViewWillAppear,因为当您将推送的视图控制器弹出堆栈时,您甚至需要在 CCCUSTHomeViewController 中拦截它,以便 UINavigationItems 重新显示为他们应该给出位于堆栈顶部的 viewcontroller 。您还可以子class UICollectionViewController 和 UITableViewController 中的所有内容执行相同的方法,这意味着使用此结构作为模板,您可以在 Xcode 中拥有一个包含所有这些子class 的空项目es 添加到其中,然后您将可以更好地控制所有视图控制器。实施此方法还有很多事情可以做,但有些事情,我必须保密,但足以说明,许多大型应用程序都使用这种相同的技术以及您看不到的其他高级技术在野外。巧妙的是,您不必委托,也不必操纵任何东西。祝你好运,祝你有美好的一天。

GISTS 因为我关心:

https://gist.github.com/anonymous/993e457561001cf8e77b

https://gist.github.com/anonymous/bc6095575038c36de77b

https://gist.github.com/anonymous/78b450d2a805781ab8a4

https://gist.github.com/anonymous/a0757179c17dd7078bb2