iOS 7自定义后退按钮

iOS 7自定义后退按钮,ios,cocoa-touch,ios7,xcode5,Ios,Cocoa Touch,Ios7,Xcode5,我想使用自定义后退按钮。在iOS 6中,一切都很完美,但iOS 7却很奇怪 [[UIBarButtonItem appearance] setBackButtonBackgroundImage:[[UIImage imageNamed:@"back_button_normal"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 12.0, 0, 12.0)] forState:UIControlStateNormal barMetrics:UIBa

我想使用自定义后退按钮。在iOS 6中,一切都很完美,但iOS 7却很奇怪

[[UIBarButtonItem appearance] setBackButtonBackgroundImage:[[UIImage imageNamed:@"back_button_normal"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 12.0, 0, 12.0)] forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
首先,它没有iOS 7箭头和背景图像

(俄语地区)

然后,如果按下按钮,将显示背景图像。我还为
UIControlStateHighlighted
状态设置了背景图像,当按住按钮时,高亮显示的图像也会出现。按下任何后退按钮后,所有后退按钮都有背景图像

但是!如果显示模式视图控制器,请将其关闭,然后按下任何视图控制器-
ios7
箭头将出现在每个后退按钮上

我使用DP5。这是一个UIKit错误吗

PS我还尝试手动创建后退按钮,使用
UIBarButtonItem
,将背景图像设置为它,然后
self.navigationItem.backBarButtonItem=barButtonItem没有帮助。
然后我尝试将背景图像设置为禁用状态,并更改我的工具栏按钮项的enabled属性,但也没有帮助


这不是一个bug,这是iOS 7中
后退按钮的外观。例如:

您可能应该在应用程序中使用新概念,而不是在iOS 7中为后退按钮设置背景图像

如果您仍然希望后退按钮与iOS6中的相同,那么您可能应该手动创建这些后退按钮:

- (void)loadView
{
    [super loadView];

    UIButton *backButton = [[UIButton alloc] initWithFrame: CGRectMake(0, 0, 60.0f, 30.0f)];
    UIImage *backImage = [[UIImage imageNamed:@"back_button_normal.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 12.0f, 0, 12.0f)];
    [backButton setBackgroundImage:backImage  forState:UIControlStateNormal];
    [backButton setTitle:@"Back" forState:UIControlStateNormal];
    [backButton addTarget:self action:@selector(popBack) forControlEvents:UIControlEventTouchUpInside];
    UIBarButtonItem *backButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];
    self.navigationItem.leftBarButtonItem = backButtonItem;
}

-(void) popBack {
  [self.navigationController popViewControllerAnimated:YES];
}
编辑:不要打断滑动手势(

self.navigationController.interactiveepgpgestureerecognizer.delegate=(id)self;

第一次推送时未出现的自定义背景图像已在iOS 7 GM中修复

要隐藏标准背面指示器,请使用以下代码:

if ([UINavigationBar instancesRespondToSelector:@selector(setBackIndicatorImage:)]) { // iOS 7
    [navigationBarAppearance setBackIndicatorImage:[UIImage imageNamed:@"transparent_1px"]];
    [navigationBarAppearance setBackIndicatorTransitionMaskImage:[UIImage imageNamed:@"transparent_1px"]];
}

据我所知,最初没有出现的自定义背景图像在iOS7 GM或final中没有修复。我看到了同样的问题。这似乎是一个Apple错误;Apple使用的私有视图在初始显示时根本没有得到setNeedsDisplay调用。对它做任何导致调用的操作都应该修复它——就像pre一样打开它(这可能会更改内部状态,以便它自己调用setNeedsDisplay),或者打开一个模式(这可能会强制在下一个视图上重新显示整个视图层次结构:call)

使用leftBarItems也可以工作,但这可能会导致现有代码的许多维护问题(例如,一些屏幕可能有自己的左侧项,期望当设置回nil时,它们会恢复原始的back项)

如前所述,理想情况下,您可以在iOS7上更改为无边界外观,这意味着错误并不明显(因为没有背景图像)。但是对于某些iOS6/iOS7转换情况,这可能会很困难(很多屏幕,和/或需要支持较旧的iOS版本一段时间,很难实现两种外观,如果没有其他更改,它看起来就不好无边框)。如果是这样,以下补丁应该可以工作:

#import <objc/runtime.h>

@implementation UINavigationBar (BackButtonDisplayFix)

+ (void)load
{
    if ([UIDevice currentDevice].systemVersion.intValue >= 7)
    {
        /*
         * We first try to simply add an override version of didAddSubview: to the class.  If it
         * fails, that means that the class already has its own override implementation of the method
         * (which we are expecting in this case), so use a method-swap version instead.
         */
        Method didAddMethod = class_getInstanceMethod(self, @selector(_displaybugfixsuper_didAddSubview:));
        if (!class_addMethod(self, @selector(didAddSubview:),
                             method_getImplementation(didAddMethod),
                             method_getTypeEncoding(didAddMethod)))
        {
            Method existMethod = class_getInstanceMethod(self, @selector(didAddSubview:));
            Method replacement = class_getInstanceMethod(self, @selector(_displaybugfix_didAddSubview:));
            method_exchangeImplementations(existMethod, replacement);
        }
    }
}

- (void)_displaybugfixsuper_didAddSubview:(UIView *)subview
{
    [super didAddSubview:subview];
    [subview setNeedsDisplay];
}

- (void)_displaybugfix_didAddSubview:(UIView *)subview
{
    [self _displaybugfix_didAddSubview:subview]; // calls the existing method
    [subview setNeedsDisplay];
}

@end
#导入
@实现UINavigationBar(BackButtonDisplayFix)
+(空)荷载
{
如果([UIDevice currentDevice].systemVersion.intValue>=7)
{
/*
*我们首先尝试简单地向类添加didAddSubview:的覆盖版本
*失败,这意味着该类已经拥有自己的方法重写实现
*(我们在本例中希望如此),因此请改用方法交换版本。
*/
Method didAddMethod=class_getInstanceMethod(self,@selector(_displaybugfixsuper_didAddSubview:);
如果(!class_addMethod(self,@selector(didAddSubview:),
方法_getImplementation(didAddMethod),
方法\u getTypeEncoding(didAddMethod)))
{
方法existMethod=class_getInstanceMethod(self,@selector(didAddSubview:);
方法替换=class_getInstanceMethod(self,@selector(_displaybugfix_didAddSubview:);
方法交换实施(现有方法,替换);
}
}
}
-(无效)_displaybugfixsuper_didAddSubview:(UIView*)子视图
{
[超级添加子视图:子视图];
[子视图设置需要显示];
}
-(无效)\u displaybugfix\u didAddSubview:(UIView*)子视图
{
[self _displaybugfix_didAddSubview:subview];//调用现有方法
[子视图设置需要显示];
}
@结束
注意:UINavigationBar目前确实有一个对所讨论方法的覆盖,所以我希望使用方法交换实现风格。为了安全起见,我刚刚添加了其他东西,以防苹果更改其代码。我们自己可能会去无边界,但我确实发现这种方法可以作为一种选择(直到更彻底的UI升级)至少


附加说明:此错误似乎在iOS 7.1中已修复。因此,该修补程序可能被限制为仅在运行>=7.0和<7.1时安装这些方法。

在iOS 7中添加按钮作为导航项,如下所示

 UIButton *btnAdd = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 60, 30)];

        [btnAdd setContentMode:UIViewContentModeScaleAspectFit];

        [btnAdd setBackgroundImage:[UIImage imageNamed:@"back.png"] forState:UIControlStateNormal];

        [btnAdd addTarget:self action:@selector(backButtonPressed:) forControlEvents:UIControlEventTouchUpInside];

        UIBarButtonItem *btnAdd = [[UIBarButtonItem alloc] initWithCustomView:imView];

        self.navigationItem.rightBarButtonItem = btnAdd;

有一个更好的解决方案,它不涉及方法切换

您需要在应用程序中的某个位置添加UINavigationViewControllerDelegate方法

- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
dispatch_async(dispatch_get_main_queue(), ^{
    [[navigationController.navigationBar subviews] makeObjectsPerformSelector:@selector(setNeedsDisplay)];
});

}

我只是提供了与iOS6相同的行为(注意navigationBar是UINavigationBar),确保navigationBar有一个topItem

UINavigationItem *topItemNavigation = [navigationBar topItem];

UIBarButtonItem *barButtonTopItemNavigation = [[UIBarButtonItem alloc] initWithTitle:topItemNavigation.title style:UIBarButtonItemStyleBordered target:nil action:nil];

[barButtonTopItemNavigation setBackButtonBackgroundImage:YOUR_IMAGE_BACKGROUND forState:UIControlStateNormal barMetrics:UIBarMetricsDefault ];
            [topItemNavigation setBackBarButtonItem: barButtonTopItemNavigation];
        }

我的解决方案是在UINavigationItem上写一个类别。这是针对iOS7的

- (void)mdSetCustomBackButton:(UINavigationController *)navigationController
{
    MDBackButton *backButton = [[MDBackButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 44.0, 44.0) navigationController:navigationController];
    [backButton addTarget:self action:@selector(popBack:) forControlEvents:UIControlEventTouchUpInside];
    UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];
    [self setLeftBarButtonItem:barButtonItem];
    [navigationController.interactivePopGestureRecognizer setDelegate:(id<UIGestureRecognizerDelegate>)self];
}

- (void)popBack:(MDBackButton *)sender
{
    [sender.navigationController popViewControllerAnimated:YES];
}

我的解决方案适用于iOS 7及以上版本

首先,使默认的后退按钮不可见

self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil action:nil];
然后,使用自定义图像设置后退按钮的默认
backindicatormage

[UINavigationBar appearance].backIndicatorImage = [[UIImage imageNamed:@"topbar_icon_back_n.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
[UINavigationBar appearance].backIndicatorTransitionMaskImage = [[UIImage imageNamed:@"topbar_icon_back_p.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
此时,制作自定义的
UINavigationBar
,用于调整
的大小\u UINavigationBarBackIndicatorView
,其中包含上述
背景指示符号图像

const CGPoint SANavigationBarOffset = {-8, 11.5};

@implementation SANavigationBar

- (void)layoutSubviews
{
    [super layoutSubviews];

    // set back button position
    NSArray *classNamesToReposition = @[@"_UINavigationBarBackIndicatorView"];

    for (UIView *view in [self subviews]) {
        if ([classNamesToReposition containsObject:NSStringFromClass([view class])]) {
            CGRect frame = [view frame];
            frame.origin.x = 0;
            frame.origin.y = 0;

            [view setFrame:frame];
        }
    }
}

@end
然后,将其设置为我的导航栏

// set custom NavagationBar for back button position
[self.navigationController setValue:[[SANavigationBar alloc] init] forKey:@"navigationBar"];
这是我的工作:

- (void)setCustomNavigationBackButton
{    
  self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil action:nil];

  UIImage *myIcon = [self imageWithImage:[UIImage imageNamed:@"backbutton.png"] scaledToSize:CGSizeMake(20, 20)];

  self.navigationController.navigationBar.backIndicatorImage = myIcon;
  self.navigationController.navigationBar.backIndicatorTransitionMaskImage = myIcon;
}

- (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize 
{
  //UIGraphicsBeginImageContext(newSize);
  // In next line, pass 0.0 to use the current device's pixel scaling factor (and thus account for Retina resolution).
  // Pass 1.0 to force exact pixel size.
  UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0);
  [image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
  UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
  UIGraphicsEndImageContext();
  return newImage;
}
另外,使用自定义颜色的自定义字体:

//self.navigationController.navigationBar.tintColor = [UIColor whiteColor];

[[UIBarButtonItem appearanceWhenContainedIn:[UINavigationBar class], nil] setTitleTextAttributes:
 @{NSForegroundColorAttributeName:[UIColor whiteColor],
   NSFontAttributeName:[UIFont fontWithName:@"Signika-Bold" size:20]}

forState:UIControlStateNormal];

参考资料:

使用Swift,您只需添加一个扩展名:

extension UIViewController: UIGestureRecognizerDelegate {
    func popBack() {
        self.navigationController?.popViewControllerAnimated(true)
    }

    func enableCustomBackButtom() {
        self.navigationItem.leftBarButtonItem = UIBarButtonItem(image: UIImage(named: "icon-back"), style: UIBarButtonItemStyle.Plain, target: self, action:"popBack")

        self.navigationController?.interactivePopGestureRecognizer.delegate = self
    }
}
在UIViewController中,使用以下命令:

self.enableCustomBackButtom()
我用这些c
//self.navigationController.navigationBar.tintColor = [UIColor whiteColor];

[[UIBarButtonItem appearanceWhenContainedIn:[UINavigationBar class], nil] setTitleTextAttributes:
 @{NSForegroundColorAttributeName:[UIColor whiteColor],
   NSFontAttributeName:[UIFont fontWithName:@"Signika-Bold" size:20]}

forState:UIControlStateNormal];
extension UIViewController: UIGestureRecognizerDelegate {
    func popBack() {
        self.navigationController?.popViewControllerAnimated(true)
    }

    func enableCustomBackButtom() {
        self.navigationItem.leftBarButtonItem = UIBarButtonItem(image: UIImage(named: "icon-back"), style: UIBarButtonItemStyle.Plain, target: self, action:"popBack")

        self.navigationController?.interactivePopGestureRecognizer.delegate = self
    }
}
self.enableCustomBackButtom()
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.translatesAutoresizingMaskIntoConstraints = NO;
button.exclusiveTouch = YES;
button.titleLabel.font = [UIFont systemFontOfSize:14.0];
[button setTitleColor:kWhiteColor forState:UIControlStateNormal];
[button setTitleColor:[UIColor colorWithRed:1/255.0 green:36/255.0 blue:60/255.0 alpha:1.0] forState:UIControlStateHighlighted];
[button setTitle:@"Back" forState:UIControlStateNormal];
[button setImage:[UIImage imageNamed:@"barbutton_back"] forState:UIControlStateNormal];
[button setImageEdgeInsets:UIEdgeInsetsMake(1.0, 0.0, 0.0, 0.0)];
CGSize fontSize = [button.titleLabel sizeThatFits:CGSizeMake(100.0, 30.0)];
button.frame = CGRectMake(0.0, 0.0, button.imageView.image.size.width+fontSize.width, 30.0);
UIBarButtonItem *barbtn = [[UIBarButtonItem alloc] initWithCustomView:button];
//fix iOS 7 left margin
UIBarButtonItem *negativeSpacer = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
negativeSpacer.width = -10;
self.navigationItem.leftBarButtonItems = [NSArray arrayWithObjects:negativeSpacer,barbtn, nil];