30天学习编写30个Swift小程序

栏目: Swift · 发布时间: 5年前

内容简介:下载=======================================================iOS开发已经做了快4年了,听说Swift也已经有两年多,但是一直都只是把学习停留在表面。无意中听说了有一个叫Sam Lu在Twitter上发起了一个100天做40个Swift小程序的活动,再加上国内看到了Allen_朝辉写的Swift学习的文章,心里暗自下了一个决定:
30天学习编写30个Swift小程序
更新 :所有代码已经更新到Swift4.1,请移步 github

下载

=======================================================

iOS开发已经做了快4年了,听说Swift也已经有两年多,但是一直都只是把学习停留在表面。无意中听说了有一个叫Sam Lu在Twitter上发起了一个100天做40个Swift小程序的活动,再加上国内看到了Allen_朝辉写的Swift学习的文章,心里暗自下了一个决定: 30天写30个Swift小程序 ,希望能推动自己学习Swift的计划。这30个小程序难度不同,有的一个晚上就能写完,有的要占用周末大部分时间来细研究。大部分不会的东西Google都能找到,就算Swift版本没有找到Objective-C版本然后用Swift重写就好,好在他们对应关系比较明确。

用例方面,既参考了Sam Lu的40个小项目,也参考了Allen_朝辉的项目,还有的是我自己仿写的知名App。

其实我并不是唯一在国内发起这个30天30个Swift小程序并且将其开源的作者,但是我可能是唯一一个从头到尾用XCode 8 + Swift3环境编写的作者。而且,为了让代码更加可读,所有代码完全手写,而非用Storyboard(除了只能用Storyboard的,例如apple watch app)。实际上多人协作的项目中我们尽可能少用Storyboard,因为很容易出现冲突问题。况且从学习的角度,storyboard很难说清楚操作步骤是什么。在这上面我其实花了不少时间,但是我认为很值得。

希望能有更多对Swift感兴趣的开发者加入这项#30天30个Swift小程序 的活动里面来。以下为Github链接: github.com/nimomeng/30…

Project 30 - Google Now App

30天学习编写30个Swift小程序

我学到了

  • 这次Project演示了Present/Dismissd如何做Transition动画,这和做Push/Pop的转场动画的基本原理都是一样的
  • 这次的动画参考了BubbleTransition的动画效果,在它之上加了修改,支持传入自定义的UI属性,方便做组合型动画(例如本例中按钮不仅放大而且上下移动)
  • 动画变化的原理是将相应的ViewController进行Scale变换,再通过一个Bubble的蒙版看起来像是气泡效果
  • 其它的细节知识如下:
    • 画圆形按钮的方法,必须要cornerRadius属性为边长的1/2,具体代码如下:
triggerButton.layer.cornerRadius = triggerButton.frame.width / 2
        triggerButton.layer.masksToBounds = true
复制代码

Project 29 - Beauty Contest

30天学习编写30个Swift小程序

我学到了

  • 这个项目是基于 Yalantis的Koloda 来制作的。 Koloda是一个非常好用的UIImage选择器
  • Swift中的懒加载的使用方法:
    • 两种方式:
lazy var firstWay = "first"
复制代码

以及

lazy var secondWay: String = {return "Second"}()
复制代码

注意:第二种方式要注意定义好字段类型,以便于编译时的类型检查;以及不要忘记最后的小括号

  • 为什么要用Lazy:因为这里面需要先知道KolodaView的尺寸,才能定Overlay的尺寸。因此这里有一个依赖关系,因此用懒加载最合适。
  • Swift中的unowned和weak的区别:
    • unowned更像OC里的unsafe_unretained; weak还是那个weak。
    • 如果确定使用时一定不会被释放,可以用unowned;否则最好用weak

Project 28 - SnapChat Like App

30天学习编写30个Swift小程序

