蓝条下压产生问题的本质原因是,热点出现时系统状态栏高度增加了20个像素,当热点消失时,系统状态栏高度变为标准的20个高度。
理论上只需捕获到系统状态栏变更通知(UIApplicationWillChangeStatusBarFrameNotification这个通知我找了20多天才无意找到),找到自定义工具栏(手写实现或xib自动布局实现)的中心点上移和下移20个像素就可以解决。至于ios7.0以下的蓝条下压产生的页面布局变化就不再适配了,现在的应用最低支持的都是ios7.0了。
实际上解决起来没有那么简单,这只能保证部分全手写控件的蓝条下压和消失控件位置错乱,自动布局控件会有很多莫明奇妙的问题。
修改的方法:
1. 在系统状态栏改变后,调整自定义手写工具栏的中心点(注意若有热点,用户去设置页面并返回原页面,原页面控制器会收到两次状态栏改变通知,第一次带热点的状态栏消失通知,第二次是带热点的状态栏出现通知)。
2. 在系统状态栏改变后,有些调整自定义xib自动布局实现的工具栏中心点,注意有的自动布局控件的最外层承载view上线留有空白,调整的高度可能大于或小于20个像素。
3. 控件出现时要根据是否有蓝条来,对控件frame进行调整。
4. 对于自定义xib自动布局控件,并且是在控件的代理函数调整高度的,注意要在页面首次加载是根据是否有蓝条,调整默认初始化位置(若是自定义xib自动布局控件在viewDidAppear或viewWillAppear显示的加载一次,在用时才加载,那么在iphone6上会显示不出来。)。
蓝条下压导致控件异常的共有四种类型:
1. 普通代码实现控件,车辆类型选择控件。
2. 代码实现控件通过页面种的滑动事件触发调整控件frame,紫色的滑动工具条。
3. 自定义xib控件通过在主页面的滑动按钮事件调整控件frame,白色费用显示工具条。
4. 自定义xib控件通过控件自身的代理函数调整frame,黄色可下拉新的预约单列表显示页面。
测试用例共有六个,不同的场景测试出来的结果截然不同,只有搞定这四个测试用例才能算修改好。
1, 启动应用时有蓝条,在本页面蓝条消失和再次出现,控件位置不能变。
2, 启动应用时没有蓝条,在本页面蓝条出现和消失,控件位置不能变。
3, 启动应用时有蓝条,经过本页面条道其它页面,蓝条消失,再回到本页面,控件位置不能变。
4, 启动应用时没有蓝条,经过本页面条道其它页面,蓝条出现后跳到本页面,控件位置不能变。
5,启动应用时没有蓝条,启动成功,出现蓝条,然后又新的自定义的工具条(xib实现的工具条)出现在顶部。
6,启动应用时有蓝条,控件位置根据是否有蓝条自动调整。
对于车辆类型选择控件,是标准的手写控件,当点击是修改控件的中心点来实现类型的选择按钮的出现和消失。这个控件对栏条下压的适配很简单。
注意若是启动应用时有蓝条,那么你就不能立刻收到状态栏改变通知,需要在加载控件时根据是否有蓝条直接调整控件的初始高度。
- (void)initSelectView { selectView.frame = CGRectMake(0, kControlHeight - 26 - [self handleUIApplicationStatusBarFrame], kControlWidth, 100); [self.view addSubview:selectView]; } -(NSInteger)handleUIApplicationStatusBarFrame { FLDDLogDebug(@"函数"); // 根据系统状态栏高判断热点栏的变动 BOOL bPersonalHotspotConnected = ([UIApplication sharedApplication].statusBarFrame.size.height==(SYS_STATUSBAR_HEIGHT+HOTSPOT_STATUSBAR_HEIGHT)?YES:NO); if(bPersonalHotspotConnected) { return HOTSPOT_STATUSBAR_HEIGHT; } else { return 0; } }
只需要处理当控件是调整控件的初始位置,处理当收到系统状态改变通知时太哦正控件的中心点就可以,对点击按钮时改变控件位置时适配蓝条就可以。
代码:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleUIApplicationWillChangeStatusBarFrameNotification:)
name:UIApplicationWillChangeStatusBarFrameNotification
object:nil]; //清除车辆选择信息通知
(void)ShowBottomSlideView:(UIButton *)sender
{
FLDDLogDebug(@”函数”);
if (NO == _isShow)
{
[UIView animateWithDuration:0.5 animations:^{ CGRect rectView = _slideView.frame; if(IS_HOTSPOT_CONNECTED) { rectView.origin.y = kControlHeight - 110 - HOTSPOT_STATUSBAR_HEIGHT; _slideView.frame = rectView; } else { rectView.origin.y = kControlHeight - 110; _slideView.frame = rectView; } } completion:^(BOOL finished) { [sender setBackgroundImage:[UIImage imageNamed:@"接单下拉条"] forState:UIControlStateNormal]; }];
}
else
{
[UIView animateWithDuration:0.5 animations:^{
CGRect rectView = _slideView.frame;
if(IS_HOTSPOT_CONNECTED)
{
rectView.origin.y = kControlHeight -26 - HOTSPOT_STATUSBAR_HEIGHT;
_slideView.frame = rectView;
}
else
{
rectView.origin.y = kControlHeight -26;
_slideView.frame = rectView;
}
} completion:^(BOOL finished) {
[sender setBackgroundImage:[UIImage imageNamed:@"接单上拉条"] forState:UIControlStateNormal]; }];
}
_isShow = !_isShow;
}
(void)handleUIApplicationWillChangeStatusBarFrameNotification:(NSNotification*)notification
{
FLDDLogDebug(@”函数”);
CGRect newStatusBarFrame = [(NSValue*)[notification.userInfo objectForKey:UIApplicationStatusBarFrameUserInfoKey] CGRectValue];
// 根据系统状态栏高判断热点栏的变动
BOOL bPersonalHotspotConnected = (CGRectGetHeight(newStatusBarFrame)==(SYS_STATUSBAR_HEIGHT+HOTSPOT_STATUSBAR_HEIGHT)?YES:NO);
CGPoint newCenter = CGPointZero;
CGFloat OffsetY = bPersonalHotspotConnected?+HOTSPOT_STATUSBAR_HEIGHT:-HOTSPOT_STATUSBAR_HEIGHT;
newCenter = _slideView.center;
if(bPersonalHotspotConnected)
{
if(kControlHeight - 26 + 110/2 == newCenter.y)
{
OffsetY = HOTSPOT_STATUSBAR_HEIGHT;
newCenter.y -= OffsetY;
_slideView.center = newCenter;
}
else if(kControlHeight - 110 + 110/2 == newCenter.y)
{
OffsetY = HOTSPOT_STATUSBAR_HEIGHT;
newCenter.y -= OffsetY;
_slideView.center = newCenter;
}
}
else
{
if(kControlHeight - 110 - HOTSPOT_STATUSBAR_HEIGHT + 110/2 == newCenter.y)
{
newCenter.y = kControlHeight - 110 + 110/2;
_slideView.center = newCenter;
}
else if(kControlHeight - 26 + 110/2 != newCenter.y)
{
newCenter.y = kControlHeight - 26 + 110/2;
_slideView.center = newCenter;
}
}
}
(void)hiddenBottomSlideView:(UIButton *)sender
{
FLDDLogDebug(@”函数”);
if (_isShow)
{
CGRect rectView = _slideView.frame;
rectView.origin.y = kControlHeight -26;
_slideView.frame = rectView;
[sender setBackgroundImage:[UIImage imageNamed:@”接单上拉条”] forState:UIControlStateNormal];
// [UIView animateWithDuration:0.5 animations:^{
// CGRect rectView = _slideView.frame;
// rectView.origin.y = kControlHeight -26;
// _slideView.frame = rectView;
// } completion:^(BOOL finished) {
//
// [sender setBackgroundImage:[UIImage imageNamed:@”接单上拉条”] forState:UIControlStateNormal];
// }];
_isShow = !_isShow;
}
}
(void)initWithBottomSlideView
{
FLDDLogDebug(@”函数”);
if(IS_HOTSPOT_CONNECTED)
{
_slideView = [[UIView alloc] initWithFrame:CGRectMake(0, kControlHeight - 26 - HOTSPOT_STATUSBAR_HEIGHT, kControlWidth, 110)];
}
else
{
_slideView = [[UIView alloc] initWithFrame:CGRectMake(0, kControlHeight - 26, kControlWidth, 110)];
}
}
对于自定义xib代理实现控件页面位置改变的控件,对蓝条适配要多一个在加载时的控件初始化位置适配:
(void)viewDidAppear:(BOOL)animated
{
FLDDLogDebug(@”函数”);
[super viewDidAppear:YES];
_mapView.frame = CGRectMake(0, 0, kControlWidth, kControlHeight);
_mapView.delegate = self;
_mapView.customizeUserLocationAccuracyCircleRepresentation = NO;
_mapView.showsUserLocation = YES;
if (!_viewDidApper)
{
_viewDidApper = YES;
noticecarview.frame = CGRectMake(0, 0, kControlWidth, kControlHeight); servicingView.frame=CGRectMake(0, -200, kControlWidth, 178); if(IS_HOTSPOT_CONNECTED) { _bookingButtonView.frame = CGRectMake(0, 0, kControlWidth, 40);
// self.center = CGPointMake(kControlWidth / 2, 84 - HOTSPOT_STATUSBAR_HEIGHT + 20);
}
else
{
_bookingButtonView.frame = CGRectMake(0, HOTSPOT_STATUSBAR_HEIGHT, kControlWidth, 40);
// self.center = CGPointMake(kControlWidth / 2, 84);
}
_priceView.frame = CGRectMake(0, kControlHeight + 100, kControlWidth, 50);
}
}
其它的自定位手写紫色工具条和自动定义xib自动布局白色费用工具条,黄色预约单工具条对蓝条匹配的代码:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleUIApplicationWillChangeStatusBarFrameNotification:)
name:UIApplicationWillChangeStatusBarFrameNotification
object:nil];
(void)handleUIApplicationWillChangeStatusBarFrameNotification:(NSNotification*)notification
{
FLDDLogDebug(@”函数”);
CGRect newStatusBarFrame = [(NSValue*)[notification.userInfo objectForKey:UIApplicationStatusBarFrameUserInfoKey] CGRectValue];
// 根据系统状态栏高判断热点栏的变动
BOOL bPersonalHotspotConnected = (CGRectGetHeight(newStatusBarFrame)==(SYS_STATUSBAR_HEIGHT+HOTSPOT_STATUSBAR_HEIGHT)?YES:NO);
CGPoint newCenter = CGPointZero;
CGFloat OffsetY = bPersonalHotspotConnected?+HOTSPOT_STATUSBAR_HEIGHT:-HOTSPOT_STATUSBAR_HEIGHT;
newCenter = bottomView.center;
if(bPersonalHotspotConnected)
{
if(kControlHeight-27.5 == newCenter.y)
{
OffsetY = HOTSPOT_STATUSBAR_HEIGHT;
newCenter.y -= OffsetY;
bottomView.center = newCenter;
}
newCenter = _priceView.center; if(!(_priceView.hidden)) { if(MAP_VIEW_MAIN == [Singleton sharedInstance].mapViewPage) { newCenter.y = kControlHeight - 75 - HOTSPOT_STATUSBAR_HEIGHT + 14; } else { newCenter.y = kControlHeight - 75 - HOTSPOT_STATUSBAR_HEIGHT; } _priceView.center = newCenter; }
// if(_bookingButtonView.getBookShowFlag)
// {
// if(MAP_VIEW_MAIN == [Singleton sharedInstance].mapViewPage)
// {
// _bookingButtonView.center = CGPointMake(kControlWidth / 2, 84 - HOTSPOT_STATUSBAR_HEIGHT + 20);
// }
// else
// {
// _bookingButtonView.center = CGPointMake(kControlWidth / 2, 84);
// }
// }
}
else
{
if(kControlHeight-27.5 - HOTSPOT_STATUSBAR_HEIGHT == newCenter.y)
{
newCenter.y = kControlHeight-27.5;
bottomView.center = newCenter;
}
newCenter = _priceView.center;
if(!(_priceView.hidden))
{
newCenter.y = kControlHeight-75 - HOTSPOT_STATUSBAR_HEIGHT;
_priceView.center = newCenter;
}
// if(_bookingButtonView.getBookShowFlag)
// {
// _bookingButtonView.center = CGPointMake(kControlWidth / 2, 84);
// }
}
}
//滑动动画
-(void)startSlideAnination
{
FLDDLogDebug(@”函数”);
[UIView animateWithDuration:0.5 animations:^{
// bottomView.frame = CGRectMake(bottomView.frame.origin.x, kControlHeight-100, bottomView.frame.size.width, bottomView.frame.size.height);
if(IS_HOTSPOT_CONNECTED)
{
bottomView.center = CGPointMake(kControlWidth/2,kControlHeight-27.5 - HOTSPOT_STATUSBAR_HEIGHT);
_priceView.center=CGPointMake(kControlWidth/2,kControlHeight-75 - HOTSPOT_STATUSBAR_HEIGHT);
// _priceView.center=CGPointMake(kControlWidth/2,kControlHeight-75);
}
else
{
bottomView.center = CGPointMake(kControlWidth/2,kControlHeight-27.5);
_priceView.center=CGPointMake(kControlWidth/2,kControlHeight-75);
// _priceView.center=CGPointMake(kControlWidth/2,kControlHeight);
}
if((-1 != [GlobalShare getGlobalShare].user.servicingOrderId) && (GETIN == [_orderDict[@”orderStatus”] integerValue]))
{
_priceView.hidden = NO;
}
bottomView.hidden = NO;
// bottomV iew.center=CGPointMake(kControlWidth/2,kControlHeight-27.5);
// _priceView.center=CGPointMake(kControlWidth/2,kControlHeight-75);
[slideImageView startAnimating]; } completion:^(BOOL finished) {
// if(NETWORK_TYPE_WIFI == [self getNetworkTypeFromStatusBar])
// {
// [SVProgressHUD showErrorWithStatus:@”手机自动连接WiFi网络时,会导致行程费用计算不准确,为减少损失,请关闭WiFi”];
// }
// else
// {
// [SVProgressHUD dismiss];
// }
}];
}
蓝条下压问题相关宏定义:
//系统状态栏相关声明
// iOS系统版本
define SYSTEM_VERSION [[[UIDevice currentDevice] systemVersion] doubleValue]
// 标准系统状态栏高度
define SYS_STATUSBAR_HEIGHT 20
// 热点栏高度
define HOTSPOT_STATUSBAR_HEIGHT 20
// 导航栏(UINavigationController.UINavigationBar)高度
define NAVIGATIONBAR_HEIGHT 44
// 工具栏(UINavigationController.UIToolbar)高度
define TOOLBAR_HEIGHT 44
// 标签栏(UITabBarController.UITabBar)高度
define TABBAR_HEIGHT 44
// APP_STATUSBAR_HEIGHT=SYS_STATUSBAR_HEIGHT+[HOTSPOT_STATUSBAR_HEIGHT]
define APP_STATUSBAR_HEIGHT (CGRectGetHeight([UIApplication sharedApplication].statusBarFrame))
// 根据APP_STATUSBAR_HEIGHT判断是否存在热点栏
define IS_HOTSPOT_CONNECTED (APP_STATUSBAR_HEIGHT==(SYS_STATUSBAR_HEIGHT+HOTSPOT_STATUSBAR_HEIGHT)?YES:NO)
// 无热点栏时,标准系统状态栏高度+导航栏高度
define NORMAL_STATUS_AND_NAV_BAR_HEIGHT (SYS_STATUSBAR_HEIGHT+NAVIGATIONBAR_HEIGHT)
// 实时系统状态栏高度+导航栏高度,如有热点栏,其高度包含在APP_STATUSBAR_HEIGHT中。
define STATUS_AND_NAV_BAR_HEIGHT (APP_STATUSBAR_HEIGHT+NAVIGATIONBAR_HEIGHT)
正常的带预约单黄条页面:
当因为没有适配首次出现黄条的初始位置时,当测试那4个测试用例时出现的异常页面:
按照以上方案当热点共享显示和消失时,仍有低概率出现底部按钮错乱的问题。主要是xib和手写带frame的控件难以控制。
可以统一使用SDAutoLayout这个第三方库写页面,请看我的新的完美解决方案:热点共享蓝条下压,导致页面底部按钮显示不全完美解决方案(http://blog.csdn.net/jia12216/article/details/53171647)