版本記錄
版本號 | 時間 |
---|---|
V1.0 | 2019.07.26 星期五 |
前言
iOS中有關(guān)視圖控件用戶能看到的都在UIKit框架里面一死,用戶交互也是通過UIKit進(jìn)行的恒序。感興趣的參考上面幾篇文章绪妹。
1. UIKit框架(一) —— UIKit動力學(xué)和移動效果(一)
2. UIKit框架(二) —— UIKit動力學(xué)和移動效果(二)
3. UIKit框架(三) —— UICollectionViewCell的擴張效果的實現(xiàn)(一)
4. UIKit框架(四) —— UICollectionViewCell的擴張效果的實現(xiàn)(二)
5. UIKit框架(五) —— 自定義控件:可重復(fù)使用的滑塊(一)
6. UIKit框架(六) —— 自定義控件:可重復(fù)使用的滑塊(二)
7. UIKit框架(七) —— 動態(tài)尺寸UITableViewCell的實現(xiàn)(一)
8. UIKit框架(八) —— 動態(tài)尺寸UITableViewCell的實現(xiàn)(二)
9. UIKit框架(九) —— UICollectionView的數(shù)據(jù)異步預(yù)加載(一)
10. UIKit框架(十) —— UICollectionView的數(shù)據(jù)異步預(yù)加載(二)
11. UIKit框架(十一) —— UICollectionView的重用、選擇和重排序(一)
12. UIKit框架(十二) —— UICollectionView的重用祷杈、選擇和重排序(二)
13. UIKit框架(十三) —— 如何創(chuàng)建自己的側(cè)滑式面板導(dǎo)航(一)
14. UIKit框架(十四) —— 如何創(chuàng)建自己的側(cè)滑式面板導(dǎo)航(二)
15. UIKit框架(十五) —— 基于自定義UICollectionViewLayout布局的簡單示例(一)
16. UIKit框架(十六) —— 基于自定義UICollectionViewLayout布局的簡單示例(二)
17. UIKit框架(十七) —— 基于自定義UICollectionViewLayout布局的簡單示例(三)
18. UIKit框架(十八) —— 基于CALayer屬性的一種3D邊欄動畫的實現(xiàn)(一)
19. UIKit框架(十九) —— 基于CALayer屬性的一種3D邊欄動畫的實現(xiàn)(二)
20. UIKit框架(二十) —— 基于UILabel跑馬燈類似效果的實現(xiàn)(一)
21. UIKit框架(二十一) —— UIStackView的使用(一)
22. UIKit框架(二十二) —— 基于UIPresentationController的自定義viewController的轉(zhuǎn)場和展示(一)
源碼
1. Swift
首先看下工程組織結(jié)構(gòu)
接著看一下sb中的內(nèi)容
最后就是源碼了
1. MainViewController.swift
import UIKit
final class MainViewController: UIViewController {
// MARK: - IBOutlets
@IBOutlet weak var yearLabel: UILabel!
@IBOutlet weak var hostLabel: UILabel!
@IBOutlet weak var medalCountButton: UIButton!
@IBOutlet weak var logoImageView: UIImageView!
// MARK: - Properties
lazy var slideInTransitioningDelegate = SlideInPresentationManager()
private let dataStore = GamesDataStore()
private var presentedGames: Games? {
didSet {
configurePresentedGames()
}
}
// MARK: - View Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
presentedGames = nil
}
// MARK: - Navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let controller = segue.destination as? GamesTableViewController {
if segue.identifier == "SummerSegue" {
controller.gamesArray = dataStore.allGames.summer
slideInTransitioningDelegate.direction = .left
} else if segue.identifier == "WinterSegue" {
controller.gamesArray = dataStore.allGames.winter
slideInTransitioningDelegate.direction = .right
}
controller.delegate = self
slideInTransitioningDelegate.disableCompactHeight = false
controller.transitioningDelegate = slideInTransitioningDelegate
controller.modalPresentationStyle = .custom
} else if let controller = segue.destination as? MedalCountViewController {
controller.medalWinners = presentedGames?.medalWinners
slideInTransitioningDelegate.direction = .bottom
slideInTransitioningDelegate.disableCompactHeight = true
controller.transitioningDelegate = slideInTransitioningDelegate
controller.modalPresentationStyle = .custom
}
}
}
// MARK: - Private
private extension MainViewController {
func configurePresentedGames() {
guard let presentedGames = presentedGames else {
logoImageView.image = UIImage(named: "medals")
hostLabel.text = nil
yearLabel.text = nil
medalCountButton.isHidden = true
return
}
logoImageView.image = UIImage(named: presentedGames.flagImageName)
hostLabel.text = presentedGames.host
yearLabel.text = presentedGames.seasonYear
medalCountButton.isHidden = false
}
}
// MARK: - GamesTableViewControllerDelegate
extension MainViewController: GamesTableViewControllerDelegate {
func gamesTableViewController(controller: GamesTableViewController, didSelectGames selectedGames: Games) {
presentedGames = selectedGames
dismiss(animated: true)
}
}
2. MedalCountViewController.swift
import UIKit
final class MedalCountViewController: UIViewController {
// MARK: - IBOutlets
@IBOutlet weak var medalCountStackView: UIStackView!
@IBOutlet var countryFlags: [UIImageView]!
@IBOutlet var countryNames: [UILabel]!
@IBOutlet var countryGolds: [UILabel]!
@IBOutlet var countrySilvers: [UILabel]!
@IBOutlet var countryBronzes: [UILabel]!
// MARK: - Properties
var medalWinners: [MedalWinner]!
// MARK: - View Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
for (index, winner) in medalWinners.enumerated() {
countryFlags[index].image = winner.flagImage
countryNames[index].text = winner.country
countryGolds[index].text = winner.goldString
countrySilvers[index].text = winner.silverString
countryBronzes[index].text = winner.bronzeString
}
setupGestureRecognizers()
}
}
// MARK: - Private
private extension MedalCountViewController {
func setupGestureRecognizers() {
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap(gestureRecognizer:)))
view.addGestureRecognizer(tapRecognizer)
}
}
// MARK: - GestureRecognizerSelectors
private extension MedalCountViewController {
@objc func handleTap(gestureRecognizer: UITapGestureRecognizer) {
dismiss(animated: true)
}
}
3. GamesTableViewController.swift
import UIKit
protocol GamesTableViewControllerDelegate: AnyObject {
func gamesTableViewController(controller: GamesTableViewController, didSelectGames selectedGames: Games)
}
final class GamesTableViewController: UITableViewController {
// MARK: - Properties
weak var delegate: GamesTableViewControllerDelegate?
var gamesArray: [Games]!
}
// MARK: - UITableViewDataSource
extension GamesTableViewController {
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return gamesArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "GamesCell", for: indexPath) as! GamesTableViewCell
let games = gamesArray[indexPath.row]
cell.hostLabel.text = games.host
cell.yearLabel.text = games.year
cell.logoImageView.image = UIImage(named: games.flagImageName)
return cell
}
}
// MARK: - UITableViewDelegate
extension GamesTableViewController {
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let selectedGames = gamesArray[indexPath.row]
delegate?.gamesTableViewController(controller: self, didSelectGames: selectedGames)
}
}
4. AllGames.swift
import Foundation
struct AllGames: Codable {
// MARK: - Properties
let summer: [Games]
let winter: [Games]
}
5. Games.swift
import Foundation
struct Games: Codable {
// MARK: - Properties
let year: String
let host: String
let country: String
let isSummer: Bool
let medalWinners: [MedalWinner]
var seasonYear: String {
return "\(season.capitalized) \(year)"
}
var flagImageName: String {
let name = country.lowercased().replacingOccurrences(of: " ", with: "_")
return "\(name)_large"
}
private var season: String {
return isSummer ? "summer" : "winter"
}
}
6. MedalWinner.swift
import UIKit
struct MedalWinner: Codable {
// MARK: - Properties
let country: String
let gold: Int
let silver: Int
let bronze: Int
}
// MARK: - Internal
extension MedalWinner {
var flagImage: UIImage? {
let imageName = country.lowercased().replacingOccurrences(of: " ", with: "_")
return UIImage(named: imageName)
}
var goldString: String {
return "\(gold)"
}
var silverString: String {
return "\(silver)"
}
var bronzeString: String {
return "\(bronze)"
}
}
7. GamesDataStore.swift
import Foundation
final class GamesDataStore {
// MARK: - Properties
let allGames: AllGames
// MARK: - Initializers
init() {
let path = Bundle.main.path(forResource: "GamesData", ofType: "plist")!
let data = FileManager.default.contents(atPath: path)!
let decoder = PropertyListDecoder()
allGames = try! decoder.decode(AllGames.self, from: data)
}
}
8. SlideInPresentationAnimator.swift
import UIKit
final class SlideInPresentationAnimator: NSObject {
// MARK: - Properties
let direction: PresentationDirection
let isPresentation: Bool
// MARK: - Initializers
init(direction: PresentationDirection, isPresentation: Bool) {
self.direction = direction
self.isPresentation = isPresentation
super.init()
}
}
// MARK: - UIViewControllerAnimatedTransitioning
extension SlideInPresentationAnimator: UIViewControllerAnimatedTransitioning {
func transitionDuration(
using transitionContext: UIViewControllerContextTransitioning?
) -> TimeInterval {
return 0.3
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
let key: UITransitionContextViewControllerKey = isPresentation ? .to : .from
guard let controller = transitionContext.viewController(forKey: key)
else { return }
if isPresentation {
transitionContext.containerView.addSubview(controller.view)
}
let presentedFrame = transitionContext.finalFrame(for: controller)
var dismissedFrame = presentedFrame
switch direction {
case .left:
dismissedFrame.origin.x = -presentedFrame.width
case .right:
dismissedFrame.origin.x = transitionContext.containerView.frame.size.width
case .top:
dismissedFrame.origin.y = -presentedFrame.height
case .bottom:
dismissedFrame.origin.y = transitionContext.containerView.frame.size.height
}
let initialFrame = isPresentation ? dismissedFrame : presentedFrame
let finalFrame = isPresentation ? presentedFrame : dismissedFrame
let animationDuration = transitionDuration(using: transitionContext)
controller.view.frame = initialFrame
UIView.animate(
withDuration: animationDuration,
animations: {
controller.view.frame = finalFrame
}, completion: { finished in
if !self.isPresentation {
controller.view.removeFromSuperview()
}
transitionContext.completeTransition(finished)
})
}
}
9. SlideInPresentationController.swift
import UIKit
final class SlideInPresentationController: UIPresentationController {
// MARK: - Properties
private var dimmingView: UIView!
private let direction: PresentationDirection
override var frameOfPresentedViewInContainerView: CGRect {
var frame: CGRect = .zero
frame.size = size(forChildContentContainer: presentedViewController,
withParentContainerSize: containerView!.bounds.size)
switch direction {
case .right:
frame.origin.x = containerView!.frame.width*(1.0/3.0)
case .bottom:
frame.origin.y = containerView!.frame.height*(1.0/3.0)
default:
frame.origin = .zero
}
return frame
}
// MARK: - Initializers
init(presentedViewController: UIViewController,
presenting presentingViewController: UIViewController?,
direction: PresentationDirection) {
self.direction = direction
super.init(presentedViewController: presentedViewController, presenting: presentingViewController)
setupDimmingView()
}
override func presentationTransitionWillBegin() {
guard let dimmingView = dimmingView else {
return
}
containerView?.insertSubview(dimmingView, at: 0)
NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "V:|[dimmingView]|",
options: [],
metrics: nil,
views: ["dimmingView": dimmingView]))
NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "H:|[dimmingView]|",
options: [],
metrics: nil,
views: ["dimmingView": dimmingView]))
guard let coordinator = presentedViewController.transitionCoordinator else {
dimmingView.alpha = 1.0
return
}
coordinator.animate(alongsideTransition: { _ in
self.dimmingView.alpha = 1.0
})
}
override func dismissalTransitionWillBegin() {
guard let coordinator = presentedViewController.transitionCoordinator else {
dimmingView.alpha = 0.0
return
}
coordinator.animate(alongsideTransition: { _ in
self.dimmingView.alpha = 0.0
})
}
override func containerViewWillLayoutSubviews() {
presentedView?.frame = frameOfPresentedViewInContainerView
}
override func size(forChildContentContainer container: UIContentContainer,
withParentContainerSize parentSize: CGSize) -> CGSize {
switch direction {
case .left, .right:
return CGSize(width: parentSize.width*(2.0/3.0), height: parentSize.height)
case .bottom, .top:
return CGSize(width: parentSize.width, height: parentSize.height*(2.0/3.0))
}
}
}
// MARK: - Private
private extension SlideInPresentationController {
func setupDimmingView() {
dimmingView = UIView()
dimmingView.translatesAutoresizingMaskIntoConstraints = false
dimmingView.backgroundColor = UIColor(white: 0.0, alpha: 0.5)
dimmingView.alpha = 0.0
let recognizer = UITapGestureRecognizer(target: self,
action: #selector(handleTap(recognizer:)))
dimmingView.addGestureRecognizer(recognizer)
}
@objc func handleTap(recognizer: UITapGestureRecognizer) {
presentingViewController.dismiss(animated: true)
}
}
10. SlideInPresentationManager.swift
import UIKit
enum PresentationDirection {
case left
case top
case right
case bottom
}
final class SlideInPresentationManager: NSObject {
// MARK: - Properties
var direction: PresentationDirection = .left
var disableCompactHeight = false
}
// MARK: - UIViewControllerTransitioningDelegate
extension SlideInPresentationManager: UIViewControllerTransitioningDelegate {
func presentationController(
forPresented presented: UIViewController,
presenting: UIViewController?,
source: UIViewController
) -> UIPresentationController? {
let presentationController = SlideInPresentationController(
presentedViewController: presented,
presenting: presenting,
direction: direction
)
presentationController.delegate = self
return presentationController
}
func animationController(
forPresented presented: UIViewController,
presenting: UIViewController,
source: UIViewController
) -> UIViewControllerAnimatedTransitioning? {
return SlideInPresentationAnimator(direction: direction, isPresentation: true)
}
func animationController(
forDismissed dismissed: UIViewController
) -> UIViewControllerAnimatedTransitioning? {
return SlideInPresentationAnimator(direction: direction, isPresentation: false)
}
}
// MARK: - UIAdaptivePresentationControllerDelegate
extension SlideInPresentationManager: UIAdaptivePresentationControllerDelegate {
func adaptivePresentationStyle(
for controller: UIPresentationController,
traitCollection: UITraitCollection
) -> UIModalPresentationStyle {
if traitCollection.verticalSizeClass == .compact && disableCompactHeight {
return .overFullScreen
} else {
return .none
}
}
func presentationController(
_ controller: UIPresentationController,
viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle
) -> UIViewController? {
guard case(.overFullScreen) = style else { return nil }
return UIStoryboard(name: "Main", bundle: nil)
.instantiateViewController(withIdentifier: "RotateViewController")
}
}
11. OlympicGamesTableViewCell.swift
import UIKit
final class GamesTableViewCell: UITableViewCell {
// MARK: - IBOutlets
@IBOutlet weak var logoImageView: UIImageView!
@IBOutlet weak var hostLabel: UILabel!
@IBOutlet weak var yearLabel: UILabel!
}
后記
本篇主要講述了基于UIPresentationController的自定義viewController的轉(zhuǎn)場和展示镣陕,感興趣的給個贊或者關(guān)注~~~