我学到了

  • UIScrollView的基本使用和细节小点,例如禁止弹跳的bounces属性,整页切换的isPagingEnabled属性,起始位置contentOffset属性等

  • 加载子Viewcontroller的addChildViewController方法

  • "xxx class has no initializers"问题:

    You have to use implicitly unwrapped optionals so that Swift can cope with 
      circular dependencies (parent <-> child of the UI components in this case) 
      during the initialization phase.
    
      @IBOutlet var imgBook: UIImageView!
      @IBOutlet var titleBook: UILabel!
      @IBOutlet var pageBook: UILabel!
    复制代码
  • 权限问题,具体错误描述为: "This app has crashed because it attempted to access privacy-sensitive data without a usage description. The app's Info.plist must contain an NSPhotoLibraryUsageDescription key with a string value explaining to the user how the app uses this data." 解决方法:iOS10之后的权限问题,在info.plist里添加相应的权限以及描述即可。 本例中权限为: NSCameraUsageDescription PhotoMe needs the camera to take photos. NSMicrophoneUsageDescription PhotoMe needs the microphone to record audio with Live Photos. NSPhotoLibraryUsageDescription PhotoMe will save photos in the Photo Library.

  • AVCaptureSession 的使用方法:

    • AVCaptureSession是AVFoundation的核心类,用于捕捉视频和音频,协调视频和音频的输入和输出流.
    • 创建 AVCaptureSession 实例,并设置其 sessionPreset 值,也就是设置画面的质量。
    • 给Session添加Input。一般是Video或者Audio数据,也可以两者都添加,即AVCaptureSession的输入源AVCaptureDeviceInput。具体步骤是先获取对应的 device 实例(此时决定是用Video还是Audio),再由实例获取其Input Source。最后将input source add到session中。
    • 给Session添加Output,即AVCaptureSession的输出源。一般输出源分成:音视频源,图片源,文件源等。这里以静态图片的输出源为例,指的是AVCapturePhotoOutput。最后将其也add到session中。
    • 设置预览图层,即AVCaptureVideoPreviewLayer。在input,output等重要信息都添加到session以后,可以用session创建AVCaptureVideoPreviewLayer,这是摄像头的视频预览层。这里千万别忘了将Layer添加到View中。
    • 启动Session,即 captureSesssion.startRunning()
  • Photo的捕获方法

    AVCapturePhotoSettings
    
func capture(_ captureOutput: AVCapturePhotoOutput, didFinishProcessingPhotoSampleBuffer photoSampleBuffer: CMSampleBuffer?, previewPhotoSampleBuffer: CMSampleBuffer?, resolvedSettings: AVCaptureResolvedPhotoSettings, bracketSettings: AVCaptureBracketedStillImageSettings?, error: Error?)
复制代码

中执行获取图像的具体逻辑。本例中是先将buffer转换为data,再转换为UIImage,最终write到相册文件夹中。

Project 27: Carousel Effect (跑马灯效果)

30天学习编写30个Swift小程序

我学到了

  • UICollectionView的使用

    • 与UItableView的不同在于,每一个对应的Cell(不论是content的cell还是header,footer的),都需要预先执行register方法
    • Cell间距太窄的问题,可以通过minimumLineSpacingForSection的DataSource代理方法来解决掉
    • 如果选择的layout为UICollectionViewFlowLayout,可以通过修改scrollDirection属性来修改滚动方向
  • 自定义Layout要在对应的子类里实现如下方法

    prepare()
      shouldInvalidateLayout(forBoundsChange newBounds: CGRect)
      targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) 
      layoutAttributesForElements(in rect: CGRect)
    复制代码

