Gray

Beijing, China
Gray

UIButton 设置图片在右的几种方法

UIButton的默认布局是图片在左,标题在右。想要得到一个图片在右,标题在做的UIButton,可以使用以下几种方法 方法一: 改变 Button 的语义属性 不同国家的文字书写方向不一样。在中国,文字书写方式是从左往右,因此UIButton的默认布局是图片在左;而在一些文字书写方向是从右往左的国家里,UIButton的默认布局是图片在右。UIView 有一个 semanticContentAttribute 属性,用来控制 View 的布局。我们可以将其强制更改为从右往左,这样 UIButton 的图片就在右边了: btn.semanticContentAttribute = .forceRightToLeft 方法二: 写一个 UIButton 的子类,重写绘制方法 final class MyCustomTitleImageButton: UIButton { /// 是否把图片放在左边,默认关闭 var isHeadBtn = false /// 是否显示箭头 var needArrow = true var it

By Gray

iOS 开发中的 inline 函数

前两天在开发的时候遇到这样一个问题:想在 OC 代码中实现一个全局变量,这个变量会根据设备类型取不同的值。代码如下: static CGFloat cardLeftMargin = isIPAD ? 30 : 16; // 这里的 isIPAD 是个宏 在 swift 中很容易就能实现这个全局变量。但是在 OC 里面,上面的代码编译时报错了, Initializer element is not a compile-time constant.在 OC 里面,全局变量在编译的时候得有个确定的值。解决这个问题有两个方法,一是用宏定义 #define,二是用inline内联函数。 先贴出来使用 inline 函数解决这个问题的方案: // .m file inline CGFloat cardLeftMargin() { return isIPAD ? 30 : 16; } // .h

By Gray

Swift GCD

基础知识 iOS 多线程实现方式 * Grand Central Dispatch (GCD): 自动管理线程生命周期 * NSOperation: 自动管理线程生命周期,基于 GCD 实现 * NSThread: 手动管理线程生命周期 并发和并行 * 并发: 并发不是真正的多线程,而是通过CPU(单核)在多个线程间快速切换调度,实现接近同时执行的效果 * 并行: 并行是真正的多线程,多个线程能同时执行 同步和异步 * 同步:在当前线程里按顺序执行多项任务,且任务结束的顺序和任务开始执行的顺序是一致的。执行同步任务不会开启新线程,所有的任务都在当前线程执行。把一个同步任务分配出去后,当前线程会一直等到这个任务执行完才能接着运行后面的代码(因为同步任务本身就是分配给当前线程干的) * 异步:异步任务也是按顺序分配给线程的,但是可能会放在多个线程里执行的,所以每个任务结束的顺序有可能是随机的。执行异步任务可能会开启新线程,要具体情况具体分析。把一个异步任务分配出去后,当前线程不用等这个任务执行完就可以执行后面的代码,因为这个异步任务有可能交给别的线程去做了

By Gray

SwiftUI 自适应布局

SwiftUI Adaptive Layout 使用 UIKit 写一套能够根据屏幕尺寸和方向自动更换布局的代码是比较麻烦的(至少从我目前的经验来看~),但是用 SwiftUI 来实现就会轻松一点。 在 SwiftUI 中,Apple 引入了一个概念 Size Classes (尺寸类型),且在横向和竖向两个维度上分别有 Horizontal Size Class 和 Vertical Size Class. Size Classes 可进一步分为两种:regular (标准) 和 compact (紧凑). 而设备的 Size Classes 由它的屏幕尺寸和屏幕方向决定,目前常见的设备 Size Classes 如下表所示, Horizontal Size Class (Width) Vertical Size Class (Height)

By Gray

SwiftUI 预览视图

SwiftUI 一个很强的特性就是可以实时预览页面,边写代码边看代码的实现效果 同时预览多个机型 如果想在 SwiftUI 项目中预览多个机型的话,可以把 Preview 的代码改成如下形式: struct ContentView_Previews: PreviewProvider { static var previews: some View { Group { ContentView() .previewInterfaceOrientation(.portrait) // 这里修改设备屏幕方向 ContentView() .previewInterfaceOrientation(.landscapeLeft) ContentView() .previewDevice(PreviewDevice(rawValue: "iPhone 12 Pro")) // 这里修改设备型号,设备型号

By Gray

Swift Package 技巧及混编兼容问题

创建 Package mkdir somePath cd somePath swift package init (--type library/executable/empty/system module) 其中,type 的四种类型分别对应: * library: 库(默认) * executable: 可执行文件 * empty: 空项目 * system module: 系统模板项目 一般情况下默认即可 创建 package 之后,还可以使用 swift package generate-xcodeproj 创建一个Xcode项目来编译和调试代码 使用 Package 在 Xcode 菜单栏中,选择 file -> add packages 可以指定 package

By Gray

iOS 计算显示字符串和字体所需要的宽度

方法一(推荐) 有时候需要根据一个字符串的内容和所用字体,计算显示这个字符串所需要的 label / view 宽度。可以使用以下方法计算: var greeting = "Hello, playground" let size = greeting.size(withAttributes: [.font: UIFont.systemFont(ofSize: 12)]) print(size.width) // 输出 98.94140625 然后用ceil()对计算结果向上取整,即可得到所需要的宽度 方法二 除了上面的方法外,还有一种方法,如下: var greeting = "Hello, playground" let limitSize = CGSize(width: CGFloat.greatestFiniteMagnitude, height:

By Gray

Swift Syntax Tips 语法技巧

if…case… 有时候一个变量的值会有很多种情况,但是我们只对其中一种或几种情况关心。这时候如果使用switch语句的话,是这样的: switch value { case A: //code default: break } 但是这样会使代码很冗长。我们可以用更加简洁且具备更强大模式匹配功能的if...case...语句: if case A,B { //code } 其中,A、B代表两个条件分支。例如对年龄的判断: var age = 23 if case 20...30 = age, age <= 25 { //code } 懒加载 lazy 开发移动应用时要着重考虑内存和计算资源的节省,懒加载就是为了这种场景而诞生的。懒加载就是直到使用者要读取某个值时才初始化这个值。由于懒加载发生的时间是不定的,且其属性也是会变化的,因此懒加载属性只能用var来定义,其关键词为lazy class student { var

By Gray

pyqt分辨率不同的设备显示问题

当两个不同分辨率不同的设备运行同一个由Qt开发的程序时,会出现控件大小不一致甚至无法正常显示等问题。解决这个问题的方法是在主函数(程序入口)最前面添加一行代码: QCoreApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling) 比如, if __name__ == '__main__': QCoreApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling) app = QApplication(sys.argv) win = myWin() win.show() sys.exit(app.exec()) 假如你是用的C++语言的话,添加如下代码 QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

By Gray