【问题标题】:Add customview in navigation bar like whatsapp在导航栏中添加自定义视图,如whatsapp
【发布时间】:2019-03-25 11:13:14
【问题描述】:

我想创建自定义导航栏,就像 WhatsApp 用来在应用程序中显示呼叫指示器一样,​​如下所示。

我已成功添加上述视图,但它没有响应,因为我无法检测到状态栏上的触摸。我只能触摸“触摸返回通话”下方的部分。

代码如下。

@property (nonatomic) UIView *navigationBarTopView;

UIWindow *window = [UIApplication sharedApplication].keyWindow;
if (_navigationBarTopView == nil) {
    _navigationBarTopView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, window.frame.size.width, 60.0)];
        [_navigationBarTopView setBackgroundColor:[UIColor colorWithRed:76.0/255.0 green:217.0/255.0 blue:100.0/255.0 alpha:1]];

    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, _navigationBarTopView.frame.size.height - 15, window.frame.size.width, 10)];
    [label setText:@"Touch to return to call"];
    [label setTextColor:[UIColor whiteColor]];
    [label setFont:[UIFont preferredFontForTextStyle:UIFontTextStyleFootnote]];
    [label setTextAlignment:NSTextAlignmentCenter];
    [_navigationBarTopView addSubview:label];

    //The setup code (in viewDidLoad in your view controller)
    UITapGestureRecognizer *singleFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)];
    [_navigationBarTopView addGestureRecognizer:singleFingerTap];

    UITapGestureRecognizer *singleFingerTap1 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)];
    [label addGestureRecognizer:singleFingerTap1];
}

[window addSubview:_navigationBarTopView];

我也尝试在状态栏上添加触摸,如下所示,但它不起作用。

How do I detect touches on UIStatusBar/iPhone

导航栏也没有下降。我试图设置keyWindow 框架。但这也行不通。

【问题讨论】:

  • 你确定这不是系统call bar
  • 试试这个[self.navigationController.view addSubview: _navigationBarTopView];
  • 是系统生成的导航栏。它会在与任何人通话时自动出现。通话可以是普通电话或VoIP(由SDK管理)。如果需要,您可以向导航栏添加自定义视图。
  • 它是苹果提供的默认行为,如果您想创建相同的行为,例如将子视图添加到顶部视图控制器上的 navigationController.view
  • @iMHiteshSurani 我没有将它放入应用程序。我已经为此实现了 Twilio Voice SDK。所以我创建了自定义视图并将其添加为屏幕顶部的 UIWindow。

标签: ios uinavigationbar custom-view uistatusbar


【解决方案1】:

UIStatusBar 的优先级高于应用程序的窗口,因此您不会通过状态栏获得任何触摸事件。

要通过状态栏获取触摸事件,您需要一个窗口级别高于 UIStatusBar 的窗口。

试试下面的代码:

#import "AppDelegate.h"

@interface AppDelegate ()

@property (nonatomic) UIWindow *buttonWindow;
@property (nonatomic) UIWindow *textWindow;
@property (nonatomic) CGFloat callViewHeight;

@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
        if (@available(iOS 11.0, *)) {
        if (([[[UIApplication sharedApplication] delegate] window].safeAreaInsets.top > 20.0)) {
            self.callViewHeight = 55.0f;
        } else {
            self.callViewHeight = 35.0f;
        }
    } else {
        self.callViewHeight = 35.0f;
    }
    return YES;
}

-(void)showVideoCallButton{
    self.textWindow = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, self.callViewHeight)];
    self.textWindow.windowLevel = self.window.windowLevel + 1;
    self.textWindow.hidden = FALSE;

    UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, self.callViewHeight)];
    view.backgroundColor = [UIColor colorWithRed:76.0/255.0 green:217.0/255.0 blue:100.0/255.0 alpha:1];
    view.clipsToBounds = TRUE;
    UILabel *lblName = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, self.callViewHeight)];
    lblName.textAlignment = NSTextAlignmentCenter;
    [lblName setFont:[UIFont preferredFontForTextStyle:UIFontTextStyleFootnote]];
    lblName.text = @"";

    UILabel *lblTouch = [[UILabel alloc] initWithFrame:CGRectMake(0, self.callViewHeight - 20.0f, [UIScreen mainScreen].bounds.size.width, 20.0f)];
    lblTouch.textAlignment = NSTextAlignmentCenter;
    [lblTouch setFont:[UIFont preferredFontForTextStyle:UIFontTextStyleFootnote]];
    lblTouch.text = @"Touch to return to call";
    lblTouch.textColor = UIColor.whiteColor;

    [view addSubview:lblTouch];
    [view addSubview:lblName];

    [self.textWindow addSubview:view];

    self.buttonWindow = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, self.callViewHeight)];
    self.buttonWindow.windowLevel = UIWindowLevelStatusBar + 1;
    self.buttonWindow.hidden = FALSE;

    UIButton *button = [[UIButton alloc] initWithFrame:lblName.bounds];
    [button setTitle:@"" forState:UIControlStateNormal];
    [button addTarget:self action:@selector(buttonTouched) forControlEvents:UIControlEventTouchUpInside];
    [self.buttonWindow addSubview:button];

    self.textWindow.transform = CGAffineTransformMakeTranslation(0, -self.callViewHeight);
    self.buttonWindow.transform = CGAffineTransformMakeTranslation(0, -self.callViewHeight);

    [UIView animateWithDuration:0.25
                     animations:^{
                         self.textWindow.transform = CGAffineTransformIdentity;
                         self.buttonWindow.transform = CGAffineTransformIdentity;
                         if (@available(iOS 11.0, *)) {
                             if (([[[UIApplication sharedApplication] delegate] window].safeAreaInsets.top > 20.0)) {
                                 self.window.frame = CGRectMake(0, self.callViewHeight - 40.0f, self.window.bounds.size.width, self.window.bounds.size.height - self.callViewHeight + 40.0f);
                             } else {
                                 self.window.frame = CGRectMake(0, self.callViewHeight - 20.0f, self.window.bounds.size.width, self.window.bounds.size.height - self.callViewHeight + 20.0f);
                             }
                         } else {
                             self.window.frame = CGRectMake(0, self.callViewHeight - 20.0f, self.window.bounds.size.width, self.window.bounds.size.height - self.callViewHeight + 20.0f);
                         }
                     }];
}