其中:

  • prepare可以定义初始化操作

  • shouldInvalidateLayout,判断是否需要更新每个Cell的bounds。如果我们的layout是那种每个cell需要动态变化的layout,则设置为true;否则为了性能考虑,请设置为false。默认为flase。

  • targetContentOffset,如果我们需要图片在滚动的过程中在特定位置可以停下来(类似iphone上专辑图片的选择),请在此函数中国年给出停下来的具体规则

  • layoutAttributesForElements 返回所有元素此时的所有布局。我们会在这里定义在滚动过程中所有其他元素的attribute布局相关属性。例如本例中,离屏幕中间越近,图片被缩放的越大;离屏幕越小,图片被缩放的越小。

  • Reference:

  • Visual Effect View的使用

    • 尽量在需要模糊化的图层之后添加进去,会自动虚化所覆盖的图层

      let blurEffect: UIBlurEffect = UIBlurEffect(style: .light)
      let blurView: UIVisualEffectView = UIVisualEffectView(effect: blurEffect)
      blurView.frame = self.view.bounds
      bgView.addSubview(blurView)
      复制代码
  • UISegmentedControl 的使用(略)

  • 其它:#selector()中的func如果带有参数,请将具体参数也一起写进去,例如: #selector(action_segmentValueChanged(sender:) 这个规则和OC不太一样,要注意。

Project 26 - Twitter-like Splash

30天学习编写30个Swift小程序

我学到了

  • 这个效果尝试了用简单的UIView的animation方法会比较吃力,因此转而使用CAAnimation来做。
  • 我们需要的效果,设置keyPath为"bounds"。吐槽一下,苹果为什么不做一个枚举。。。完整的keyPath列表如下所示:
    30天学习编写30个Swift小程序
  • 由于logo的动画定制化要求比较高,所以关于这个变化的动画,选择CAAnimation里的CAKeyFrameAnimation来做。主要关注keyTimes,values属性,也就是keyFrame的属性。timingFunctions属性是keyframe的count - 1, 也就是frame1到frame2,frame2到frame3的动画过渡函数。这个不多说了,之前的Project有提到过。
  • 在logo变大的过程中,logo中间的alpha值也应该有白色变为透明,因此应该先添加一个maskView,藏在最上层,logo层之下,作为白色的底。动画trigger的时间和duration与logo的动画保持步调一致,并且记得在动画complete的时候被移除掉。这里使用了CABasicAnimation的animationDidStop代理来完成。
  • logo的透明度变化既可以使用简单的UIView的animation方法来做,也可以采用layer级别的CABasicAnimation来完成。因为对前者比较熟悉了,所以我在这里使用后者,注意keyPath是 opacity 。代码比较简单,这里不赘述。
  • 整体效果还是很炫的:)
  • CAKeyFrameAnimation参考此篇文档

Project 25 Custom Transition

30天学习编写30个Swift小程序

我学到了

  • NavigationController的动画是可以自定义的,去实现UINavigationControllerDelegate里的方法就好
  • 如果切换动画只需要关注之前的VC和之后的VC,不需要关注中间过程,直接实现以下方法即可:
navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning?
复制代码
  • 上述方法的返回值 UIViewControllerAnimatedTransitioning 需要自定义动画,需要实现 UIViewControllerAnimatedTransitioning 代理,实现具体的两个方法:
    • 转场动画时间,直接返回一个时间即可
transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval
复制代码
  • 转场动画过程,如下所示,这个比较复杂:
animateTransition(using transitionContext: UIViewControllerContextTransitioning) 
复制代码
  • 第一步,获得转场动画的fromVC,toVC,container:
let fromVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from) as! XXXController
let toVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to) as! YYYController
let container = transitionContext.containerView
复制代码
  • 之后是动画前的准备工作,例如image赋值,例如坐标的计算:
let snapshotView = fromVC.selectedCell.imageView.snapshotView(afterScreenUpdates: false)
snapshotView?.frame = container.convert(fromVC.selectedCell.imageView.frame, from: fromVC.selectedCell)
....
复制代码
  • 最后当然是Animation动画的执行逻辑了,可以通过UIView的animate方法去实现。具体参数和方法可以参考之前的Project来进灵活组合。
    transitionContext.completeTransition(true)
    transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
    
  • 如果需要关注动画的执行过程,则在上述的基础之上还应该实现下述方法:
