iOS中容易用错的常用知识点

iOS,常用,知识点 · 浏览次数 : 110

小编点评

```swift func convert(_ point: CGPoint, from view: UIView?) -> CGPoint { guard let window = view.superview as? UIWindow else { return point } let transform = window.transform return CGPoint(x: point.x * transform.tx, y: point.y * transform.ty) } ``` **注释:** 1. 方法接受两个参数:`point` 是原始点的坐标,`view` 是原始 UIView。 2. 首先检查 `view` 的类型,如果是 `UIWindow`,则获取它的 `transform` 属性。 3. 如果 `view` 不是 `UIWindow`,则返回原始点坐标。 4. 获取 `window` 的 `transform` 属性,它是一个 `CGAffineTransform` 对象,它包含了对平移、缩放和旋转的变换参数。 5. 通过 `transform.tx` 和 `transform.ty` 获取平移参数,通过 `transform.a`、`transform.d` 和 `transform.c` 获取缩放参数,通过 `transform.rotation` 获取旋转参数。 6. 将原始点的坐标转换为 `CGPoint` 对象,并返回最终的结果。

正文

坐标系转换
ios中的坐标系有三种
视图坐标系:原点(0,0)视图的左上角
窗口坐标系:原点(0,0)窗口的左上角
世界坐标系:原点(0,0)游戏中世界的原点

平时开发中经常会遇到转UIWindow坐标问题,如:已知一个UI控件的坐标,把它转换到UIWindow时,它对应的UIWindow坐标是什么?
苹果提供了一套相关的转换方法,但是它缺少了坐标在转换时会涉及到三个UIView, 方法中没有对这3个UIView关系的描述,这在使用坐标转换时就很容易搞迷糊了。
open func point(inside point: CGPoint, with event: UIEvent?) -> Bool

open func convert(_ point: CGPoint, to view: UIView?) -> CGPoint

open func convert(_ point: CGPoint, from view: UIView?) -> CGPoint

open func convert(_ rect: CGRect, to view: UIView?) -> CGRect

open func convert(_ rect: CGRect, from view: UIView?) -> CGRect
举例如下:
override func viewDidLoad() {
    super.viewDidLoad()
    
    view.addSubview(myButton)
    
    let center2 = view.convert(myButton.center, to: UIApplication.shared.keyWindow)
}
下面这件代码的意思是将self.view下面的子视图self.myButton的中点从它的视图坐标系中转换到keyWindow的窗口坐标系中时,得到的坐标是什么。
这句代码种涉及到的三个UIView: self.view, self.myButton, keyWindow。其中self.myButton是self.view的子视图。这层关系需要清楚,就避免迷糊了。
view.convert(myButton.center, to: UIApplication.shared.keyWindow)

 

自定义UIButton中Image和title的位置关系
UIButton中Image和title的位置坐标是可以自定义调整的,弄懂了下面这些就不用经常在UIView里套Image和Label来自定义视图了。

前置条件
手写UIButton时,ButtonType选择custom,style设置为Default(这个没有找到设置的地方,在xib上有这项,实际上手动创建的代码style默认就是Default)
使用xib创建的UIButton时,把它的plain改成Default。ButtonType设置成custom。
就是截图中的上面2项:
已知概念
1.UIButton中的image和image现在默认是上下,左右居中,并且image和title在水平方向是挨着的。
btn.contentEdgeInsets = .zero
btn.imageEdgeInsets = UIEdgeInsets(top: 2, left: 2, bottom: 2, right: 25)
btn.titleEdgeInsets = UIEdgeInsets(top: 2, left: 12, bottom: 2, right: 2)
2.上面btn相关的EdgeInset值的设置的效果 是和css中的padding内边距效果一致的。即:值>0内容向内缩,值<0内容往外扩展。
3.image和title具有中间挨着的特性,默认情况下,无论image左移多少,title都会跟随左移多少,以满足image和title中间挨着的特性。
4.对于设置的EdgeInset中的偏移量是相对于image和title在没有设置任何偏移量时的默认状态的偏移。

了解了上面这些概念就可以愉快的自定义UIButton中image和lable的位置了。
let btn = UIButton(type: .custom)
btn.frame = CGRect(x: 100, y: 80, width: 40, height: 20)
btn.setTitleColor(.white, for: .normal)
btn.setTitle("jack", for: .normal)
btn.titleLabel?.font = UIFont.systemFont(ofSize: 10)
btn.setImage(UIImage.init(named: "loveHeat"), for: .normal)
btn.backgroundColor = UIColor.black.withAlphaComponent(0.6)
btn.layer.cornerRadius = 4;
btn.layer.masksToBounds = true;
btn.imageEdgeInsets = UIEdgeInsets(top: 3, left: 2, bottom: 1, right: 25)
btn.titleEdgeInsets = UIEdgeInsets(top: 0, left: 1, bottom: 0, right: 0)
btn.isUserInteractionEnabled = false
 
图层遮罩mask
在APP启动引导页或者APP中的气泡弹窗时,经常会用到图层的mask遮罩来自定义一些气泡形状。当向view.layer的mask属性添加一个图层属性时,有时候会搞混乱,这两个图层都有内容,它们作用在一起后,最终的显示效果是哪个展示,哪个不展示呢
view.layer.mask = maskLayer
简单的理解为:将view.layer中的页面内容按照maskLayer的路径进行裁剪。得出一个有一定路径边界的view视图。
举例如下:
let view = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
view.backgroundColor = .red

