[Swift通天遁地]九、拔剑吧-(14)创建更美观的景深视差滚动效果

景深视差经常被应用在游戏项目中。

本文将演示创建更美观的景深视差滚动效果。

首先确保已经安装了所需的第三方类库。双击查看安装配置文件【Podfile】

1 platform :ios, '12.0'
2 use_frameworks!
3 
4 target 'DemoApp' do
5     source 'https://github.com/CocoaPods/Specs.git'
6     pod 'Presentation'
7 end

根据配置文件中的相关设置,安装第三方类库。

安装完成之后,双击打开项目文件【DemoApp.xcodeproj】

在左侧的项目导航区,打开视图控制器的代码文件【ViewController.swift】

  1 import UIKit
  2 //引入已经安装的第三方类库
  3 import Presentation
  4 
  5 //修改当前类的父类,这里使用第三方类库提供的父类
  6 class ViewController: PresentationController {
  7 
  8     //添加一个结构体类型,
  9     //用来更加方便的管理背景视图中的视差图片,
 10     //四个属性依次表示:
 11     struct BackgroundImage
 12     {
 13         //图片的名称
 14         let name: String
 15         //水平初始位置
 16         let left: CGFloat
 17         //垂直初始位置
 18         let top: CGFloat
 19         //滚动的速度
 20         let speed: CGFloat
 21         
 22         //添加一个初始化方法,用来初始化结构体的各个属性。
 23         init(name: String, left: CGFloat, top: CGFloat, speed: CGFloat)
 24         {
 25             //依次设置各个属性的值
 26             self.name = name
 27             self.left = left
 28             self.top = top
 29             self.speed = speed
 30         }
 31         
 32         //添加一个方法,用来获取当滚动到某个页面时到位置属性
 33         func positionAt(_ index: Int) -> Position?
 34         {
 35             //添加一个位置变量
 36             var position: Position?
 37             
 38             //判断当前是否时是需要显示滚动效果的页面。
 39             if index == 0 || speed != 0.0
 40             {
 41                 //根据起始位置、当前页面的序号、计算当前页面的视差图片的水平位置。
 42                 let currentLeft = left + CGFloat(index) * speed
 43                 //设置视差图片的新的位置,视差图片的垂直坐标,是保持不变的。
 44                 position = Position(left: currentLeft, top: top)
 45             }
 46             
 47             //返回设置好的位置
 48             return position
 49         }
 50     }
 51     
 52     //添加一个导航条按钮控件,作为导航条左侧的按钮
 53     lazy var leftButton: UIBarButtonItem =
 54         { [unowned self] in
 55             
 56             //对导航条按钮进行初始化操作,并设置它的标题、样式和动作属性。
 57             let leftButton = UIBarButtonItem(title: "Previous", style: .plain,
 58                                              target: self, action: #selector(moveBack))
 59             
 60             //设置标题的前景颜色为黑色
 61             leftButton.setTitleTextAttributes(
 62                 [NSAttributedString.Key.foregroundColor : UIColor.black], for: .normal)
 63             
 64             //返回设置好的按钮控件
 65             return leftButton
 66             }()
 67     
 68     //创建另一个导航条按钮控件,作为导航条右侧的按钮。
 69     lazy var rightButton: UIBarButtonItem =
 70         { [unowned self] in
 71             
 72             //对导航条按钮k进行初始化操作,并设置它的标题、样式和动作属性。
 73             let rightButton = UIBarButtonItem(title: "Next", style: .plain,
 74                                               target: self, action: #selector(moveForward))
 75             
 76             //设置标题文字的前景颜色为黑色。
 77             rightButton.setTitleTextAttributes(
 78                 [NSAttributedString.Key.foregroundColor : UIColor.black], for: .normal)
 79             
 80             //返回设置好的按钮控件。
 81             return rightButton
 82             }()
 83     
 84     override func viewDidLoad() {
 85         super.viewDidLoad()
 86         // Do any additional setup after loading the view, typically from a nib.
 87         
 88         //依次设置导航控制器左侧和右侧的导航按钮。
 89         navigationItem.leftBarButtonItem = leftButton
 90         navigationItem.rightBarButtonItem = rightButton
 91         
 92         //设置根视图的背景颜色。
 93         view.backgroundColor = UIColor(red: 1.0, green: 188.0/255, blue: 0, alpha: 1)
 94         
 95         //调用两个方法:
 96         //方法一:用来设置滚动的标题
 97         configureSlides()
 98         //方法二:用来设置具有景深效果的背景视图。
 99         configureBackground()
100     }
101 
102     //添加一个方法,用来配置滚动标题
103     func configureSlides()
104     {
105         //初始一个字体对象
106         let font = UIFont(name: "HelveticaNeue", size: 24.0)!
107         //初始化一个颜色对象
108         let color = UIColor(red: 1.0, green: 232.0/255, blue: 169.0/255, alpha: 1)
109         //作为标题文字的字体和颜色。
110         
111         //初始化一个段落样式对象
112         let paragraphStyle = NSMutableParagraphStyle()
113         //设置段落样式的对齐方式为居中
114         paragraphStyle.alignment = NSTextAlignment.center
115         
116         //初始化一个属性常量,作为标题文字的字体、颜色和段落样式。
117         let attributes = [NSAttributedString.Key.font: font, NSAttributedString.Key.foregroundColor: color, .paragraphStyle: paragraphStyle]
118         
119         //初始化一个字符串数组,作为五个滚动标题的内容。
120         let titles = [
121             "Parallax is a displacement or difference in the apparent position of an object viewed along two different lines of sight.",
122             "It's measured by the angle or semi-angle of inclination between those two lines.",
123             "The term is derived from the Greek word παράλλαξις (parallaxis), meaning 'alteration'.",
124             "Nearby objects have a larger parallax than more distant objects when observed from different positions.",
125             "http://www.coolketang.com"]
126             //对标题数组进行遍历,设置标题的样式
127             .map
128             { title -> Content in
129                 //初始化一个标签对象,
130                 let label = UILabel(frame: CGRect(x: 0, y: 0, width: 550, height: 200))
131                 //设置标签对象最多显示的行数
132                 label.numberOfLines = 5
133                 //设置标签对象显示的文字内容,和文字的外观样式。
134                 label.attributedText = NSAttributedString(string: title, attributes: attributes)
135                 //初始化一个位置对象
136                 let position = Position(left: 0.0, top: 0.35)
137                 
138                 //使用标签和位置初始化一个内容对象,并返回内容对象作为页面的标题
139                 return Content(view: label, position: position)
140         }
141         
142         //初始化一个滑动控制器类型的数组对象。
143         var slides = [SlideController]()
144         
145         //添加一个执行五次的循环语句,用来往数组中添加控制器。
146         for index in 0...(titles.count - 1)
147         {
148             //初始化一个滑动控制器对象,并设置它的标题内容
149             let controller = SlideController(contents: [titles[index]])
150             //往滑动控制器中,添加一个标题滚动的动画。
151             controller.add(animations: [Content.centerTransition(forSlideContent: titles[index])])
152            
153             if(index == titles.count - 1)
154             {
155                 controller.setLast()
156             }
157             
158              //将配置好的滑动控制器,添加到数组中。
159             slides.append(controller)
160         }
161         
162         //将滑动控制器数组添加到景深视图控制器中。
163         add(slides)
164     }
165     
166     //添加另一个方法,用来配置具有景深效果的背景视图。
167     func configureBackground()
168     {
169         //初始化一个图像视图数组,作为背景视图中的视差图片。
170         let backgroundImages =
171             [
172                 //往数组中,依次添加同结构体类型,生成的九张视差图片,
173                 //并设置每张视查图片的名称、位置、和速度等属性。
174                 BackgroundImage(name: "Trees", left: 0.0, top: 0.743, speed: -0.3),
175                 BackgroundImage(name: "Bus", left: 0.02, top: 0.77, speed: 0.25),
176                 BackgroundImage(name: "Truck", left: 1.3, top: 0.73, speed: -1.5),
177                 BackgroundImage(name: "Roadlines", left: 0.0, top: 0.79, speed: -0.24),
178                 BackgroundImage(name: "Houses", left: 0.0, top: 0.627, speed: -0.16),
179                 BackgroundImage(name: "Hills", left: 0.0, top: 0.51, speed: -0.08),
180                 BackgroundImage(name: "Mountains", left: 0.0, top: 0.29, speed: 0.0),
181                 BackgroundImage(name: "Clouds", left: -0.415, top: 0.14, speed: 0.18),
182                 BackgroundImage(name: "Sun", left: 0.8, top: 0.07, speed: 0.0)
183         ]
184         
185         //添加一个内容类型的数组。
186         var contents = [Content]()
187         
188         //对视差图片数组进行遍历,从而创建九个视差内容,
189         //并放置在数组中。
190         for backgroundImage in backgroundImages
191         {
192             //从指定的结构体中,获得图片的名称,然后初始化一个指定图片名称的图像视图。
193             let imageView = UIImageView(image: UIImage(named: backgroundImage.name))
194             //获得结构体中的视差图片的位置。
195             if let position = backgroundImage.positionAt(0)
196             {
197                 //初始化一个指定视图、位置和中心点属性的视差内容。然后将视差内容添加到数组中。
198                 contents.append(Content(view: imageView, position: position, centered: false))
199             }
200         }
201         
202         //将所有的视差内容添加到背景视图中
203         addToBackground(contents)
204         
205         //添加另一个执行五次的循环语句,给每个页面添加一个视差动画。
206         for row in 1...4
207         {
208             //对数组中的视差内容进行遍历
209             for (column, backgroundImage) in backgroundImages.enumerated()
210             {
211                 //获得视差内容,以及视差内容的当前位置。
212                 if let position = backgroundImage.positionAt(row), let content = contents.at(column)
213                 {
214                     //初始化一个过渡动画对象,并设置动画对象的视差内容、目标位置、动画时长和阻尼值
215                     addAnimation(TransitionAnimation(content: content, destination: position, duration: 2.0, damping: 1.0), forPage: row)
216                 }
217             }
218         }
219         
220         //创建一个指定显示区域的视图对象,作为视差背景的地面视图
221         let groundView = UIView(frame: CGRect(x: 0, y: 0, width: 1024, height: 60))
222         //设置地面视图的背景颜色,
223         groundView.backgroundColor = UIColor(red: 1.0, green: 205.0/255, blue: 65/255.0, alpha: 1.0)
224         //将地面视图转换成一个内容对象,并设置它的位置。
225         let groundContent = Content(view: groundView,
226                                     position: Position(left: 0.0, bottom: 0.063), centered: false)
227         //将地面内容对象也添加到数组中。
228         contents.append(groundContent)
229         
230         //将内容数组添加到背景视图。
231         addToBackground([groundContent])
232     }
233 }
234 
235 //添加一个针对数组类型的扩展。
236 extension Array
237 {
238     //添加一个扩展方法,用来获得在数组中指定位置的元素。
239     func at(_ index: Int?) -> Element?
240     {
241         //创建一个元素变量。
242         var object: Element?
243         //当元素位置在数组长度范围之内时,根据下标获得数组中的元素。
244         if let index = index , index >= 0 && index < endIndex
245         {
246             object = self[index]
247         }
248         
249         //返回获得的元素
250         return object
251     }
252 }

在左侧的项目导航区,打开应用程序的代理文件【AppDelegate.swift

在应用程序加载完成的方法中,创建一个导航控制器。

 1 import UIKit
 2 
 3 @UIApplicationMain
 4 class AppDelegate: UIResponder, UIApplicationDelegate {
 5 
 6     var window: UIWindow?
 7 
 8     func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
 9         // Override point for customization after application launch.
10         
11         //清除导航条在默认状态下的背景图片
12         UINavigationBar.appearance().setBackgroundImage(UIImage(), for: .default)
13         //清除导航条的阴影图片
14         UINavigationBar.appearance().shadowImage = UIImage()
15         
16         //多上文创建的视图控制器进行初始化操作。
17         let vc = ViewController(pages: [])
18         //创建一个导航控制器,并设置导航控制器的根视图控制器
19         let navigationController = UINavigationController(rootViewController: vc)
20         //设置窗口对象的根视图控制器,为导航控制器。
21         window?.rootViewController = navigationController
22          //并将窗口对象作为应用程序的主窗口。
23         window?.makeKeyAndVisible()
24 
25         return true
26     }
27 
28     func applicationWillResignActive(_ application: UIApplication) {
29         // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
30         // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
31     }
32 
33     func applicationDidEnterBackground(_ application: UIApplication) {
34         // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
35         // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
36     }
37 
38     func applicationWillEnterForeground(_ application: UIApplication) {
39         // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
40     }
41 
42     func applicationDidBecomeActive(_ application: UIApplication) {
43         // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
44     }
45 
46     func applicationWillTerminate(_ application: UIApplication) {
47         // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
48     }
49 }

猜你喜欢

转载自www.cnblogs.com/strengthen/p/10359062.html