navigationController(_ navigationController: UINavigationController, interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning?
复制代码

其中, UIViewControllerInteractiveTransitioning 是动画过渡对象

  • 获取iOS中手从左往右沿屏幕滑动的事件,是通过 UIScreenEdgePanGestureRecognizer 方法并设置其edges为left实现的:
let edgePanGesture = UIScreenEdgePanGestureRecognizer(target: self, action: #selector(edgePanGestrueAction(_:)))
edgePanGesture.edges = UIRectEdge.left
复制代码
  • 这篇教程针对的是Push与Pop的自定义动画的制作
  • 参考 文档1 ,文档2,并在他们的基础之上做了改动
  • 这个例子我很喜欢,图片是罗斯科。

Project 24 - Vertical Menu Transition

30天学习编写30个Swift小程序

我学到了

  • 本文和Google Now App项目思路一致,都是针对Present/Dismiss的操作进行自定义Transition
  • 由于动画需要局部截图,因此建议将Present和Dismiss的Transition写到一起,通过一个变量来进行不同动画的切换和控制。变量可以通过 animationController(forDismissed dismissed: UIViewController)animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) 来进行设置。
  • target-action方式,一般会将target设置为self。如果设置为对应的delegate,则action字段应该填写 #selector(CustomTransitionDelegate.functionName)
  • 在Present/Dismiss的自定义转场动画中,记得在complete回调中加入动画结束语句块:
transitionContext.completeTransition(true)
    fromViewController?.endAppearanceTransition()
    toViewController?.endAppearanceTransition()
复制代码

Project 23 - Side Navigation App

30天学习编写30个Swift小程序

####我学到了

  • Swift-OC混编方法
    • 新建一个头文件,例如名为Bridge.h
    • 单击Project文件,选择Build Setting,找到Objective-C Bridge Header,输入Bridge.h的路径
    • 之后所有需要在swift文件中引用的OC文件的头文件放到Bridge.h中进行import
30天学习编写30个Swift小程序
  • 侧滑效果借鉴了 SWRevealViewController ,使用步骤如下(原项目只提到了OC中的调用方法)
    • 项目中至少有以下几类viewController:第一页展示的VC,比如FrontViewController;tabeView所在的MenuViewController
    • 在AppDelegate中根据规则创建自定义Window,具体步骤为:
      • 建立UIWindow
      • 新建两个UINavigationController,分别以FrontViewController和MenuViewController为rootViewController
      • 实例化SWRevealViewController,并设置rearViewController的值和frontViewController的值。其中,rearViewController是tableView所在的UINavigationController,frontViewController是FrontViewController所在的UINavigationController
      • 将实例化的SWRevealViewController设置为Window的rootViewController
window = UIWindow(frame: UIScreen.main.bounds)
 let rearNavigationController = UINavigationController(rootViewController: MenuViewController())
let frontNavigationController = UINavigationController(rootViewController: FrontViewController())
let revealController = SWRevealViewController(rearViewController: rearNavigationController, frontViewController: frontNavigationController)
revealController?.delegate = self 
window?.rootViewController = revealController
window?.makeKeyAndVisible()
复制代码
  • 需要在每一个ViewController中加入左滑激活Menu的逻辑,一句话:
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
复制代码
  • 效果需要,最好隐藏掉status bar以及navigationBar:
self.navigationController?.isNavigationBarHidden = true
复制代码
override var prefersStatusBarHidden: Bool {  return true  }
复制代码

Project 22 - Basic Animations

30天学习编写30个Swift小程序

我学到了

  • 本次涉及到最基本的UIAnimation,很多复杂的Animation其实是各种简单的Animation的叠加,所以不能轻视
  • Position的Animation既可以通过直接修改frame的origin属性,也可以直接通过UIView的transform来进行修改
  • Opacity直接改Alpha值就可以了
  • Scale是修改了UIView的transform,传入要缩放的相对比例并创建对应的CGAffineTransform对象。例如:
heartView.transform = CGAffineTransform(scaleX: 1.5, y: 1.5)
复制代码
  • Color是直接修改backgroundColor就可以了
  • Rotation是通过修改UIView的transform,传入要旋转的值并创建对应的CGAffineTransform对象。其中,值为0 - 2*Pi之间,表示0到360°之间。注意,正值为逆时针转动。例如:
self.rollingBallView.transform = CGAffineTransform(6.28)
复制代码

Project 21 CoreData App

30天学习编写30个Swift小程序

我学到了

  • 一定要勾选 UseCoreData,这样在Appdelegate里会自动生成部分代码
    30天学习编写30个Swift小程序
  • 不一定非要通过Editor生成SubClass
  • 本例中Entity如图所示:
30天学习编写30个Swift小程序
  • 在需要调用CoreData的类中,import CoreData
  • 本例比较简单,只进行了getResult和Add的操作,思路分别为:
    • getResult:
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: EntityName)
        do {
            let searchResults = try getContext().fetch(fetchRequest)
            dataSource = searchResults as! [TodoList]
        } catch  {
           // todo error handler
        }
