在UINavigationBar上设置自定义返回按钮图片

14

我试图为后退按钮设置一个自定义图片,当新视图被推入堆栈时,它会自动放置在导航栏上。

我已经尝试在父视图控制器的viewDidLoad中添加以下内容:

[[UIBarButtonItem appearance] setBackButtonBackgroundImage:[UIImage imageNamed:@"BackButton.png"] forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];

我也尝试了以下方法:

UIBarButtonItem *btn = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"BackButton.png"] style:UIBarButtonItemStyleBordered target:nil action:nil];
    self.navigationItem.backBarButtonItem = btn;

使用UIAppearance会产生相当奇怪的结果: 返回按钮的图像似乎被放置在原始标题下方


除了每次都要这样做之外,backBarButtonItem方法成功了吗? - Brian Nickel
不,两种方法都没有成功。我最终不得不采用一种hacky的方式,隐藏返回按钮,然后设置一个标准按钮并弹出堆栈中的视图。这并不理想。 - Paul Morris
嗯...你可以尝试将返回按钮文本设置为@" ",或者在使用第一种方法的同时将返回按钮文本颜色设置为透明。 - Brian Nickel
这看起来像是你创建的返回按钮已经有文本了...如果是这样的话...方法是错误的...iOS会扩展按钮以适应返回按钮文本,并在其上放置文本。 - Heavy_Bullets
8个回答

37

试试这段代码

UIButton *backBtn = [UIButton buttonWithType:UIButtonTypeCustom];  
UIImage *backBtnImage = [UIImage imageNamed:@"BackBtn.png"]  ;  
[backBtn setBackgroundImage:backBtnImage forState:UIControlStateNormal];  
[backBtn addTarget:self action:@selector(goback) forControlEvents:UIControlEventTouchUpInside];  
backBtn.frame = CGRectMake(0, 0, 54, 30);  
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithCustomView:backBtn] ;  
self.navigationItem.leftBarButtonItem = backButton;

然后像这样定义 goback 方法

- (void)goback
{
    [self.navigationController popViewControllerAnimated:YES];
}

这基本上就是我作为解决方法所做的。我隐藏了返回按钮并使用leftBarButton来显示我的自定义图像,然后将视图从堆栈中弹出。虽然这不是理想的解决方案。 - Paul Morris
这是经过测试的代码,我在许多应用程序中使用它,请尝试复制并粘贴我的代码,有可能您做错了什么,请再次检查一下。 - Piyush Kashyap
我的代码有点不同,因为我用自定义视图(即UIButton)初始化了UIBarButtonItem。 - Piyush Kashyap
我并不是说这段代码有错。我已经采用了同样的方法。我的意思是,这并不是真正的/正确/做法,因为iOS 5有一个UIApperance属性可以设置自定义图像作为返回按钮。 - Paul Morris
好的,没错,IOS 5有不同的方法来设置返回按钮的图像,但他们并没有说你不能自己创建一个返回按钮,所以我认为你也可以使用那段代码 :) - Piyush Kashyap

29

自 iOS 7.0 起,API 中有一个新的方法 backIndicatorImage。如果您不想将图像拉伸以适应文本(例如,如果您想要一个固定大小的自定义返回箭头),则可以使用它来替代 setBackButtonBackgroundImage。下面是一个示例(Swift):

let image = UIImage(named: "back_button")
    
UINavigationBar.appearance().backIndicatorImage = image
UINavigationBar.appearance().backIndicatorTransitionMaskImage = image

您可以使用这个技巧隐藏按钮中的文本:

UIBarButtonItem.appearance().setBackButtonTitlePositionAdjustment(UIOffsetMake(0, -66), for: .default)

适用于Swift 5:

var backButtonImage = UIImage(named: "back_button")

backButtonImage = backButtonImage?.stretchableImage(withLeftCapWidth: 15, topCapHeight: 30) UIBarButtonItem.appearance().setBackButtonBackgroundImage(backButtonImage, for: .normal, barMetrics: .default)


您还可以在StoryBoard上隐藏文本,在执行segue(push)的控制器中,您可以将NavigationBar的返回按钮标题设置为空格(" "不带引号)(属性在属性检查器上)。 - José Roberto Abreu
如何让图片适应大小?现在我得到的是一个不太适合的大图像... - Sylvan D Ash

23

这是我在自己的iOS 5应用中使用的代码,运行完美。这段代码来自于应用委托中的application:didFinishLaunchingWithOptions:方法:

UIImage * backButtonImage = [UIImage imageNamed: @"back-button-image"];
backButtonImage = [backButtonImage stretchableImageWithLeftCapWidth: 15.0 topCapHeight: 30.0];
[[UIBarButtonItem appearance] setBackButtonBackgroundImage: backButtonImage forState: UIControlStateNormal barMetrics: UIBarMetricsDefault];

你可能需要使用可拉伸图片,其中左边的“点”是左端点


或者在Swift中

let backButtonImage = UIImage(named: "back-button-image")
backButtonImage = backButtonImage?.stretchableImageWithLeftCapWidth(15, topCapHeight: 30)
UIBarButtonItem.appearance().setBackButtonBackgroundImage(backButtonImage, forState: .Normal, barMetrics: .Default)

使用backButtonImage = [backButtonImage resizableImageWithCapInsets:UIEdgeInsetsZero]; 替代stretchableImageWithLeftCapWidth方法,因为该方法已被弃用。 - Ramis

5

iOS 8+ 版本的 Swift(可以很容易地转换为 ObjC)。这种方法保留了与标准返回按钮相关的导航栏所有优点和行为(推入/弹出时的动画,交互式弹出手势等)

// Call the code ONE TIME somewhere on app launch to setup custom back button appearance
UINavigationBar.appearance().tintColor = UIColor.blackColor()
// If you need custom positioning for your back button, in this example button will be 1 px up compared to default one
// Also only vertical positioning works, for horizontal add offsets directly to the image
let backImageInsets = UIEdgeInsetsMake(0, 0, -1, 0)
// Get image, change of rendering (so it preserves offsets made in file), applying offsets
let backImage = UIImage(named: "YourButtonImageAssetFileName")?.imageWithRenderingMode(.AlwaysOriginal).imageWithAlignmentRectInsets(backImageInsets)
// Setting images
UINavigationBar.appearance().backIndicatorImage = backImage
UINavigationBar.appearance().backIndicatorTransitionMaskImage = backImage

// Call EACH TIME BEFORE pushing view controller if you don't need title near your back button arrow
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .Plain, target: nil, action: nil)
// Push controller
self.navigationController?.pushViewController(vc, animated: true)

3

尝试下面的代码,这对我有效:

[[UINavigationBar appearance] setBackIndicatorImage:[UIImage imageNamed:@"back-button-image"]];
[[UINavigationBar appearance] setBackIndicatorTransitionMaskImage:[UIImage imageNamed:@"back-button-image"]];

2

这段代码适用于 Swift 5XCode 10

将以下代码添加到AppDelegate的func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool中,以应用于您所有的视图控制器:

//Custom back button
    let barButtonItemAppearance = UIBarButtonItem.appearance()
    barButtonItemAppearance.setTitleTextAttributes([NSAttributedStringKey.foregroundColor: UIColor.clear], for: .normal)
    barButtonItemAppearance.setTitleTextAttributes([NSAttributedStringKey.foregroundColor: UIColor.clear], for: .highlighted)
    let backImg: UIImage = UIImage(named: "back")!
    barButtonItemAppearance.setBackButtonBackgroundImage(backImg, for: .normal, barMetrics: .default)

    let image = UIImage()

    UINavigationBar.appearance().backIndicatorImage = image
    UINavigationBar.appearance().backIndicatorTransitionMaskImage = image

2
将此方法编写在通用类中,并从您想要绘制的控制器中调用它。"
(UIButton *)drawNavigationBarBackButton:(UIViewController*)viewController 
{

    UIImage *navBackImage = nil;

    UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom];
     navBackImage = [UIImage imageNamed:@"Back_Button"];

    [backButton setImage:navBackImage forState:UIControlStateNormal];
    UIBarButtonItem *leftButton = [[UIBarButtonItem alloc] initWithCustomView:backButton];
    viewController.navigationItem.leftBarButtonItem = leftButton;

    return backButton;
}



call from controller class and setting action

- (void)viewDidLoad {

[super viewDidLoad];

 UIButton *backButton = [CommonClass drawNavigationBarBackButton:self];
    [backButton addTarget:self action:@selector(onTapBackButton) forControlEvents:UIControlEventTouchUpInside];
}

- (void)onTapBackButton 
{
    [self.navigationController popViewControllerAnimated:YES];
}

1
这对我有用:

这对我有用:

let button1 = UIBarButtonItem(
    image: #imageLiteral(resourceName: "back_arrow"), 
    style: .plain, 
    target: self, 
    action: #selector(self.backBtnTapped(_:))
)
self.navigationItem.leftBarButtonItem  = button1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接