-
一、iOS 相关
(一)给一整个View加渐变
- 如果我给一个View设置了maskView加了渐变,那是不是所有加到View上的subView展示的样式都会收到View.mastView的影响?
是的,如果给一个UIView设置了maskView并加了渐变,那么所有加到UIView上的subView展示的样式都会受到UIView.maskView的影响。
UIView.maskView属性会将一个UIView实例设置为另一个UIView实例的遮罩视图,即遮罩视图会覆盖在被遮罩的UIView上。因此,所有加到被遮罩的UIView上的subView都会被遮罩视图遮挡或显示。如果遮罩视图是一个带有渐变的UIView实例,那么所有加到被遮罩的UIView上的subView都会受到渐变的影响。
需要注意的是,如果某个subView的alpha值小于1.0,那么它的展示效果可能与其他subView不同。因为遮罩视图是根据alpha通道来遮挡或显示被遮罩的UIView的部分区域的,而alpha值小于1.0的subView可能会透过遮罩视图的alpha通道,从而影响展示效果。因此,在给一个UIView设置maskView时,需要注意subView的alpha值,以确保展示效果正确。
效果:
代码:
// 0 - 0.6 : 渐变
// 0.6 - 0.9 : 消失
gradientLayer.locations = @[ @(0), @(0.6), @(0.9), @(1) ];
gradientLayer.colors = @[ (__bridge id)inputColor0.CGColor,
(__bridge id)inputColor1.CGColor ,
(__bridge id)inputColor1.CGColor ,
(__bridge id)inputColor0.CGColor ];
// 0.1 - 0.4 : 渐变 ,前后都需要补充保护带,前 [0,0.1],后[0.4,0.401]
// 0.7 - 0.9 : 消失 ,前后都需要补充保护带,前 [0.699,0.7],后[0.9,0.901]
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(0) color:inputColor0]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(0.1) color:inputColor0]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(0.4) color:inputColor1]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(0.401) color:inputColor0]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(0.699) color:inputColor0]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(0.7) color:inputColor1]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(0.9) color:inputColor1]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(0.901) color:inputColor0]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(1) color:inputColor0]];
完整测试代码:
+ (UIView *)createGradientMaskViewRenderFrame:(CGRect)renderFrame blankArea:(CGRect)blankArea targetView:(UIView *)targetView {
CGFloat parentWidth = targetView.width;
CGFloat parentHeight = targetView.height;
UIView *gradientMaskView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, parentWidth, parentHeight)];
gradientMaskView.isAccessibilityElement = NO;
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
gradientLayer.frame = CGRectMake(0, 0, parentWidth, parentHeight);
gradientLayer.startPoint = CGPointMake(0, 0);
gradientLayer.endPoint = CGPointMake(1, 0);
// 以blankArea为优先,处理重叠区域
renderFrame = [self.class subtractRect:renderFrame withRect:blankArea];
// 计算渐变和抹掉区域
CGFloat renderStart = MIN(MAX(renderFrame.origin.x / parentWidth, 0), 1.0);
CGFloat renderEnd = MIN(MAX((renderFrame.origin.x + renderFrame.size.width) / parentWidth, 0), 1.0);
BOOL renderValid = renderStart >= 0 && renderEnd >= 0;
CGFloat blankStart = MIN(MAX(blankArea.origin.x / parentWidth, 0), 1.0);
CGFloat blankEnd = MIN(MAX((blankArea.origin.x + blankArea.size.width) / parentWidth, 0), 1.0);
BOOL blankValid = blankStart >= 0 && blankEnd >= 0;
WCFinderDebug(@"NavBar renderStart:%f,renderEnd:%f,blankStart:%f,blankEnd:%f,parentWidth:%f,parentHeight:%f",
renderStart,
renderEnd,
blankStart,
blankEnd,
parentWidth,
parentHeight);
if (!renderValid && !blankValid) {
WCFinderError(@"Error render blank frame");
return nil;
}
/*
四种情况:
1. 渐变 x 抹掉
2. 抹掉 x 渐变
3. 渐变
4. 抹掉
Tips:
1. 下面描述加保护带的原因是要迅速完成颜色转变。
2. 这里说的渐变都是右边更模糊,左边清晰
*/
NSMutableArray<WCFinderGradientColorModel *> *modelArray = [NSMutableArray array];
UIColor *inputColor0 = [UIColor blueColor];
UIColor *inputColor1 = UIColor.clearColor;
if (renderValid && blankValid) {
// {渐变 + 抹掉}
if (fabs(renderEnd - blankStart) < 0.05) {
// 无缝接壤
if (renderEnd > blankStart) {
// 渐变 + 抹掉
// renderStart - renderEnd : 渐变 , 无保护带
// renderEnd/blankStart - blankEnd : 抹掉, 后面要加保护带,后[blankEnd,blankEnd + 0.01]
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(0) color:inputColor0]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(renderStart) color:inputColor0]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(renderEnd) color:inputColor1]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(blankEnd) color:inputColor1]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(blankEnd + 0.01) color:inputColor0]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(1.0) color:inputColor0]];
} else {
// 抹掉 + 渐变
// blankStart - blankEnd : 抹掉 , 前面要加保护带,前 [blankStart - 0.01,blankStart]
// blankEnd/renderStart - renderEnd : 渐变, 前后面要加保护带,前[blankEnd, blankEnd + 0.01],后[renderEnd,renderEnd + 0.01]
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(0) color:inputColor0]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(blankStart - 0.01) color:inputColor0]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(blankStart) color:inputColor1]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(blankEnd) color:inputColor1]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(blankEnd + 0.01) color:inputColor0]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(renderEnd) color:inputColor1]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(renderEnd + 0.01) color:inputColor0]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(1.0) color:inputColor0]];
}
} else {
// 有间隙
if (renderEnd > blankStart) {
// 渐变 + 抹掉
// renderStart - renderEnd : 渐变 ,后面有保护带 , [renderEnd, renderEnd + 0.01]
// blankStart - blankEnd : 抹掉, 前后要加保护带,前:[blankStart - 0.01 , blankStart],后[blankEnd,blankEnd + 0.01]
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(0) color:inputColor0]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(renderStart) color:inputColor0]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(renderEnd) color:inputColor1]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(renderEnd + 0.01) color:inputColor0]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(blankStart - 0.01) color:inputColor0]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(blankStart) color:inputColor1]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(blankEnd) color:inputColor1]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(blankEnd + 0.01) color:inputColor0]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(1.0) color:inputColor0]];
} else {
// 抹掉 + 渐变
// blankStart - blankEnd : 抹掉, 前后要加保护带,前:[blankStart - 0.01 , blankStart],后[blankEnd,blankEnd + 0.01]
// renderStart - renderEnd : 渐变 ,后面有保护带 ,[renderEnd, renderEnd + 0.01]
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(0) color:inputColor0]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(blankStart - 0.01) color:inputColor0]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(blankStart) color:inputColor1]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(blankEnd) color:inputColor1]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(blankEnd + 0.01) color:inputColor0]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(renderStart) color:inputColor0]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(renderEnd) color:inputColor1]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(renderEnd + 0.01) color:inputColor0]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(1.0) color:inputColor0]];
}
}
} else if (renderValid) {
// 纯渐变
// renderStart - renderEnd : 渐变 ,后面有保护带 ,[renderEnd, renderEnd + 0.01]
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(0) color:inputColor0]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(renderStart) color:inputColor0]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(renderEnd) color:inputColor1]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(renderEnd + 0.01) color:inputColor0]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(1.0) color:inputColor0]];
} else if (blankValid) {
// 纯抹掉
// blankStart - blankEnd : 抹掉, 前后要加保护带,前:[blankStart - 0.01 , blankStart],后[blankEnd,blankEnd + 0.01]
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(0) color:inputColor0]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(blankStart - 0.01) color:inputColor0]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(blankStart) color:inputColor1]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(blankEnd) color:inputColor1]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(blankEnd + 0.01) color:inputColor0]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(1.0) color:inputColor0]];
}
WCFinderGradientLayerModel *model = [WCFinderGradientLayerModel genGradientModel:modelArray];
gradientLayer.locations = model.locations;
gradientLayer.colors = model.colors;
[gradientMaskView.layer addSublayer:gradientLayer];
return gradientMaskView;
}
(二)动画库的选择
《视频号直播动画框架》
2023年05月18日15:16:50
Lottie && PAG
- Pag 能力更强大
PAG 3.0 -> 4.0
- 性能Pag4.0和Pag3.0相当
- Pag4.0支持三维
动画卡顿时的处理方法:
- PAG资源优先级
- 重pag降低刷新频率
- 降低其它类型的点赞的pag、停掉不可见的pag
直播应用动画的框架:
- PAG
- 小游戏动画引擎
- WeVision
当在iOS项目中需要嵌入脚本语言时,Lua是一个非常不错的选择。下面是一些Lua在iOS项目中的应用场景:
游戏开发:Lua在游戏开发中非常流行,因为它可以用来编写游戏逻辑和游戏脚本。在iOS游戏中,Lua可以用来编写关卡逻辑、AI行为、游戏界面等。
应用程序扩展:Lua可以用来编写应用程序的插件和扩展。例如,你可以使用Lua编写一个插件,使得你的应用程序可以通过脚本来自定义功能。
用户脚本:Lua可以用来编写用户脚本,这些脚本可以用来自定义应用程序的行为。例如,你可以使用Lua编写一个脚本,使得你的应用程序可以根据用户的需求来自定义UI界面。
数据处理:Lua可以用来处理数据,例如解析JSON数据、处理XML数据等。在iOS项目中,Lua可以用来处理从服务器获取的数据,以及在应用程序中存储的本地数据。
总之,Lua在iOS项目中有很多应用场景,它可以用来编写游戏逻辑、应用程序扩展、用户脚本和数据处理等。如果你正在开发一个iOS项目,并且需要嵌入脚本语言,那么Lua是一个非常不错的选择。
(三)JSCore优化
- 帮我介绍一下JIT优化
当我们运行一个编译型语言编写的程序时,代码会被编译成机器码,然后直接在CPU上执行。而当我们运行一个解释型语言编写的程序时,代码会被解释器逐行解释执行。这种解释执行的方式会导致程序的运行速度比较慢。
JIT(即时编译)优化是一种优化技术,它可以在程序运行时将解释执行的代码编译成机器码,然后直接在CPU上执行。这种方式可以大大提高程序的运行速度。
在iOS开发中,JIT优化可以用来提高应用程序的性能。例如,我们可以使用JIT优化来提高游戏的帧率,或者使用JIT优化来提高应用程序的启动速度。
在iOS开发中,可以使用一些支持JIT优化的框架和库,例如LuaJIT、JavaScriptCore等。这些框架和库可以让我们使用JIT优化来提高应用程序的性能,同时也可以让我们更加方便地编写高性能的应用程序。
总之,JIT优化是一种非常有用的优化技术,它可以大大提高程序的运行速度。在iOS开发中,可以使用一些支持JIT优化的框架和库来提高应用程序的性能。
- TaggedPointer
用指针去存储内容。
- Hermes
Hermes是Facebook开发的一款JavaScript引擎,它专门用于React Native应用程序的开发。相比于iOS系统自带的JavaScriptCore引擎,Hermes有以下几个优点:
更快的启动速度:Hermes的启动速度比JavaScriptCore更快,这可以提高React Native应用程序的启动速度。
更小的内存占用:Hermes的内存占用比JavaScriptCore更小,这可以减少React Native应用程序的内存占用。
更好的性能:Hermes的性能比JavaScriptCore更好,这可以提高React Native应用程序的性能。
更好的调试支持:Hermes提供了更好的调试支持,可以方便地调试React Native应用程序。
在iOS开发中,我们可以使用Hermes作为React Native应用程序的JavaScript引擎。使用Hermes可以提高React Native应用程序的启动速度、性能和内存占用,并且可以提供更好的调试支持。同时,Hermes也可以与其他React Native工具和库一起使用,例如React Native CLI、Expo等。
总之,Hermes是一款非常有用的JavaScript引擎,它可以提高React Native应用程序的性能、启动速度和内存占用,并且提供了更好的调试支持。如果你正在开发React Native应用程序,那么可以考虑使用Hermes作为JavaScript引擎。
但是!! Hermes 现在有很多恶心的bug!!要小心使用!!
(四)使用yoga时重新触发布局: makeDirty
[self.likeBtn configureLayoutWithBlock:^(YGLayout *_Nonnull layout) {
layout.isEnabled = self.likeBtn.isHidden == NO ? YES : NO;
layout.width = YGPointValue(targetWidth);
}];
[self.likeBtn.yoga markDirty];
(五)layoutIfNeeded
和setNeedsLayout
在iOS开发中,UIView类提供了两个方法来触发视图的布局:layoutIfNeeded
和setNeedsLayout
。
setNeedsLayout
方法是UIView的方法,它会标记当前视图及其子视图需要重新布局。但是它并不会立即触发布局,而是将布局标记为“需要”,然后在下一个run loop周期中,系统会调用layoutSubviews
方法来进行布局。
示例代码如下:
1 | // 标记当前视图需要重新布局 |
layoutIfNeeded
方法是UIView的方法,它会立即触发布局计算,并更新视图的位置和大小。如果视图已经标记为“需要”布局,那么layoutIfNeeded
方法会立即进行布局计算并更新视图;如果视图没有标记为“需要”布局,那么layoutIfNeeded
方法不会进行任何操作。
示例代码如下:
1 | // 如果视图需要重新布局,则立即进行布局计算 |
因此,setNeedsLayout
方法只是标记视图需要重新布局,而layoutIfNeeded
方法则会立即进行布局计算并更新视图。在实际开发中,我们可以根据需要选择使用这两个方法。
(六)无符号整形的计算方法
NSUInteger abc = 0;
print(abc - 5); // 会溢出变成很大