复制代码

注意,或取出来的searchResult可以直接实例化为TodoList(TodoList是我的Entity名字),这样后续就可以直接使用TodoList的content方法了。

  • saveContent:
let context = getContext()
        // 定义一个entity,这个entity一定要在xcdatamodeld中做好定义
        let entity = NSEntityDescription.entity(forEntityName: EntityName, in: context)
        let todoList = NSManagedObject(entity: entity!, insertInto: context)
        todoList.setValue(content, forKey: "content"
        do {
            try context.save()
        }catch{}
复制代码

对应getConent方法的代码两行:

let appDelegate = UIApplication.shared.delegate as! AppDelegate
return appDelegate.persistentContainer.viewContext
复制代码

如此操作后使用的时候直接通过获取TodoList对象,然后调用其content方法即可完成。 cell.textLabel?.text = (dataSource[indexPath.row]).content

  • UIAlertController添加输入款的方法:
alertController.addTextField { (textField) in
textField.placeholder = "Please input the todo Item"}
复制代码
  • 该方法在XCode8.3 + Swift3.2测试通过,CoreData在iOS10的变化很大,之前的版本可能和上述操作方法有出入
  • 参考文章

Project 20 - Apple Watch OS App - Guess Game

30天学习编写30个Swift小程序

我学到了

  • Watch程序,需要在create project的先选择Watch OS的Section,之后选择如下:

    30天学习编写30个Swift小程序
  • watch中的UI只可以通过Storyboard来进布局,布局文件在WatchKit App中的Interface.storyboard中

  • 例子中涉及到了watch和主app的交互,这里使用的是 WCSession 方法,使用步骤如下:

    • 确定app所在设备是否支持WCSession
    • 生成一个WCSession对象,并设置其delegate
    • 激活此WCSession对象 至此部分,代码为:
let wcsession = WCSession.default()
        if WCSession.isSupported() {
            wcsession.delegate = self
            wcsession.activate()
        }
复制代码
try wcsession.updateApplicationContext(["numberToBeGuessed": number])
func session(_ session: WCSession, didReceiveApplicationContext applicationContext: [String : Any]) 
复制代码

Project 19 - TodayWidget

30天学习编写30个Swift小程序

我学到了

  • 创建Today Widget: File > New > Target…,然后选择 iOS 中的 Application Extension 的 Today Extension
  • 为了方便Widget与App数据共享,需要切换成App Group模式。步骤为打开主target,选择capability,找到App Group,打开:
30天学习编写30个Swift小程序
  • 在主Target下为这个app group添加一个名称,然后去Extension的target下去采用相同操作,并勾选这个group
  • 我们可以采用UserDefault作为主app与widget之间的共享存储。但是此处不能使用standardUserDefaults,只能通过suiteName的方式来进行共享,且名字是之前在app group中添加的名称,代码如下:
let userDefault = UserDefaults(suiteName: "group.nimoAndHisFriend.watchDemo")
复制代码
  • 在Widget的ViewController里写入相应的读取逻辑代码:
let userDefaults = UserDefaults(suiteName: "group.nimoAndHisFriend.watchDemo")
var leftTimeWhenQuit = userDefaults?.double(forKey: "lefttime")
复制代码

为了想让widget里的数据也进行同步更新,可以在extension的代码里也加入一个timer来进行同步操作。这样widge和主程序的widge即可同步

  • 如果想了解更多关于Widget的使用,请参考文档

Project 18 - Spotlight Search

30天学习编写30个Swift小程序

我学到了

  • Spotlight Search的使用:
    import CoreSpotlight
    
let tmpItems = [searchItem]
CSSearchableIndex.default().indexSearchableItems(tmpItems) { (error) in
}
复制代码
  • 如果调试过程中,发现模拟器上重新了之前的spotlight缓存无法清除的情况,请更换新的模拟器,或者重置模拟器。或者干脆切换成真机进行调试,真机这种情况少一些:)

