对于 Plus 机型,在打电话,录音或开启热点等状态下,状态栏高度会从20变为40(非Plus机型和全面屏,状态栏高度不会变化)。状态栏高度的变化,会对页面布局形成影响,以下图所示ios
首先,开启电话模拟状态栏(模拟器上使用 Command
+ Y
开启);而后,进入列表页面;最后,关闭电话模拟状态栏,在 Plus 机型上,能够看到列表底部有大约20的间隙(以下图所示)git
布局时,采用了 Frame
布局,进入页面前,Plus 机型上状态栏高度为40,所以列表高度计算时,计算公式 列表高度 = 屏幕高度 - 导航栏高度 - 底部tabBar高度 - 状态栏高度
中,状态栏高度会按照40进行计算。github
进入页面后,关闭电话模拟状态栏,状态栏高度会变为20,列表总体会向上偏移 20 来适配状态栏高度变化。可是此时,列表高度并无从新计算,赋值和更新,因此致使了上述问题。xcode
//常规状态栏高度 20
#define KStatusBarHeight [JDBIPhoneGlobalConfig statusBarHight]
// Plus机型下,电话状态会变成40
#define KNewStatusBarHeight [[UIApplication sharedApplication] statusBarFrame].size.height
复制代码
分析下面代码,能够看到,在采用 Frame
布局时,会根据初始状态下的状态栏高度,计算出列表的高度。后续状态栏变化时,并无进行列表高度值的从新计算,赋值和更新。bash
#define kiPhoneXNaviBarTopMargin (22)
#define kTabViewHeight (50.0)
#define kTabViewiPhoneXHeight (83.0)
#define KSSSViewControllerHeight (KViewControllerHeight)
#define KSSSMainViewHeight (KSSSViewControllerHeight-kTabViewHeight)
#define KSSSMainViewiPhoneXHeight (KSSSViewControllerHeight-kTabViewiPhoneXHeight)
#define KStatusBarHeight [JDBIPhoneGlobalConfig statusBarHight]
// 电话状态会变成40
#define KNewStatusBarHeight [[UIApplication sharedApplication] statusBarFrame].size.height
//计算列表高度
- (CGRect)p_getViewFrame {
CGFloat customeViewFrameHeight = isNotch ? KSSSMainViewiPhoneXHeight:KSSSMainViewHeight;
CGRect rect = CGRectMake(0.0, 0.0, CGRectGetWidth(self.view.bounds), customeViewFrameHeight);
return rect;
}
// 计算底部tabBar高度
- (CGRect)p_getTabbarViewFrame {
CGRect rect;
if(!isNotch){
CGFloat beginY = KSSSMainViewHeight;
rect = CGRectMake(0, beginY, SCREEN_WIDTH, kTabViewHeight);
} else {
CGFloat beginY = KSSSViewControllerHeight-kTabViewiPhoneXHeight;
rect = CGRectMake(0, beginY, SCREEN_WIDTH, kTabViewiPhoneXHeight);
}
return rect;
}
复制代码
Ref - IOS 打电话、分享热点状态栏变化引发的UI变化 | CSDN网络
方法1 - 监听状态栏变化,在监听事件中进行适配app
//移除通知
- (void)dealloc {
//...
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIApplicationWillChangeStatusBarFrameNotification
object:nil];
}
//添加通知
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusChange) name:UIApplicationWillChangeStatusBarFrameNotification object:nil];
//...
}
//监听事件
- (void)statusChange
{
self.isStatusChanged = YES;
[self.tableView reloadData]; //触发reload 从新布局
//或者 调用方法更新列表列表frame
}
复制代码
UIViewAutoresizingFlexibleHeight
// xxx.autoresizingMask = UIViewAutoresizingFlexibleHeight;
- (void)loadView {
[super loadView];
UIView *customView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, _customViewHeight)];
customView.autoresizingMask = UIViewAutoresizingFlexibleHeight;
self.view = customView;
}
复制代码
viewWillLayoutSubviews
生命周期函数中处理:状态栏的变化,会触发 viewWillLayoutSubviews
生命周期函数的调用,能够进行对应的布局操做- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
self.currentViewController.view.frame = [self p_getViewFrame]; //更新列表高度
self.tabBarView.frame = [self p_getTabbarViewFrame]; //更新底部tabBar高度
}
复制代码
UILabel
添加渐变背景色后,能够展现包含中文的字符串,对于纯数字或者纯英文字符串,没法展现color
的 CAGradientLayer
与显示字符串的 layer
层之间会有一个中间 layer
(_UIContentLayer
),使中文字符串不会被覆盖(正常显示);而显示纯英文字符串时,是没有这个中间 layer
的,致使 CAGradientLayer
覆盖了 字符串layer,从而致使字符串没法展现UIView
上添加 UILabel
, UIView
用于显示渐变背景色,UILabel
用于展现字符串。UILabel
的宽或高为小数时,会产生黑色边界线ceilf()
NSUInteger assteId = 0;
NSDictionary *dict = @{@"assetId":assteId};
复制代码
如上代码,向字典对象插入基本类型值时,会报错,显示iphone
Collection element of type 'NSUInteger' (aka 'unsigned long') is not an Objective-C object
复制代码
错误缘由为,将一个基本类型值(好比 int
,char
等)赋值给一个对象变量(好比 NSNumber
)。函数
针对上述问题,其解决方案以下,使用 @()
包裹基本类型值。布局
NSUInteger assteId = 0;
NSDictionary *dict = @{@"assetId":@(assteId)};
复制代码
PingFangSC
。IOS 9.0之前的系统,是没有平方字体的。UIFont
对象为 nil
,处理不当,会致使 App 闪退UIFont *font = [UIFont fontWithName:@"PingFangSC-Regular" size:18];
//IOS 9.0以前的系统 font对象为nil
复制代码
font
为 nil
,能够考虑采用降级方案(使用其余字体),或者手动导入第三方字体UIFont *font = [UIFont fontWithName:@"PingFangSC-Regular" size:18];
if(font == nil){
//手动导入第三方字体
// ...
}
复制代码
for (NSString *fontFamilyName in [UIFont familyNames])
{
NSLog(@"fontFamilyName:'%@'", fontFamilyName);
for (NSString *fontName in [UIFont fontNamesForFamilyName:fontFamilyName])
{
NSLog(@"\tfont:'%@'",fontName);
}
NSLog(@"-------------");
}
复制代码
执行上述代码,在IOS 9.0+系统上输出的平方字体信息以下
2019-09-24 16:45:35.837877+0800 fontFamilyName:'PingFang SC'
2019-09-24 16:45:35.837877+0800 font:'PingFangSC-Medium'
2019-09-24 16:45:35.837978+0800 font:'PingFangSC-Semibold'
2019-09-24 16:45:35.838068+0800 font:'PingFangSC-Light'
2019-09-24 16:45:35.838188+0800 font:'PingFangSC-Ultralight'
2019-09-24 16:45:35.838320+0800 font:'PingFangSC-Regular'
2019-09-24 16:45:35.839010+0800 font:'PingFangSC-Thin'
复制代码
Showing Recent Messages:-1:
Multiple commands produce'/Users/admxjx/Library/Developer/Xcode/DerivedData/*****-fiyqckrgqvolmlefumieigxfboco/Build/Products/Debug-iphonesimulator/*****.app/Info.plist':
1) Target '*****' (project '*****') has copy command from '/Users/admxjx/coin-iOS/coin-ios1.0/*****/Info.plist' to '/Users/admxjx/Library/Developer/Xcode/DerivedData/*****-fiyqckrgqvolmlefumieigxfboco/Build/Products/Debug-iphonesimulator/*****.app/Info.plist'
2) Target '*****' (project '*****') has process command with output '/Users/admxjx/Library/Developer/Xcode/DerivedData/*****-fiyqckrgqvolmlefumieigxfboco/Build/Products/Debug-iphonesimulator/*****.app/Info.plist'
复制代码
从报错信息可知,Info.plist
文件重复。删除重复的 info.plist
可。参考 - Stack Overflow
Xcode 中, 打开 File -> Project/Workspace settings
,将 Build System
更改成 Legacy Build system
,以下图所示。
也能够手动删除多余的info.plist
。Xcode 中,打开 target
> Build phase
> Copy Bundle Resource/Compile Sources
,删除多余的 info.plist
。
Xcode only builds what you say it should, so my guess is that the target's Compile step doesn't include those copied files in its compile list.
To fix this, select the target (normally your app), then select the Build Phases panel and open the Compile Sources step, then click the + button and add them (that list should include all sources needed to build the app).
To add new files in the future and repeating this manual compile list updating, right click on a project folder, click "Add Files to ...", select the file(s), click the Options button and select the target, then click Add.
在建立类时,注意将其关联到对应的 target
。下面以京东秒杀代码为例,进行说明。
建立类时,Target
属性中勾选 JDSeckillModule
。这样,在建立的类文件中,文件头部的注释部分会显示对应的 Target
,以下所示
//
// SSSSKMViewController.m
// JDSeckillModule // ---> 本行表示关联的 Target
//
// Created by 刘保帅 on 2019/6/10.
//
复制代码
NSInteger
为基本类型,在接收网络请求时,若无该字段下发,则默认值为 0
。NSNumber
为一个类,是个对象,在接收网络请求时,若无该字段下发,则默认值为 nil
。记录以下 3 种方法
// 方法1 - 回滚到表的最顶端
[self.tableView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:NO];
// 方法2
[self.tableView setContentOffset:CGPointMake(0,0) animated:NO];
// 方法3
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
复制代码