草庐IT

ios - 将按钮添加到 UINavigationBar 的子类

coder 2024-01-18 原文

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

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

应用委托(delegate):

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

在我的子类 UINavigation 头文件中:

@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 头文件中的文档:

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

您必须覆盖 UIViewController 的这个功能,这是可能的,但需要您继承 UIViewController,然后强制应用程序中的所有 View Controller 成为您的子类 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];
}

您仍然可以子类化 UINavigationBar,但不要将它用作子类来尝试覆盖已经挂接到 UIKit 默认的 UIViewController 的 barbuttonitems,如果您想对此感到疯狂,那么这就是开始关于如何子类化 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)];
}

您看,您向自定义 View Controller 添加了 Bool 属性,这些属性更改了 UIViewController 中 UINavigationItems 的内部结构。然后,使用此方法需要您在作为此自定义 View Controller 子类的 View Controller 的 INIT 中调用并设置这些 bool 值,如下所示:

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

然后在子类化的 UIViewController 中,使 bool 开关能够实际切换。

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

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

搞定了,复杂吗?有点,但这就是你如何使用尽可能多的自定义导航项按钮来模板化项目,完整的代码大约有 1k 行代码,但这是它的核心,子类 UIViewController,在标题中设置 bool 属性,设置这些子类中的 bool 属性,以便使用该子类作为其父类的 UIViewControllers 可以在“init”中调用这些 bool setter 属性,然后您将能够切换并选择您喜欢的导航项。此外,为了确保您的 View Controller 维护您为它们设置的项目,请确保您还在使用 UIViewController 的自定义子类作为父 View 的 View Controller 中的 viewWillAppear 中声明了这些项目设置。祝你好运,祝你有美好的一天。

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

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

然后,这是一个使用新的导航栏项目切换器的子类 View Controller 的示例:

CCCUSTomeViewController.h

#import "CCUSTViewController.h"

@interface CCCUSTHomeViewController : CCUSTViewController
@end

CCCUSTomeViewController.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,因为当您将推送的 View Controller 弹出堆栈时,您甚至需要在 CCCUSTHomeViewController 中拦截它,以便 UINavigationItems 按原样重新出现应该给位于堆栈顶部的 View Controller 。您还可以使用相同的方法从 UICollectionViewController 和 UITableViewController 继承所有内容,这意味着使用此结构作为模板,您可以在 Xcode 中创建一个空项目,并将所有这些子类添加到其中,然后您将可以更好地控制所有 View Controller 。实现此方法还有很多事情可以做,但有些事情,我必须保密,但足以说明,许多大型应用程序都使用这种相同的技术以及您看不到的其他高级技术在野外。巧妙的是,您不必委托(delegate),也不必操纵任何东西。祝你好运,祝你有美好的一天。

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

关于ios - 将按钮添加到 UINavigationBar 的子类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31897581/

有关ios - 将按钮添加到 UINavigationBar 的子类的更多相关文章

  1. ruby - 我需要将 Bundler 本身添加到 Gemfile 中吗? - 2

    当我使用Bundler时,是否需要在我的Gemfile中将其列为依赖项?毕竟,我的代码中有些地方需要它。例如,当我进行Bundler设置时:require"bundler/setup" 最佳答案 没有。您可以尝试,但首先您必须用鞋带将自己抬离地面。 关于ruby-我需要将Bundler本身添加到Gemfile中吗?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/4758609/

  2. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  3. ruby - 将 Bootstrap Less 添加到 Sinatra - 2

    我有一个ModularSinatra应用程序,我正在尝试将Bootstrap添加到应用程序中。get'/bootstrap/application.css'doless:"bootstrap/bootstrap"end我在views/bootstrap中有所有less文件,包括bootstrap.less。我收到这个错误:Less::ParseErrorat/bootstrap/application.css'reset.less'wasn'tfound.Bootstrap.less的第一行是://CSSReset@import"reset.less";我尝试了所有不同的路径格式,但它

  4. ruby - 续集在添加关联时访问many_to_many连接表 - 2

    我正在使用Sequel构建一个愿望list系统。我有一个wishlists和itemstable和一个items_wishlists连接表(该名称是续集选择的名称)。items_wishlists表还有一个用于facebookid的额外列(因此我可以存储opengraph操作),这是一个NOTNULL列。我还有Wishlist和Item具有续集many_to_many关联的模型已建立。Wishlist类也有:selectmany_to_many关联的选项设置为select:[:items.*,:items_wishlists__facebook_action_id].有没有一种方法可以

  5. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

  6. Ruby——嵌套类和子类是一回事吗? - 2

    下面例子中的Nested和Child有什么区别?是否只是同一事物的不同语法?classParentclassNested...endendclassChild 最佳答案 不,它们是不同的。嵌套:Computer之外的“Processor”类只能作为Computer::Processor访问。嵌套为内部类(namespace)提供上下文。对于ruby​​解释器Computer和Computer::Processor只是两个独立的类。classComputerclassProcessor#Tocreateanobjectforthisc

  7. Ruby 文件 IO 定界符? - 2

    我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的

  8. ruby - 可以通过多少种方法将方法添加到 ruby​​ 对象? - 2

    当谈到运行时自省(introspection)和动态代码生成时,我认为ruby​​没有任何竞争对手,可能除了一些lisp方言。前几天,我正在做一些代码练习来探索ruby​​的动态功能,我开始想知道如何向现有对象添加方法。以下是我能想到的3种方法:obj=Object.new#addamethoddirectlydefobj.new_method...end#addamethodindirectlywiththesingletonclassclass这只是冰山一角,因为我还没有探索instance_eval、module_eval和define_method的各种组合。是否有在线/离线资

  9. ruby - 如何在 Ruby 中向现有方法定义添加语句 - 2

    我注意到类定义,如果我打开classMyClass,并在不覆盖的情况下添加一些东西我仍然得到了之前定义的原始方法。添加的新语句扩充了现有语句。但是对于方法定义,我仍然想要与类定义相同的行为,但是当我打开defmy_method时似乎,def中的现有语句和end被覆盖了,我需要重写一遍。那么有什么方法可以使方法定义的行为与定义相同,类似于super,但不一定是子类? 最佳答案 我想您正在寻找alias_method:classAalias_method:old_func,:funcdeffuncold_func#similartoca

  10. ruby-on-rails - 添加回形针新样式不影响旧上传的图像 - 2

    我有带有Logo图像的公司模型has_attached_file:logo我用他们的Logo创建了许多公司。现在,我需要添加新样式has_attached_file:logo,:styles=>{:small=>"30x15>",:medium=>"155x85>"}我是否应该重新上传所有旧数据以重新生成新样式?我不这么认为……或者有什么rake任务可以重新生成样式吗? 最佳答案 参见Thumbnail-Generation.如果rake任务不适合你,你应该能够在控制台中使用一个片段来调用重新处理!关于相关公司

随机推荐