Project 17 - 3D Touch Quick Action

30天学习编写30个Swift小程序
self.window?.traitCollection.forceTouchCapability == .available
UIApplicationShortcutItem
UIViewControllerPreviewingDelegate
self.registerForPreviewing(with: self, sourceView: self.view)
func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) 
复制代码
  • 如果想实现例子中的额外Action button,需要override对应的previewActionItems属性,并返回你需要的UIPreviewAction的Array

Project 16 - LoginAnimation

30天学习编写30个Swift小程序

我学到了

  • 开始以为很简单,普通UIView的Animation方法即可完成。后来发现弹跳效果并不是我使用的常规方法可以完成的
  • 弹跳动画需要使用 usingSpringWithDamping 来完成,其中的属性要注意:
    • usingSpringWithDamping:值越小动画越夸张,借用网上图来说明其区别:

      30天学习编写30个Swift小程序
    • initialSpringVelocity:值越大则起始速度越大,再借用网上图片来说明其区别:

      30天学习编写30个Swift小程序
    • options的各个动画曲线有何区别:可以看图来进行区分:

30天学习编写30个Swift小程序
  • UIView.animation的usingSpringWithDamping与不带usingSpringWithDamping的参数动画有什么区别呢?可以看下图:
30天学习编写30个Swift小程序
  • 带Spring属性的动画太有意思了!:)
  • 此部分参考文档1, 文档2

Project 15 - Tumblr Menu

30天学习编写30个Swift小程序

我学到了

  • 这个例子本质上是对动画+BlurEffect
  • 三排的动画有一个先后顺序,这个可以通过animation的delay参数进行调节
  • button的上图下文效果需要设置,这里自定义了一个CustomButton,对样式进行了封装。参考了这篇文章

Project 14 - Video Splash

30天学习编写30个Swift小程序

我学到了

  • 创建一个AVPlayerViewController,并将其view放到背景中
  • 之后结合AVPlayerViewController进行视频播放,并自动循环
  • 视频播放部分借鉴了此篇文章中的第十个用例,据说也是参考了一个叫VideoSplashViewController的库

Project 13: Animation In TableViewCell

30天学习编写30个Swift小程序

