カスタムの戻るボタンを使用したい。 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
状態に設定された背景画像があり、ボタンを押したままにすると、強調表示された画像も表示されます。戻るボタンを一度押すと、すべての戻るボタンに背景画像が表示されます。
しかし!モーダルView Controllerを表示する場合は、それを閉じてから、View Controllerをプッシュします-iOS 7
矢印は、戻るボタンごとに表示されます。
DP5を使用します。それはUIKitのバグですか?
PSまた、UIBarButtonItem
を使用してバックボタンを手動で作成し、背景画像を設定してからself.navigationItem.backBarButtonItem = barButtonItem;
助けにならなかった。次に、背景画像を無効状態に設定し、バーボタンアイテムの有効プロパティを変更しようとしましたが、あまり役に立ちませんでした。
これはバグではなく、この方法Back button
は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];
}
Edit:壊さないスワイプジェスチャ( ここにありますソース)
self.navigationController.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)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呼び出しを取得しません。その呼び出しを修正するために何かを行うと、その上で(内部状態を変更してsetNeedsDisplay自体を呼び出す可能性が高い)、またはモーダルを起動する(おそらく次のviewWillAppear:呼び出しでビュー階層全体の再表示を強制する).
代わりにleftBarItemsを使用しても動作しますが、既存のコードで多くのメンテナンスの問題が発生する可能性があります(一部の画面には独自の左アイテムがあり、nilに戻すと元のバックアイテムが復元されるなど)。
前述のように、理想的には、iOS7でボーダーレスの外観に変更できるようになります。つまり、背景画像がないため、バグは実際には明らかではありません。ただし、一部のiOS6/iOS7の移行状況では、それは難しい場合があります(多くの画面、および/またはしばらくの間古いiOSバージョンをサポートする必要があり、2つの外観を実装するには非常に困難であり、他なしでは見た目が良くありません)変更)。その場合は、次のパッチが機能するはずです。
#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には問題のメソッドがオーバーライドされているため、method_exchangeImplementationsスタイルが使用されることを期待しています。 Appleはコードを変更します。ボーダレスになるかもしれませんが、このアプローチはオプションとして機能することがわかりました(より徹底的なUIの向上まで)少なくとも。
追記:このバグはiOS 7.1で修正されたようです。そのため、パッチを条件付きにして、7.0以降および7.1以降を実行している場合にのみメソッドをインストールすることができます。
メソッドのスウィズリングを伴わないより良い解決策があります。
UINavigationViewControllerDelegateメソッドをアプリのどこかに追加する必要があります。
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
dispatch_async(dispatch_get_main_queue(), ^{
[[navigationController.navigationBar subviews] makeObjectsPerformSelector:@selector(setNeedsDisplay)];
});
}
私の解決策はiOS 7以上です。
最初に、デフォルトの戻るボタンを非表示にします。
self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil action:nil];
次に、カスタム画像を使用して、戻るボタンのデフォルトbackIndicatorImage
を設定します。
[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
を作成します_UINavigationBarBackIndicatorView
上記のbackIndicatorImage
を含む。
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
次に、それを私のnavigationBarとして設定します
// set custom NavagationBar for back button position
[self.navigationController setValue:[[SANavigationBar alloc] init] forKey:@"navigationBar"];
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()
以下のようにios7のナビゲーション項目としてボタンを追加
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;
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];
}
以下のコードを使用します。これはiOS 8で動作します
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];
私の解決策は、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];
}
また、UIButtonをサブクラス化してUINavigationControllerプロパティを追加します(スワイプバックデリゲートをポップして設定します)。
@property (nonatomic, weak) UINavigationController *navigationController;
@implementation MDBackButton
- (id)initWithFrame:(CGRect)frame navigationController:(UINavigationController *)navigationController
{
self = [super initWithFrame:frame];
if(self){
_navigationController = navigationController;
[self setImage:[UIImage imageNamed:@"back_button"] forState:UIControlStateNormal];
}
return self;
}
これは私の仕事です:
- (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];