let maskLayer = CAShapeLayer()
let path = UIBezierPath(ovalIn: view.bounds)
maskLayer.path = path.cgPath

view.layer.mask = maskLayer

这里我们首先创建了一个红色的 UIView,然后创建了一个圆形的 CAShapeLayer,将其 path 属性设置为一个内切于 view 边界的圆形 UIBezierPath,最后将 view 的 mask 属性设置为这个 CAShapeLayer,这样就实现了将视图裁剪成圆形的效果。 

获取keyWindow
从iOS 13开始,应用程序可能同时包含多个场景(多个窗口),所以要获取keyWindow的话,已经不能直接读取UIApplication中的kewWindow这种方式了。
而是需要通过connectedScenes属性获取所有连接的场景(Scene),然后选择第一个场景,并将其转换为UIWindowScene类型。
然后从该场景中选择第一个UIWindow对象,判断该对象被是否被标记为isKeyWindow,如果返回true,则表示当前window为keyWindow。
代码如下:
if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
   let window = windowScene.windows.first(where: { $0.isKeyWindow }) {
    // 在这里使用当前正在使用的window对象
}

 

 

 

 

与iOS中容易用错的常用知识点相似的内容:

iOS中容易用错的常用知识点

坐标系转换 ios中的坐标系有三种 视图坐标系:原点(0,0)视图的左上角 窗口坐标系:原点(0,0)窗口的左上角 世界坐标系:原点(0,0)游戏中世界的原点 平时开发中经常会遇到转UIWindow坐标问题,如:已知一个UI控件的坐标,把它转换到UIWindow时,它对应的UIWindow坐标是什么

在原生APP中集成Unity容器

随着技术的发展,越来越多的APP期望拥有3D,AR的能力。要达到这个目标可以选择使用原生开发,也可以使用Unity成熟的3D开发技术链,通过嵌入的方式将Unity容器嵌入到APP中。这里介绍的是通过嵌入Unity容器的方式来实现APP的3D,AR能力的。 Unity集成到iOS应用的本质是将Unit

iOS中的3种定时器

在iOS中有3种常见的定时器,它们可以根据不同的场景进行选择使用。 1.DispatchSourceTimer: 基于GCD实现。 2.CADisplayLink:基于屏幕刷新实现。 3.Timer:基于RunLoop实现。 DispatchSourceTimer定时器 DispatchSource

iOS视图控件的内容显示和离屏渲染流程

iOS中UI控件内容显示流程 UIKit界面组成 iOS中组成页面的各个元素基本来自UIKit,我们可以修改布局或自定义绘制来修改UIKit元素的默认展示。 UIView的页面显示内容有CALayer负责,事件的接收与响应由UIView自己负责。 为什么需要有这样的分工呢,原因是因为Mac上和iPh

iOS开发基础102-后台保活方案

iOS系统在后台执行程序时,有严格的限制,为了更好地管理资源和电池寿命,iOS会限制应用程序在后台的运行时间。然而,iOS提供了一些特定的策略和技术,使得应用程序可以在特定场景下保持后台运行(即“后台保活”)。以下是iOS中几种常见的后台保活方案,并附上示例代码: 一、后台任务 利用beginBac

flutter系列之:Navigator的高级用法

简介 上篇文章我们讲到了flutter中navigator的基本用法,我们可以使用它的push和pop方法来进行Router之间的跳转。 在flutter中一个Router就是一个widget,但是在Android中,一个Router就是Activity,在IOS中,一个Router是一个ViewC

Swift中UITableViewDiffableDataSource的使用

在 iOS 13 中 Apple 为 UITableView 和 UICollectionView 引入了 DiffableDataSource, 让开发者可以更简单高效的实现 UITableView、UICollectionView 的局部数据刷新。 新的刷新的方法为 apply 通过使用 app

iOS开发基础109-网络安全

在iOS开发中,保障应用的网络安全是一个非常重要的环节。以下是一些常见的网络安全措施及对应的示例代码: Swift版 1. 使用HTTPS 确保所有的网络请求使用HTTPS协议,以加密数据传输,防止中间人攻击。 示例代码: 在Info.plist中配置App Transport Security (

集成Unity3D到iOS应用程序中

如果想让原生平台(例如 Java/Android、Objective C/iOS 或 Windows Win32/UWP)包含 Unity 功能,可以通过Unity 生成UnityFramework静态库包含到项目中进行实现。 Unity 从2019.3 开始支持将 Unity 运行时组件集成到原生

CocoaPods 在iOS开发中养活了这么多项目,它到底是个啥?

对于iOS开发者而言,CocoaPods并不陌生,通过pod相关的命令操作,就可以很方便的将项目中用到的三方依赖库资源集成到项目环境中,大大的提升了开发的效率。CocoaPods作为iOS项目的包管理工具,它在命令行背后做了什么操作?而又是通过什么样的方式将命令指令声明出来供我们使用的?这些实现的背后底层逻辑是什么?都是本文想要探讨挖掘的。