Let’s try writing the data structure to support the animation as shown below. Basically you need to have multiple views be able to move back and forth. I went with circular linked list since, it maintains a pointer to the next and previous nodes. I wrote the data structure using Generics, this way we are able to use it to support different data types.
![](https://i0.wp.com/redflowerinc.com/wp-content/uploads/2019/12/rolodex.gif?resize=176%2C380&ssl=1)
The data structure is shown below.
//
// CircularLinkedList.swift
// swipeRight
//
// Copyright © 2019 darshan. All rights reserved.
//
import Foundation
// -------------------------------------------------------------------------------------------
// Circular linked list
// -------------------------------------------------------------------------------------------
class Node<T : Equatable> {
var next : Node<T>?
var prev : Node<T>?
var value : T?
init(input : T?) {
self.value = input
self.next = nil
self.prev = nil
}
}
extension Node : Equatable {
static func == (lhs: Node, rhs: Node) -> Bool {
return lhs.value == rhs.value
}
}
class circularlinkedlist<T : Equatable> {
var head : Node<T>?
var current : Node<T>?
func insert(value : T) -> Node<T> {
let newNode = Node(input: value)
if self.head == nil {
newNode.next = newNode
newNode.prev = newNode
self.head = newNode
current = self.head
} else {
// If list is not empty
/* Find last node */
let last = self.head?.prev
// Start is going to be next of new_node
newNode.next = self.head
// Make new node previous of start
self.head?.prev = newNode
// Make last previous of new node
newNode.prev = last
// Make new node next of old last
last?.next = newNode
current = last
}
return current!
}
func isEqual(left : Node<T>?, right : Node<T>?) -> Bool {
if left?.value == right?.value {
return true
}
return false
}
func display() {
var nextNode = self.head
repeat {
print(nextNode!.value!)
nextNode = nextNode?.next
// } while !self.isEqual(left: nextNode, right: self.head)
} while !(nextNode == self.head)
}
func getCurrent() -> Node<T> {
return current!
}
func setCurrent(node: Node<T>) {
current = node
}
func getNext() -> Node<T>? {
current?.next
}
func getPrev() -> Node<T>? {
return current?.prev
}
func deleteNodeWith(value : T) {
// iterate through the nodes
if(self.head?.value == value) {
// delete the head node
var next = self.head?.next
var prev : Node<T>?
while next?.value != self.head?.value {
prev = next
next = next?.next
}
self.head = next?.next
prev?.next = self.head
} else {
// lets iterate through all the nodes
var prev : Node<T>?
var next = self.head
let delete = Node(input: value)
while next?.value != delete.value {
prev = next
next = next?.next
}
prev?.next = next?.next
}
}
func deleteNode(node : Node<T>) {
// iterate through the nodes
if(self.head == node) {
// delete the head node
var next = self.head?.next
var prev : Node<T>?
while next != self.head {
prev = next
next = next?.next
}
self.head = next?.next
prev?.next = self.head
} else {
// lets iterate through all the nodes
var prev : Node<T>?
var next = self.head
while next != node {
prev = next
next = next?.next
}
prev?.next = next?.next
}
}
}
You can test the code as shown below. As you can see, for now I have tested this with UIView, String and Int.
//let clist = circularlinkedlist<String>()
//let mon = clist.insert(value: "monday")
//let tues = clist.insert(value: "tuesday")
//let wed = clist.insert(value: "wednesday")
//let thur = clist.insert(value: "thursday")
//let friday = clist.insert(value: "friday")
//let saturday = clist.insert(value: "saturday")
//let sunday = clist.insert(value: "sunday")
//clist.deleteNode(node: thur)
//clist.deleteNodeWith(value: "monday")
//clist.display()
let clist = circularlinkedlist<Int>()
clist.insert(value: 1)
clist.insert(value: 2)
clist.insert(value: 3)
clist.insert(value: 4)
clist.insert(value: 5)
clist.deleteNodeWith(value: 2)
clist.display()
//let clist = circularlinkedlist<UIView>()
//let v1 = clist.insert(value: UIView())
//let v2 = clist.insert(value: UIView())
//let v3 = clist.insert(value: UIView())
//clist.deleteNode(node: v2)
//clist.display()
//print("Next ",clist.getNext()?.value," Prev ", clist.getPrev()?.value)
//print("Next ",clist.getNext()?.value," Prev ", clist.getPrev()?.value)
//print("Next ",clist.getNext()?.value," Prev ", clist.getPrev()?.value)
This is the code for testing the view controller animation
//
// ViewController.swift
// swipeRight
//
// Created by darshan on 11/27/19.
// Copyright © 2019 darshan. All rights reserved.
//
import UIKit
class ViewController: UIViewController {
let weekdays = ["sunday", "saturday", "friday", "thursday", "wednesday", "tuesday", "monday"]
let views : [UIView] = []
let list = circularlinkedlist<Day>()
override func viewDidLoad() {
super.viewDidLoad()
for day in weekdays {
let view = Day(frame: self.view.frame)
view.setName(day)
_ = list.insert(value: view)
}
let currentView = list.getCurrent().value ?? Day()
view.backgroundColor = .red
self.view.addSubview(currentView)
let rightSwipe = UISwipeGestureRecognizer(target: self, action:#selector(didSwipe(_:)))
rightSwipe.direction = .right
let leftSwipe = UISwipeGestureRecognizer(target: self, action: #selector(didSwipe(_:)))
leftSwipe.direction = .left
self.view.addGestureRecognizer(rightSwipe)
self.view.addGestureRecognizer(leftSwipe)
}
@objc
func didSwipe(_ sender : UISwipeGestureRecognizer) {
if sender.direction == .left {
let node = list.getPrev()
let currentView = self.list.getCurrent().value ?? Day()
print("prev ", node?.prev?.value?.label?.text, " next ",node?.next?.value?.label?.text, " currently this ",node?.value?.label?.text)
list.setCurrent(node: node!)
let view = node!.value
let beforeFrame = view?.frame
view?.frame = CGRect(x: (view?.frame.size.width)!, y: 0, width: (view?.frame.size.width)!, height: (view?.frame.size.height)!)
self.view .addSubview(node!.value!)
UIView.animate(withDuration: 0.5) {
view?.frame = beforeFrame ?? CGRect(x: 0, y: 0, width: 0, height: 0)
currentView .removeFromSuperview()
}
}
if sender.direction == .right {
let currentView = list.getCurrent().value ?? Day()
let node = list.getNext()
print("prev ", node?.prev?.value?.label?.text, " next ",node?.next?.value?.label?.text, " currently this ",node?.value?.label?.text)
list.setCurrent(node: node!)
self.view .addSubview(node!.value!)
let view = node!.value
let beforeFrame = view?.frame
view?.frame = CGRect(x: -(view?.frame.size.width)!, y: 0, width: (view?.frame.size.width)!, height: (view?.frame.size.height)!)
UIView.animate(withDuration: 0.5) {
view?.frame = beforeFrame ?? CGRect(x: 0, y: 0, width: 0, height: 0)
currentView .removeFromSuperview()
}
}
}
}
This is a subclass of the View
//
// View.swift
// swipeRight
//
// Copyright © 2019 darshan. All rights reserved.
//
import Foundation
import UIKit
class Day : UIView {
var label : UILabel?
var name : String = ""
override init(frame: CGRect) {
super.init(frame: frame)
label = UILabel(frame: CGRect(x: 0, y: 0, width: 300, height: 100))
label?.text = "test"
label?.center = self.center
label?.font = UIFont.italicSystemFont(ofSize: 40.0)
self.addSubview(label!)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setName(_ name : String) {
self.label?.text = name
}
}
Leave a Reply