我学到了

  • 开始的思路是在willDisplay的delegate里进行动画操作,效果良好,但是发现在滚动cell时发生cell错乱的现象,原因是在滚动时cell重绘导致重新调用willDisplay进而坐标错误。粗看了下,解决起来有点儿麻烦,于是换思路。以此这种“进场动画”不应该在渲染过程中的delegate中执行。
  • 将动画放到ViewWillAppear里来做。可以通过tableView的visibleCells获取将要显示的所有cell的Array,逐一遍历来进行动画操作。
  • 改变Cell的动画,采用上一章所说的usingSpringWithDamping的动画,usingSpringWithDamping设置为0.8,initialSpringVelocity设置为0.(不然动画会弹跳过大,造成顺次露出白色间隙,很不美观)
  • 改变Cell的具体方式,既可以直接操作 cell.frame.origin.y ,也可以通过 cell.transform = CGAffineTransform(translationX: 0, y: tableHeight) ,效果是一样的。不过如果要用到缩放或者旋转的动画,恐怕只能使用后者了。
  • 动画确实是很有意思的:)

Project 12 - Emoji Slot Machine

30天学习编写30个Swift小程序

我学到了

Int(arc4random())%(emojiArray.count - 2) + 1

Project 11 - Gradient in TableView

30天学习编写30个Swift小程序

我学到了

  • 这个比较简单,注意将CAGradientLayer应用在UITableViewCell上即可
  • 建议将CAGradientLayer作为cell的backgroundView,而不是直接在cell.layer上进行添加
  • 美观起见,隐藏掉Cell的Select效果以及separatorStyle: table.separatorStyle = .none cell.selectionStyle = .none

Project 10 - Stretchy Header

30天学习编写30个Swift小程序

我学到了

  • 通过监听ScrollView(及其子类)的scrollViewDidScroll代理可以知道scrollView被拉动的位移(offset)
  • 通过位移以及限定的缩放值可以得出图片需要放大的倍率
  • 通过设置ImageView的transform来完成修改即可,核心代码为
bannerImgView.transform = CGAffineTransform(scaleX: scaleFactor, y: scaleFactor)
复制代码

Project 9 - Swipeable Cell

30天学习编写30个Swift小程序

我学到了

简单起见,我用Project 13的代码基础上进行修改,换了个清爽的绿色:)

  • 实现editActionsForRowAt这个delegate方法,返回值是Array,新建几个你需要的功能返回即可
  • 每一个Action直接通过UITableViewRowAction的init方法新建即可。在新建方法里有block,直接将点击逻辑写进去就行了。
  • 这种交互适用于Accessory比较简单的情况,例如对交互按钮大小和内容无要求的情况;如果有特殊要求,需要自定义UITableViewCell,手动控制Cell与捕捉UIPanGesture来进行实现。注意,这种方式要排除上下滑动Cell的情况,不要错误触发。

Project 8 - Color Gradient

30天学习编写30个Swift小程序

我学到了

  • 颜色渐变效果采用的是类CAGradientLayer
  • 色彩空间的概念可以借助于Color数组来实现,注意,成员变量是CGColor类型,然后通过设置CAGradientLayer的colors属性来实现
  • 上下滑动时改变颜色是通过加PanGestureRecognizer来实现。具体效果参考了应用Solar
    30天学习编写30个Swift小程序

Project 7 - Simple Photo Browser

30天学习编写30个Swift小程序

我学到了

  • 缩放图片的方式:将imageView添加到ScrollView上
  • 设置好scrollView的max/minZoomScale
  • 设置好delegate对象,至少实现viewForZooming的代理方法

Project 6 - Video Player

30天学习编写30个Swift小程序

我学到了

  • AVPlayer:视频播放器实体
  • AVPlayerViewController:简单封装了的视频播放器,有简单的控制功能
  • AVPlayerLayer:视频的Layer层,所有功能需要写控件进行控制,适合对播放器进行深度开发
  • 后台播放的plist设置方式
  • do...catch...语法的使用
  • background modes的设置。
  • 如何做到app在后台长期运行:参考简书的文章
  • 如何显示锁屏信息,以及如何响应锁屏设置(实现remoteControlReceived的代理方法)

Project 5 - Pull To Refresh

30天学习编写30个Swift小程序

