★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
➤微信公众号:山青咏芝(shanqingyongzhi)
➤博客园地址:山青咏芝(https://www.cnblogs.com/strengthen/)
➤GitHub地址:https://github.com/strengthen/LeetCode
➤原文地址:https://www.cnblogs.com/strengthen/p/10359062.html
➤如果链接不是山青咏芝的博客园地址,则可能是爬取作者的文章。
➤原文已修改更新!强烈建议点击原文地址阅读!支持作者!支持原创!
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
景深视差经常被应用在游戏项目中。
本文将演示创建更美观的景深视差滚动效果。
首先确保已经安装了所需的第三方类库。双击查看安装配置文件【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, 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, 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 }