版本记录
版本号 | 时间 |
---|---|
V1.0 | 2018.10.31 星期三 |
前言
iOS中有关视图控件用户能看到的都在UIKit框架里面,用户交互也是通过UIKit进行的。感兴趣的参考上面几篇文章。
1. UIKit框架(一) —— UIKit动力学和移动效果(一)
2. UIKit框架(二) —— UIKit动力学和移动效果(二)
3. UIKit框架(三) —— UICollectionViewCell的扩张效果的实现(一)
源码
1. Swift
首先看一下工程组织结构
看一下sb中的内容
1. InspirationsViewController.swift
import UIKit
class InspirationsViewController: UICollectionViewController {
let inspirations = Inspiration.allInspirations()
override var preferredStatusBarStyle: UIStatusBarStyle {
return UIStatusBarStyle.lightContent
}
override func viewDidLoad() {
super.viewDidLoad()
if let patternImage = UIImage(named: "Pattern") {
view.backgroundColor = UIColor(patternImage: patternImage)
}
collectionView?.backgroundColor = .clear
collectionView?.decelerationRate = .fast
}
}
extension InspirationsViewController {
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return inspirations.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(
withReuseIdentifier: InspirationCell.reuseIdentifier, for: indexPath)
as? InspirationCell else {
return UICollectionViewCell()
}
cell.inspiration = inspirations[indexPath.item]
return cell
}
}
2. UIColor+Palette.swift
import UIKit
extension UIColor {
class func colorFromRGB(_ r: Int, g: Int, b: Int) -> UIColor {
return UIColor(red: CGFloat(Float(r) / 255), green: CGFloat(Float(g) / 255), blue: CGFloat(Float(b) / 255), alpha: 1)
}
class func palette() -> [UIColor] {
let palette = [
UIColor.colorFromRGB(85, g: 0, b: 255),
UIColor.colorFromRGB(170, g: 0, b: 170),
UIColor.colorFromRGB(85, g: 170, b: 85),
UIColor.colorFromRGB(0, g: 85, b: 0),
UIColor.colorFromRGB(255, g: 170, b: 0),
UIColor.colorFromRGB(255, g: 255, b: 0),
UIColor.colorFromRGB(255, g: 85, b: 0),
UIColor.colorFromRGB(0, g: 85, b: 85),
UIColor.colorFromRGB(0, g: 85, b: 255),
UIColor.colorFromRGB(170, g: 170, b: 255),
UIColor.colorFromRGB(85, g: 0, b: 0),
UIColor.colorFromRGB(170, g: 85, b: 85),
UIColor.colorFromRGB(170, g: 255, b: 0),
UIColor.colorFromRGB(85, g: 170, b: 255),
UIColor.colorFromRGB(0, g: 170, b: 170)
]
return palette
}
}
3. UIImage+Decompression.swift
import UIKit
extension UIImage {
var decompressedImage: UIImage {
UIGraphicsBeginImageContextWithOptions(size, true, 0)
draw(at: CGPoint.zero)
guard let decompressedImage = UIGraphicsGetImageFromCurrentImageContext() else {
return UIImage()
}
UIGraphicsEndImageContext()
return decompressedImage
}
}
4. UltravisualLayout.swift
import UIKit
// The heights are declared as constants outside of the class so they can be easily referenced elsewhere
struct UltravisualLayoutConstants {
struct Cell {
// The height of the non-featured cell
static let standardHeight: CGFloat = 100
// The height of the first visible cell
static let featuredHeight: CGFloat = 280
}
}
// MARK: Properties and Variables
class UltravisualLayout: UICollectionViewLayout {
// The amount the user needs to scroll before the featured cell changes
let dragOffset: CGFloat = 180.0
var cache: [UICollectionViewLayoutAttributes] = []
// Returns the item index of the currently featured cell
var featuredItemIndex: Int {
// Use max to make sure the featureItemIndex is never < 0
return max(0, Int(collectionView!.contentOffset.y / dragOffset))
}
// Returns a value between 0 and 1 that represents how close the next cell is to becoming the featured cell
var nextItemPercentageOffset: CGFloat {
return (collectionView!.contentOffset.y / dragOffset) - CGFloat(featuredItemIndex)
}
// Returns the width of the collection view
var width: CGFloat {
return collectionView!.bounds.width
}
// Returns the height of the collection view
var height: CGFloat {
return collectionView!.bounds.height
}
// Returns the number of items in the collection view
var numberOfItems: Int {
return collectionView!.numberOfItems(inSection: 0)
}
}
// MARK: UICollectionViewLayout
extension UltravisualLayout {
// Return the size of all the content in the collection view
override var collectionViewContentSize : CGSize {
let contentHeight = (CGFloat(numberOfItems) * dragOffset) + (height - dragOffset)
return CGSize(width: width, height: contentHeight)
}
override func prepare() {
cache.removeAll(keepingCapacity: false)
let standardHeight = UltravisualLayoutConstants.Cell.standardHeight
let featuredHeight = UltravisualLayoutConstants.Cell.featuredHeight
var frame = CGRect.zero
var y: CGFloat = 0
for item in 0..<numberOfItems {
let indexPath = IndexPath(item: item, section: 0)
let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
// Important because each cell has to slide over the top of the previous one
attributes.zIndex = item
// Initially set the height of the cell to the standard height
var height = standardHeight
if indexPath.item == featuredItemIndex {
// The featured cell
let yOffset = standardHeight * nextItemPercentageOffset
y = collectionView!.contentOffset.y - yOffset
height = featuredHeight
} else if indexPath.item == (featuredItemIndex + 1) && indexPath.item != numberOfItems {
// The cell directly below the featured cell, which grows as the user scrolls
let maxY = y + standardHeight
height = standardHeight + max((featuredHeight - standardHeight) * nextItemPercentageOffset, 0)
y = maxY - height
}
frame = CGRect(x: 0, y: y, width: width, height: height)
attributes.frame = frame
cache.append(attributes)
y = frame.maxY
}
}
// Return all attributes in the cache whose frame intersects with the rect passed to the method
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
var layoutAttributes: [UICollectionViewLayoutAttributes] = []
for attributes in cache {
if attributes.frame.intersects(rect) {
layoutAttributes.append(attributes)
}
}
return layoutAttributes
}
// Return the content offset of the nearest cell which achieves the nice snapping effect, similar to a paged UIScrollView
override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
let itemIndex = round(proposedContentOffset.y / dragOffset)
let yOffset = itemIndex * dragOffset
return CGPoint(x: 0, y: yOffset)
}
// Return true so that the layout is continuously invalidated as the user scrolls
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
return true
}
}
5. Inspiration.swift
import UIKit
class Inspiration: Session {
class func allInspirations() -> [Inspiration] {
var inspirations: [Inspiration] = []
guard let URL = Bundle.main.url(forResource: "Inspirations", withExtension: "plist"),
let tutorialsFromPlist = NSArray(contentsOf: URL) else {
return inspirations
}
for dictionary in tutorialsFromPlist {
let inspiration = Inspiration(dictionary: dictionary as! NSDictionary)
inspirations.append(inspiration)
}
return inspirations
}
}
6. Session.swift
import UIKit
class Session {
var title: String
var speaker: String
var room: String
var time: String
var backgroundImage: UIImage
var roomAndTime: String {
get {
return "\(time) • \(room)"
}
}
init(title: String, speaker: String, room: String, time: String, backgroundImage: UIImage) {
self.title = title
self.speaker = speaker
self.room = room
self.time = time
self.backgroundImage = backgroundImage
}
convenience init(dictionary: NSDictionary) {
let title = dictionary["Title"] as? String
let speaker = dictionary["Speaker"] as? String
let room = dictionary["Room"] as? String
let time = dictionary["Time"] as? String
let backgroundName = dictionary["Background"] as? String
let backgroundImage = UIImage(named: backgroundName!)
self.init(title: title!, speaker: speaker!, room: room!, time: time!, backgroundImage: backgroundImage!.decompressedImage)
}
}
7. InspirationCell.swift
import UIKit
class InspirationCell: UICollectionViewCell {
static let reuseIdentifier = String(describing: InspirationCell.self)
@IBOutlet private weak var imageView: UIImageView!
@IBOutlet private weak var imageCoverView: UIView!
@IBOutlet private weak var titleLabel: UILabel!
@IBOutlet private weak var timeAndRoomLabel: UILabel!
@IBOutlet private weak var speakerLabel: UILabel!
var inspiration: Inspiration? {
didSet {
if let inspiration = inspiration {
imageView.image = inspiration.backgroundImage
titleLabel.text = inspiration.title
timeAndRoomLabel.text = inspiration.roomAndTime
speakerLabel.text = inspiration.speaker
}
}
}
override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) {
super.apply(layoutAttributes)
let featuredHeight = UltravisualLayoutConstants.Cell.featuredHeight
let standardHeight = UltravisualLayoutConstants.Cell.standardHeight
let delta = 1 - ((featuredHeight - frame.height) / (featuredHeight - standardHeight))
let minAlpha: CGFloat = 0.3
let maxAlpha: CGFloat = 0.75
imageCoverView.alpha = maxAlpha - (delta * (maxAlpha - minAlpha))
let scale = max(delta, 0.5)
titleLabel.transform = CGAffineTransform(scaleX: scale, y: scale)
timeAndRoomLabel.alpha = delta
speakerLabel.alpha = delta
}
}
后记
本篇主要讲述了UICollectionViewCell的扩张效果的实现,感兴趣的给个赞或者关注~~~