我学到了

  • 下拉刷新组件: UIRefreshControl 设置好提示文字 attributedTitle ,添加好target事件( UIControlEvents.valueChanged 事件)后,添加到tableView中,即可

Project 4 - Limited Input Text Field

30天学习编写30个Swift小程序

我学到了

  • 通过新建UIBarButtonItem来创建navigationBarItem的左右Item
  • 通过TextView的textViewDidChange事件捕捉当前输入内容,从而进行限制输入字数
  • 通过监听NSNotification.Name.UIKeyboardWillChangeFrame事件来监视Keyboard的弹出和收起。在对应回调中,通过note.userInfo?[UIKeyboardFrameEndUserInfoKey]来拿到键盘的endFrame,从而拿到键盘的高度,对计数器进行frame操作
  • 同理,通过note.userInfo?[UIKeyboardAnimationDurationUserInfoKey]拿到键盘的动画duration,进而可以通过UIView的animation动画做到同步变化计数器的frame

Project 3 - Find My Position

30天学习编写30个Swift小程序

我学到了

  • 定位点配置: 在plist中添加配置: NSLocationAlwaysUsageDescription
  • 用CLLocationManager来进行定位
  • 在逆地址解析的方法reverseGeocodeLocation调用时如果遇到了block中一直出现 Domain=GEOErrorDomain Code=-8 "(null)" 之类的错误,将 CLGeocoder 改成全局变量即可
  • 之后这种简单功能可以直接通过苹果内置方法来完成,不需要再通过引入高德SDK(省去了高德SDK的大小)

Project 2: Watch Demo

30天学习编写30个Swift小程序

我学到了

  • Update cocoaPods to 1.2.0
  • Learn how to use SnapKit (Quite similar with Masonry)
  • Learn how to use Timer in Swift
  • 我学到了: guard语句,详见guard详解

Project 1: Change Custom Font

30天学习编写30个Swift小程序

我学到了

  • 如何修改字体属性,熟悉字体属性

  • 字体名称可以去storyboard中查询,或者通过如下代码来进行查询:

    func printAllSupportedFontNames() {
    let familyNames = UIFont.familyNames
    for familyName in familyNames {
        print("++++++ \(familyName)")
        let fontNames = UIFont.fontNames(forFamilyName: familyName)
        for fontName in fontNames {
            print("----- \(fontName)")
        }}}
    复制代码

写在最后:

能坚持看到这里的,我给你们手动双击666!

30天学习编写30个Swift小程序

实话实说,文章有点标题党,实际开发时间是40天左右,因为开发时间在下班后到睡觉前,所以有时因为要出去聚餐,有时犯懒,还有时晚上要你懂得,所以完成这三十个项目的时间比计划的时间要长。。。

30天学习编写30个Swift小程序

写完这些项目,感觉上一方面是提高了使用Swift语言的熟练度,另一方面更是复习了一遍iOS开发的知识点,因为写到后来我已经基本感觉不出来跟用OC开发有什么思路上的差异。这也回答了别人问过我的问题,“如果我现在学iOS开发,是应该学OC还是Swift”:

我觉得从iOS SDK的熟悉角度来说,没有本质区别,如果熟悉OC下对应语法去使用Swift写没有太大区别。所以与其花时间纠结不如赶紧找两个项目上手进行练习。

30天学习编写30个Swift小程序

下一步,我打算再重新梳理下Swift语法,对这些项目进行小规模的重构,从结构上去看看能否挖掘到Swift的特性,从另一个角度(目前是功能角度)来学习Swift。所以也许还会有下一篇。

30天学习编写30个Swift小程序

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Bad Blood

Bad Blood

John Carreyrou / Knopf / 2018-5-21 / USD 27.95

The full inside story of the breathtaking rise and shocking collapse of Theranos, the multibillion-dollar biotech startup, by the prize-winning journalist who first broke the story and pursued it to t......一起来看看 《Bad Blood》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

SHA 加密
SHA 加密

SHA 加密工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具