一. 点击uiscrollview
的子视图,即使不产生滑动,总是会走- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
测试发现:
- 如果是代码创建的
scrollview
,在scrollview
上面添加子视图button
,点击button
,不产生滑动,并不会走scrollViewDidEndDecelerating
- 如果是
xib
创建的scrollview
,点击button
,即使不产生任何滑动,总是会走scrollViewDidEndDecelerating
,即使添加的是其他子视图uiview
,也是一样。这种情况,只需要取消scrollview.pagesnable=yes
,就可以了。是不是xib多设置了什么东西,没搞明白。
二. xib自定义的控件,用纯代码加载,报错找不到xib控件拉好的IBOutlet属性
- 报错:
*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[
setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key searchBtn - xib控件File`s Owner关联的类取消,改由view关联对应的类
- xib的属性全部重新拉线(由File`s Owner改为view关联,拉线的属性不改还是会报错)
- xib控件是作为另一个xib的子视图,不是由代码加载,不用改
三. scrollview滑动卡住,也不崩溃。
- (void)layoutSubviews不要做任何frame的更新,因为scrollview滑动会一直调用- (void)layoutSubviews,里面做frame更新,又会反过来调用- (void)layoutSubviews,就会一直卡在这个方法里
四.scrollview里面添加button或者其他控件,不能点击
- 是因为scrollview加了撑开的contentview,button又加载contentview上,contentview高度或者宽度显示不下button,导致点击传递事件到了contentview就找不到下层的button了。
- 层级关系: scrollview-> contentview->button,contentview的size装载不下button。传递事件断裂
五. tablefooterview的按钮不能点击
- 很多帖子讲是
tabletooterview``的高度不够,这其实是个很明显的问题,跟
上面第四条```道理一样。 - 但其实,我有次明显设置了
footerview
的高度,也看了层级关机,没有被遮挡。后来发现,原来是设置了渐变色的原因,因为渐变色是用layer去实现的,直接把渐变色layer加在button上,会遮挡button文字显示。所以写了个分类,渐变色layer加载一个bgview上,再把bgview加在button的最底层。这样就可以实现渐变色背景的按钮。但是!!!!我们点击的响应,也直接点击在bgview上,所以button接收不到响应链。解决办法,bgView.isUserInteractionEnabled = false
/或者self.colorView.userInteractionEnabled = NO
。部分代码如下:let gradientLayer = CAGradientLayer() gradientLayer.frame = self.bounds gradientLayer.colors = array gradientLayer.locations = [0.0,1.0] gradientLayer.startPoint = CGPoint.init(x: 0, y: 0.5) gradientLayer.endPoint = CGPoint.init(x: 1, y: 0.5) let bgView = UIView(frame: self.bounds) bgView.isUserInteractionEnabled = false //不设置这句,button的点击是点击在bgview上 self.addSubview(bgView) self.sendSubviewToBack(bgView) bgView.layer.addSublayer(gradientLayer)
五. tableview.tableFooterView和tableview.tableHeaderView的高度或者宽度有问题。
- tableview.tableFooterView要初始化frame
- tableview.tableFooterView不能直接=self.footerView,解决办法,先赋值一个view,再让view addsubview,如下:
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, 700)];
[view addSubview:self.footerView];
tableview.tableFooterView = view
- tableview.tableHeaderView同理
六.@property (getter=isActive) BOOL active,设置yes/no,不生效
- 我遇到的情景是,做聊天气泡时,xib上拉label的left和right约束,根据内容决定label的left或者right约束的active是yes还是no,从而决定label是靠左还是右。然后有时候会出现label左右位置混乱。解决:
- 拉lable的left或者right作为属性时,是weak修饰,改为strong就可以了(个人猜测,当active=no时,约束不生效的原因,其实就是移除了该约束,然而因为是weak修饰,当再次设置该约束active=yes时,其实该约束已经不存在了,所以更改strong修饰后,再次修改active=yes,还是能生效)。
七。更改状态栏颜色问题(-(UIStatusBarStyle)preferredStatusBarStyle
不调用问题)
在info.plist 中 View controller-based status bar appearance 一定要改为为 YES
-
navigationcontroller
中添加:- (UIViewController *)childViewControllerForStatusBarStyle { return self.topViewController; }
-
每个
Viewcontroller
中添加:-(UIStatusBarStyle)preferredStatusBarStyle { return UIStatusBarStyleDarkContent; }
需要注意,如果有导航栏
navigationcontroller
,状态栏颜色由导航栏统一管理,事实上由导航栏管理也最好。如果需要单独改变某个状态栏,就单独在那个控制器实现preferredStatusBarStyle
状态一直是白色,怎么也改不到黑色:暗黑模式下无法设置为黑色,关闭暗黑模式
info.plist
-->Appearance = Light
。关闭之后再检查preferredStatusBarStyle
返回的是深色字体还是白色字体。
八。使用UINavigationController,控制器self.view距离顶部的距离,一会高,一会低。(UICollectionView/UITableView
顶部会留白的解决办法)
- 场景:从控制器A,进入控制器C,C的self.view是全屏,距离顶部是0。从控制器B,进入控制器C,C的self.view距离顶部有个一导航栏的高度。这就导致控制器C写这样的布局,也会变化:
[_headerView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.view).offset(0);
}];
- 原因:设置
.translucent
这个属性,会影响UIViewcontroller
的布局:-
.translucent = NO
,导航栏取消毛玻璃效果(导航栏设置什么颜色就是什么颜色,可以理解为会遮挡下一层的self.view),self.view的原点是从导航栏左下角
开始计算。 -
.translucent = YES
,导航栏显示毛玻璃效果(导航栏会有一层模糊的半透明的毛玻璃效果,可以理解为,即使第一层从导航栏滚过,也会看到一点点,不会遮挡self.view),self.view的原点是从导航栏左上角
开始计算。
-
- 解决:在哪个控制器设置过
self.navigationController.navigationBar.translucent = NO
,就在这个控制器viewWillDisappear
中,设置回来(self.navigationController.navigationBar.translucent = YES)
- 或者直接设置:(
self.collectionview/self.tableview
顶部会留白的解决办法)if (@available(iOS 11, *)) { self.collectionView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; }else{ self.automaticallyAdjustsScrollViewInsets = NO; }
九。两个UICollectionView嵌套,都使用MJRefresh。滑动方向冲突
- 场景:UICollectionView
(A)
和UICollectionView(B)
。A
是横向滚动,每个cell是当前控制器的view
大小。B
是纵向滚动的瀑布流布局,加载A
的cell上。
这个时候在屏幕上斜方向滑动,会产生A
和B
同时一起斜方向滑动
。按照场景需求,应该是要么纵向滚动瀑布流,要么横向滚动页面。 - 原因:后来看了
MJRefresh
源码,大概是,他给UICollectionView
加了一个滑动手势,滑动时候,把scrollview
的contentInset
还是contentOffset
来着,把它的值改变,形成继承于scrollview
的视图也跟着手势滑动的效果。- 至于为什么一个
collectionview
不会斜方向滑动,两个嵌套就会斜方向滑动,就没有深入追究了
- 至于为什么一个
- 解决:
- 要么
A
和B
,只留一个使用MJRefresh
。上拉刷新下拉加载的功能也就只能添加在A
或者B
上。 - 要么就把
A
或者B
的mj_header
和mj_footer
给移除掉,其实产生的效果等同于上面。
- 要么
十.UITableView,用masnory布局约束,发现底部往下偏移了,也就是底部有部分显示不了
- 场景:
这个情况比较特殊,不具备普遍化,自己碰到过,记下来
。因为上面第九
条原因,所以自己在自定义TableView基类的时候,会用一个方法禁止掉MJRefresh
功能:self.mj_header?.scrollView?.bounces = false self.mj_footer?.scrollView?.bounces = false self.mj_header?.scrollView?.contentInset = .zero self.mj_footer?.scrollView?.contentInset = .zero self.mj_header?.endRefreshing() self.mj_footer?.endRefreshing() self.mj_footer?.removeFromSuperview() self.mj_header?.removeFromSuperview()
然而,在不需要刷新功能的界面,为了防止出现布局混乱,调用了上面这个方法,结果就出现tableview
底部,被屏幕遮住了。而检查约束条件make.edges.equalToSuperview()
,这完全没问题。
- 原因:打开层级显示,定位
TableView
,发现这段话:
baseClass = UITableView; frame = (0 64; 375 603); clipsToBounds = YES;
contentOffset: {0, 198}; contentSize: {375, 845}; adjustedContentInset: {0, 0, -44, 0};
contentOffset: {0, 198}
,这说明tableview无缘无故往下移动了198
。这是什么原因?
- 解决:无意中,注释掉上面说的基类tableview中的禁止
MJRefresh
功能方法中的,两行代码,解决了!而且层级定位发现contentOffset: {0, 0}
就是注释了这两行代码 //self.mj_header?.scrollView?.contentInset = .zero //self.mj_footer?.scrollView?.contentInset = .zero
- 思考:为什么,
MJRefresh
中的mj_header/mj_footer
,禁止scrollView?.contentInset
,会导致UITableView的contentOffset: {0, 198}
,MJRefresh做了什么? - 探究:
- 原来
self.mj_header?.scrollView?
等于self.mj_header?.superView
等于self(tableView)
- 然而,断点打印如下:
(lldb) po self.mj_header?.scrollView?.contentInset ▿ Optional
▿ some : UIEdgeInsets - top : 0.0 - left : 0.0 - bottom : 44.0 - right : 0.0 - 所以,注释掉那两行代码,就是让
tableview.contenInset
,由系统建立的距离底部的值bottom=44(正常显示)
变成bottom=0(被遮挡一部分)
,可不就是遮挡了嘛
- 原来
- 最后:至于为什么不注释那两行,
contentOffset: {0, 0}
,注释掉就变成contentOffset: {0, 198}
。有待考证
十一.UICollectionView截屏,显示不全问题
- 场景: 自定义布局的UICollectionView,cell是xib,一个section只有一个item。需要截取全部collectionView,生成图片分享。截屏代买如下:
let frame = collectionView.frame UIGraphicsBeginImageContextWithOptions(collectionView.contentSize, false, 0) collectionView.layer.frame = CGRect(x:0, y:0, width:kUIScreenWidth, height:collectionView.contentSize.height) collectionView.layer.render(in: UIGraphicsGetCurrentContext()!) let collectionViewImg = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() collectionView.frame = frame return collectionViewImg
- 问题:上面代码,只会截取
已经出现在屏幕的cell
,对于未出现的cell,截取的空的。 - 原因:
- 原来在基类控制器设置过:
self.navigationController?.navigationBar.isTranslucent = false
-
isTranslucent = false
设置带来的直接结果是,控制器的顶部
与屏幕的顶部
距离一个导航栏的高度 - 也会导致截屏时,对于未展示过的cell,不会调用datasource去加载cell,所以未展示过的cell的layer,自然是空白的。(为什么会这样,不得而知)
- isTranslucent 其他的影响
- 原来在基类控制器设置过:
十二. UICollectionView反向序列排列
- 场景:
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
下,collectionview滚动是从右往左滚动的,那么如果从坐往右滚动呢?比如滑动翻日历,往往进去就是默认最近的日历,往前翻,就需要反向排列了。 - 解决:自定义
UICollectionViewFlowLayout
,全部代码如下:#import "RCalendarLayout.h" @implementation RCalendarLayout ///决定flowyout是否能主动选择其他滚动方向,默认NO - (BOOL)flipsHorizontallyInOppositeLayoutDirection { return YES; } ///决定flowyout的滚向,默认是LeftToRight - (UIUserInterfaceLayoutDirection)developmentLayoutDirection { return UIUserInterfaceLayoutDirectionRightToLeft; } @end
- 这两个方法的理解可能有误,最好点进原方法,看注释。
十三. UICollectionView的UICollectionElementKindSectionHeader
,设置在Cell的背后。
- 默认自定义
UICollectionElementKindSectionHeader
的时候,会在cell的上层,如果要cell遮挡sectionHeader
的效果,就要自定义UICollectionViewFlowLayout
,具体方法如下:- (NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect { NSArray *attributes = [[super layoutAttributesForElementsInRect:rect] copy]; for (UICollectionViewLayoutAttributes *attr in attributes) { CGRect frame = attr.frame; if (frame.size.height < 300) { CGPoint origin = frame.origin; origin.y = origin.y - 60; frame.origin = origin; attr.frame = frame; attr.zIndex = attr.indexPath.row + 1;///此属性是关键,cell.zIndex 最小值是1,依次递增 }else{ attr.zIndex = 0;///此属性是关键,sectionheader.zIndex 永远是0 } } return attributes; }
十四. UITableView的tableHeaderView | sectionHeaderView留白解决方法
-
方法1:
tableHeaderView
: 一般解决办法(带有导航栏)
:///self=UIViewController ///tableView.tableViewStyle = UITableViewPlan if #available(iOS 11.0, *) { tableView.contentInsetAdjustmentBehavior = .never } else { self.automaticallyAdjustsScrollViewInsets = false }
-
方法2: 我的场景是:
没有导航栏
,tableView.tableViewStyle = UITableViewGroup
,设置方法1后
,还是留白。- 需要再加上以下属性:
其实就是要设置tableView的sectionHeaderView
和tableHeaderView
的高度tableView.tableHeaderView = UIView(frame:.zero) # 如果上面不生效,则用下面方法试试 self.tableView.tableHeaderView = UIView(frame:CGRect(x:0, y:0, width:0.01, height: 0.01)) self.tableView.tableFooterView = UIView(frame:CGRect(x:0, y:0, width:0.01, height: 0.01))
- 需要再加上以下属性:
-
方法3: 我的场景是:
顶部空白高度
=22
,(没有导航栏,tableView.tableViewStyle = UITableViewPlain)
,iphone8
,ios16.1
,if #available(iOS 15.0, *) { self.tableView.sectionHeaderTopPadding = 0 } else { }
-
其他类似的问题,可能会误导致顶部有一段小留白的:
-
sectionHeaderView
: 也有个类似的场景:tableview的style = .group
时,sectionHeaderView
的高度,会有默认的一段高度。即使设置了delegate
的sectionHeaderView
的高度return 0
不生效。return = 0.01
生效。 -
sectionFooderView
同上。 - 小结:在某些iOS版本中,
tablestyle = .group
场景下,无论是tableHeaderView
还是sectionHeaderView
,对其相应的方法设置高度=0
,都无效,需要设置高度=0.01
-
十五.关于切圆角不生效问题
- 下面代码不生效问题:
cell.contentView.cornerRadius = 10; cell.contentView.layer.masksToBounds = YES;
- 检查
cell
的颜色,color会影响layer。某种情况下发现,xib设置的cell,如果背景颜色是默认的,上面呢代码不会生效。 - 设置圆角加阴影,用以上方法,会产生离屏渲染,用下面方法:
let bounds = CGRect(x:0, y: 0, width:w, height: 216.0/162*w) self.layer.shadowPath = UIBezierPath(roundedRect:bounds, byRoundingCorners:[.topLeft,.topRight,.bottomLeft,.bottomRight], cornerRadii: CGSize(width:4, height: 4)).cgPath self.layer.shadowColor = "#CFCFCF".color().cgColor self.layer.shadowOffset = CGSize(width: 0, height: 0) self.layer.shadowRadius = 4 self.layer.shadowOpacity = 1 self.layer.cornerRadius = 4 self.layer.masksToBounds = false ///一定要设置这个
十六.UITextView带link的富文本,下划线和link字符串颜色设置问题
let text = "By clicking start, you agree to our Terms and Conditions and Privacy Statement.".attri(UIFont.systemFont(ofSize: 14), "#E2665C".color())
var attri = [.underlineStyle:NSUnderlineStyle.single.rawValue,.underlineColor:"#E2665C".color(),.link:"privacy"] as [NSAttributedString.Key : Any]
var attri2 = [.underlineStyle:NSUnderlineStyle.single.rawValue,.underlineColor:"#E2665C".color(),.link:"agreement"] as [NSAttributedString.Key : Any]
text.addAttributes(attri, range: NSRange(location:36, length: 20))
text.addAttributes(attri2, range: NSRange(location: 61, length: 18))
self.agreement.attributedText = text
self.agreement.linkTextAttributes = [.foregroundColor:"#E2665C".color()]
十七.XcodeDefault.xctoolchain/usr/lib/arc/libarclite_iphoneos.a
- 原因:
Xcode 14.3移除了arc目录,因为Xcode 14支持的最低部署目标iOS 11, 最低部署版本的系统都已经内置了ARC相关的库, 我们只需要将第三方库部署目标的iOS版本设置成和应用最低部署目标的iOS版本即可
- 解决方法: 原方法摘自这
post_install do |installer|
installer.generated_projects.each do |project|
project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '11.0' #9.0
end
end
end
end
但是,我的Podfile,加上上面方法,会报很多错误!!!
- 解决方法2: 根据上面所说,将第三方库的最低部署iOS的版本,改到
ios11
以上就可以了- Xcode 左侧文件栏最顶部,有个⚠️号的按钮,点击,找到报错的第三方库
- 左侧文件栏,点击
Pods.xcodeproj
->Targets
->对应三方库
->General
->修改Minimum Deployments = iOS11以上
十八.Command PhaseScriptExecution failed with a nonzero exit code
- 该报错有一定概率是cocoapods 的问题,可以试试升级版本:
更新gem:
sudo gem update --system
下载最新版本:
sudo gem install -n /usr/local/bin cocoapods --pre