-(void)hideVideoCallButton{

    [UIView animateWithDuration:0.25
                     animations:^{
                         self.textWindow.transform = CGAffineTransformMakeTranslation(0, -self.callViewHeight);
                         self.buttonWindow.transform = CGAffineTransformMakeTranslation(0, -self.callViewHeight);
                         self.window.frame = [UIScreen mainScreen].bounds;
                     } completion:^(BOOL finished) {

                         dispatch_async(dispatch_get_main_queue(), ^{
                             self.buttonWindow.hidden = TRUE;
                             self.buttonWindow = nil;

                             self.textWindow.hidden = TRUE;
                             self.textWindow = nil;
                         });

                     }];
}

-(void)buttonTouched{
    NSLog(@"Button Touched");
}

@end

【讨论】:

  • 感谢@iDhaval 这个解决方案有效。我进行了一些更改以使其与 iPhone X+ 设备兼容。
  • 你好,请问有什么快速的解决方案吗?
  • @iDhaval,我试过了,它在 xcode 11.6 中不起作用
  • @swift2geek 你遇到了什么问题?
【解决方案2】:

我也在 singleViewcontroller 和 UITabbar Controller 中尝试过,我附加的示例项目here,对于状态栏点击操作我遵循Flar answer

 - (void)viewDidLoad {
[super viewDidLoad];

dispatch_async(dispatch_get_main_queue(), ^(void){
    //Run UI Updates
     [self createDummyView];
});


}

 -(void)createDummyView{

if (_navigationBarTopView == nil) {
     float statusBarHeight = [self statusBarHeight];
    CGFloat width = [UIScreen mainScreen].bounds.size.width;

    _navigationBarTopView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, width, self.navigationController.navigationBar.frame.size.height +  statusBarHeight)];
    [_navigationBarTopView setBackgroundColor:[UIColor colorWithRed:76.0/255.0 green:217.0/255.0 blue:100.0/255.0 alpha:1]];

    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, _navigationBarTopView.frame.size.height - 15,width, 10)];
    [label setText:@"Touch to return to call"];
    [label setTextColor:[UIColor whiteColor]];
    [label setFont:[UIFont preferredFontForTextStyle:UIFontTextStyleFootnote]];
    [label setTextAlignment:NSTextAlignmentCenter];
    [label setUserInteractionEnabled:YES];
    [_navigationBarTopView addSubview:label];

    UITapGestureRecognizer *singleFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)];
    [_navigationBarTopView addGestureRecognizer:singleFingerTap];

    [self.navigationController.view addSubview:_navigationBarTopView];


}


-(float) statusBarHeight
{
CGSize statusBarSize = [[UIApplication sharedApplication] statusBarFrame].size;
return MIN(statusBarSize.width, statusBarSize.height);
}

-(void)handleSingleTap:(UITapGestureRecognizer*)recognizer{
NSLog(@"recognizer == %@", recognizer.view.tag);
}

【讨论】:

  • 仅供参考:具有安全区域可用呼叫功能的设备不像非安全区域设备那样工作。它将在状态栏中显示一个小的呼叫图标
  • @Anbu.Karthik 我已经实现了此代码,但使用该代码我无法触及状态栏。我也有复杂的结构,它包含一个标签栏和 4 个导航栏控制器。所以在应用中管理起来非常困难。
  • 要在状态栏上设置触摸事件,我正在使用此解决方案。但它不适用于标签栏。 stackoverflow.com/questions/2470562/… 它适用于单视图控制器。
  • 请同样使用这个库。我知道,也许需要进行一些定制,但它易于使用且收视率很高。 github.com/huri000/SwiftEntryKit
  • @JayeshSojitra - 我更新了答案,它也适用于单视图控制器和 UITabbar 控制器,请检查
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-14
  • 1970-01-01
  • 2021-09-19
  • 1970-01-01
  • 2011-08-21
相关资源
最近更新 更多