Skip to content

Commit

Permalink
Bugs correction
Browse files Browse the repository at this point in the history
  • Loading branch information
clarknt committed Aug 3, 2019
1 parent 4f77a11 commit 3e7911e
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 14 deletions.
2 changes: 2 additions & 0 deletions 61-Milestone-Projects28-30/Milestone-Projects28-30/Card.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import Foundation
enum CardSide {
case front
case back
case matched
case complete
}

class Card {
Expand Down
72 changes: 66 additions & 6 deletions 61-Milestone-Projects28-30/Milestone-Projects28-30/CardCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ class CardCell: UICollectionViewCell {
var front: UIImageView!
var back: UIImageView!
var container: UIView!


var card: Card?

fileprivate var hideAnimationComplete = true
fileprivate var showAnimationComplete = true
fileprivate var animationComplete: Bool {
Expand Down Expand Up @@ -70,14 +72,55 @@ class CardCell: UICollectionViewCell {
if !__CGSizeEqualToSize(back!.frame.size, frame.size) {
back.frame = CGRect(x: 0, y: 0, width: size.width, height: size.height)
}

// reapply visible face and / or scaling
if let card = card {
set(side: card.visibleSide)
}
}

fileprivate func set(side: CardSide) {
switch side {
case .back:
flipToNotAnimated(side: .back)
case .front:
flipToNotAnimated(side: .front)
case .matched:
flipToNotAnimated(side: .front)
DispatchQueue.main.async { [weak self] in
self?.transform = CGAffineTransform(scaleX: 0.6, y: 0.6)
}
case .complete:
flipToNotAnimated(side: .front)
}
}

fileprivate func flipToNotAnimated(side: CardSide) {
if side == .front {
guard getFacingSide() == .back else { return }
}
if side == .back {
guard getFacingSide() == .front else { return }
}

let initialAngle = side == .front ? 0 : CGFloat.pi
let angle = initialAngle + CGFloat.pi

var transform = CATransform3DIdentity
transform.m34 = -1 / 500
transform = CATransform3DRotate(transform, angle, 0, 1, 0)
container.layer.sublayerTransform = transform
}

func set(frontImage: String, backImage: String) {
front.image = UIImage(named: frontImage)
back.image = UIImage(named: backImage)
func set(card: Card) {
front.image = UIImage(named: card.frontImage)
back.image = UIImage(named: card.backImage)
self.card = card
}

func animateFound() {
// make sure card is facing front
flipToNotAnimated(side: .front)
UIView.animate(withDuration: 2, delay: 0, usingSpringWithDamping: 0.3, initialSpringVelocity: 5, options: [], animations: { [weak self] in
self?.transform = CGAffineTransform(scaleX: 0.6, y: 0.6)
})
Expand All @@ -99,19 +142,35 @@ class CardCell: UICollectionViewCell {
}

fileprivate func triggerFlipAnimation(side: CardSide) {
if side == .front {
guard getFacingSide() == .back else { return }
}
if side == .back {
guard getFacingSide() == .front else { return }
}

hideAnimationComplete = false
showAnimationComplete = false

let initialAngle = side == .front ? 0 : CGFloat.pi
animateFlip(duration: 0.5, initialAngle: initialAngle) { [weak self] in

animateFlip(duration: 0.3, initialAngle: initialAngle) { [weak self] in
self?.hideAnimationComplete = true
self?.showAnimationComplete = true
}
}

fileprivate func getFacingSide() -> CardSide {
// m11, m33 in the transformation matrix should be 1, 1 when back is facing, -1, -1 when front is facing
if container.layer.sublayerTransform.m11 > 0 && container.layer.sublayerTransform.m33 > 0 {
return .back
}
return .front
}

fileprivate func animateFlip(duration: Double, initialAngle: CGFloat = 0, completionHandler: (() -> ())?) {
let fps: Double = 30

// UIView animation is not working with sublayerTransform: animate manually
DispatchQueue.global().async { [weak self] in
let loops = Int(fps * duration)
Expand All @@ -120,6 +179,7 @@ class CardCell: UICollectionViewCell {
usleep(useconds_t(1000000 / fps))

var angle = initialAngle + CGFloat.pi * CGFloat(i) / CGFloat(loops)

// make sure exact .pi is reached
if i == loops {
angle = initialAngle + CGFloat.pi
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ class ViewController: UICollectionViewController, UICollectionViewDelegateFlowLa

override func viewDidLoad() {
super.viewDidLoad()

guard (cardsLongNumber * cardsShortNumber) % 2 == 0 else {
fatalError("Odd number of cards")
}

// some ipad don't automatically refresh the collection view when rotated
NotificationCenter.default.addObserver(forName: UIDevice.orientationDidChangeNotification, object: nil, queue: .main, using: didRotate)

buildCards()
}

Expand Down Expand Up @@ -55,7 +63,7 @@ class ViewController: UICollectionViewController, UICollectionViewDelegateFlowLa
frontImages += frontImages
// shuffle images
frontImages.shuffle()

for i in 0..<cardsNumber {
cards.append(Card(frontImage: frontImages[i], backImage: backImage!))
}
Expand All @@ -70,8 +78,7 @@ class ViewController: UICollectionViewController, UICollectionViewDelegateFlowLa

guard let cell = dequeuedCell as? CardCell else { return dequeuedCell }

let card = cards[indexPath.row]
cell.set(frontImage: card.frontImage, backImage: card.backImage)
cell.set(card: cards[indexPath.row])

return dequeuedCell
}
Expand All @@ -97,7 +104,9 @@ class ViewController: UICollectionViewController, UICollectionViewDelegateFlowLa
}

func matchedCards() {
for (position, _) in flippedCards {
for (position, card) in flippedCards {
card.visibleSide = .matched

let indexPath = IndexPath(item: position, section: 0);
if let cell = collectionView.cellForItem(at: indexPath) as? CardCell {
// wait for flip animatiom to complete
Expand All @@ -113,12 +122,16 @@ class ViewController: UICollectionViewController, UICollectionViewDelegateFlowLa

func checkCompletion() {
for card in cards {
if card.visibleSide == .back {
if card.visibleSide != .matched && card.visibleSide != .complete {
return
}
}

// all cards complete
for card in cards {
card.visibleSide = .complete
}

animateCompletion()
}

Expand Down Expand Up @@ -160,14 +173,18 @@ class ViewController: UICollectionViewController, UICollectionViewDelegateFlowLa
}
}

func didRotate(_: Notification) -> Void {
collectionView.collectionViewLayout.invalidateLayout()
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return getCardSize(collectionView: collectionView)
}

func getCardSize(collectionView: UICollectionView) -> CGSize {
let width = collectionView.frame.size.width
let height = collectionView.frame.size.height

let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout
let minInterimSpacing = layout?.minimumInteritemSpacing ?? 0
let minLineSpacing = layout?.minimumLineSpacing ?? 0
Expand All @@ -194,8 +211,8 @@ class ViewController: UICollectionViewController, UICollectionViewDelegateFlowLa
heightCardNumber = CGFloat(cardsShortNumber)
}

let availableWidth = width - leftRightMargin - leftRightInsets - minInterimSpacing * widthCardNumber
let availableHeight = height - topBottomMargin - topBottomInsets - minLineSpacing * heightCardNumber
let availableWidth = width - leftRightMargin - leftRightInsets - minInterimSpacing * (widthCardNumber - 1)
let availableHeight = height - topBottomMargin - topBottomInsets - minLineSpacing * (heightCardNumber - 1)

guard availableWidth > widthCardNumber && availableHeight > heightCardNumber else {
fatalError("Too many cards to display")
Expand Down

0 comments on commit 3e7911e

Please sign in to comment.