Xin chào các bạn ! Hôm nay mình xin giới thiệu với các bạn một số những chuyển động hoạt hình (Animations) cơ bản trong Swift.
https://github.com/soapyigu/Swift-30-Projects/tree/master/Project%2011%20-%20Animations
B1: Tạo NavigationController, ViewController
Tạo ViewController
Để tạo Navigation, chọn màn ViewController, vào Editor - Embed in - Navigation Controller
Ta được như hình
Ở ViewController thứ 2 đổi tên thành Animations, tạo TableView cho màn này.
Màn thứ 3 đặt tên là Detail View Controller, thêm 1 Button tên là Animate
Để từ màn 2 show ra màn 3, ta chọn màn 2 (Animations) kéo vào màn 3 (Detail View Controller), chọn Show
Và đừng quên layout cho các thành phần trong các View chúng ta vừa kéo thả nhé !
Cuối cùng ta dc như hình dưới đây.
B2: Tiếp theo chúng ta cùng nhau vào phần code nào !
- Để ánh xạ TableView ta kéo chuột phải từ tableview vào phần code bên phải, chọn new referencing outlet
class ViewController: UIViewController {
// MARK: - IBOutlets
@IBOutlet weak var masterTableView: UITableView!
- Khai báo các biến. Ở đấy ta có 8 ví dụ, nên khai 8 biến tương ứng
// MARK: - Variables
fileprivate let items = ["2-Color", "Simple 2D Rotation", "Multicolor", "Multi Point Position", "BezierCurve Position",
"Color and Frame Change", "View Fade In", "Pop"]
- Tạo hàm animateTable() để tạo animation cho TableView.
func animateTable() {
masterTableView.reloadData()
let cells = masterTableView.visibleCells
let tableHeight = masterTableView.bounds.size.height
// move all cells to the bottom of the screen
for cell in cells {
cell.transform = CGAffineTransform(translationX: 0, y: tableHeight)
}
// move all cells from bottom to the right place
var index = 0
for cell in cells {
UIView.animate(withDuration: duration, delay: 0.05 * Double(index), usingSpringWithDamping: 0.8, initialSpringVelocity: 0, options: [], animations: {
cell.transform = CGAffineTransform(translationX: 0, y: 0)
}, completion: nil)
index += 1
}
}
- Tạo Segue để chuyển đổi giữa 2 màn ViewController chúng ta tạo lúc đầu là Animations và DetailViewController.
// MARK: - Segue
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == segueDetailIdentifier {
let detailView = segue.destination as! DetailViewController
let indexPath = masterTableView.indexPathForSelectedRow
if let indexPath = indexPath {
detailView.barTitle = self.items[(indexPath as NSIndexPath).row]
}
}
}
}
- Thiết lập UITableViewDelegate và UITableViewDataSource.
// MARK: - UITableViewDelegate
extension ViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return CGFloat(headerHeight)
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return "Basic Animations"
}
}
// MARK: - UITableViewDataSource
extension ViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier = "cell"
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath)
cell.textLabel?.text = self.items[(indexPath as NSIndexPath).row]
return cell
}
}
- Thêm 3 biến ngoài class ViewController
import UIKit
let headerHeight = 50.0
let segueDetailIdentifier = "toAnimateDetail"
let duration = 1.5
class ViewController: UIViewController {
- Đừng qên nhập hàm animateTable() vào ViewWillAppear
override func viewWillAppear(_ animated: Bool) {
animateTable()
}
- Tạo thêm 1 Swift file đặt tên là DetailViewController.
- Cài đặt NavigationBar.
import UIKit
class DetailViewController: UIViewController {
// MARK: - Variables
var barTitle = ""
var animateView: UIView!
fileprivate let duration = 2.0
fileprivate let delay = 0.2
fileprivate let scale = 1.2
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
setupRect()
setupNavigationBar()
}
fileprivate func setupNavigationBar() {
navigationController?.navigationBar.topItem?.title = barTitle
}
fileprivate func setupRect() {
if barTitle == "BezierCurve Position" {
animateView = drawCircleView()
} else if barTitle == "View Fade In" {
animateView = UIImageView(image: UIImage(named: "whatsapp"))
animateView.frame = generalFrame
animateView.center = generalCenter
} else {
animateView = drawRectView(UIColor.red, frame: generalFrame, center: generalCenter)
}
view.addSubview(animateView)
}
- Ở màn Detail View Controller ta lại kéo thả Button Animate, chọn Touch Up Inside. Sau đó tiến hành code để được những Animations ưng ý.
// MARK: - IBAction
@IBAction func didTapAnimate(_ sender: AnyObject) {
switch barTitle {
case "2-Color":
changeColor(UIColor.green) // Đổi màu
case "Simple 2D Rotation":
rotateView(Double.pi) // Xoay 2 chiều
case "Multicolor":
multiColor(UIColor.green, UIColor.blue) // Nhiều màu
case "Multi Point Position":
multiPosition(CGPoint(x: animateView.frame.origin.x, y: 100), CGPoint(x: animateView.frame.origin.x, y: 350)) // Di chuyển vị trí
case "BezierCurve Position":
var controlPoint1 = self.animateView.center
controlPoint1.y -= 125.0
var controlPoint2 = controlPoint1
controlPoint2.x += 40.0
controlPoint2.y -= 125.0;
var endPoint = self.animateView.center;
endPoint.x += 75.0
curvePath(endPoint, controlPoint1: controlPoint1, controlPoint2: controlPoint2) //Làm quả bóng nảy
case "Color and Frame Change":
let currentFrame = self.animateView.frame
let firstFrame = currentFrame.insetBy(dx: -30, dy: -50)
let secondFrame = firstFrame.insetBy(dx: 10, dy: 15)
let thirdFrame = secondFrame.insetBy(dx: -15, dy: -20)
colorFrameChange(firstFrame, secondFrame, thirdFrame, UIColor.orange, UIColor.yellow, UIColor.green) // Đổi màu và cả kích thước
case "View Fade In":
viewFadeIn() // Đổi hình
case "Pop":
Pop()// nảy
default:
let alert = makeAlert("Alert", message: "The animation not implemented yet", actionTitle: "OK")
self.present(alert, animated: true, completion: nil)
}
}
// MARK: - Private Methods for Animations
fileprivate func changeColor(_ color: UIColor) {
UIView.animate(withDuration: self.duration, animations: {
self.animateView.backgroundColor = color
}, completion: nil)
}
fileprivate func multiColor(_ firstColor: UIColor, _ secondColor: UIColor) {
UIView.animate(withDuration: duration, animations: {
self.animateView.backgroundColor = firstColor
}, completion: { finished in
self.changeColor(secondColor)
})
}
fileprivate func multiPosition(_ firstPos: CGPoint, _ secondPos: CGPoint) {
func simplePosition(_ pos: CGPoint) {
UIView.animate(withDuration: self.duration, animations: {
self.animateView.frame.origin = pos
}, completion: nil)
}
UIView.animate(withDuration: self.duration, animations: {
self.animateView.frame.origin = firstPos
}, completion: { finished in
simplePosition(secondPos)
})
}
fileprivate func rotateView(_ angel: Double) {
UIView.animate(withDuration: duration, delay: delay, options: [.repeat], animations: {
self.animateView.transform = CGAffineTransform(rotationAngle: CGFloat(angel))
}, completion: nil)
}
fileprivate func colorFrameChange(_ firstFrame: CGRect, _ secondFrame: CGRect, _ thirdFrame: CGRect,
_ firstColor: UIColor, _ secondColor: UIColor, _ thirdColor: UIColor) {
UIView.animate(withDuration: self.duration, animations: {
self.animateView.backgroundColor = firstColor
self.animateView.frame = firstFrame
}, completion: { finished in
UIView.animate(withDuration: self.duration, animations: {
self.animateView.backgroundColor = secondColor
self.animateView.frame = secondFrame
}, completion: { finished in
UIView.animate(withDuration: self.duration, animations: {
self.animateView.backgroundColor = thirdColor
self.animateView.frame = thirdFrame
}, completion: nil)
})
})
}
fileprivate func curvePath(_ endPoint: CGPoint, controlPoint1: CGPoint, controlPoint2: CGPoint) {
let path = UIBezierPath()
path.move(to: self.animateView.center)
path.addCurve(to: endPoint, controlPoint1: controlPoint1, controlPoint2: controlPoint2)
// create a new CAKeyframeAnimation that animates the objects position
let anim = CAKeyframeAnimation(keyPath: "position")
// set the animations path to our bezier curve
anim.path = path.cgPath
// set some more parameters for the animation
anim.duration = self.duration
// add the animation to the squares 'layer' property
self.animateView.layer.add(anim, forKey: "animate position along path")
self.animateView.center = endPoint
}
fileprivate func viewFadeIn() {
let secondView = UIImageView(image: UIImage(named: "facebook"))
secondView.frame = self.animateView.frame
secondView.alpha = 0.0
view.insertSubview(secondView, aboveSubview: self.animateView)
UIView.animate(withDuration: duration, delay: delay, options: .curveEaseOut, animations: {
secondView.alpha = 1.0
self.animateView.alpha = 0.0
}, completion: nil)
}
fileprivate func Pop() {
UIView.animate(withDuration: duration / 4,
animations: {
self.animateView.transform = CGAffineTransform(scaleX: CGFloat(self.scale), y: CGFloat(self.scale))
}, completion: { finished in
UIView.animate(withDuration: self.duration / 4, animations: {
self.animateView.transform = CGAffineTransform.identity
})
})
}
Các bạn hãy thử thay các thuộc tính để được các Animation khác nữa nhé !
Oke và giờ ấn chạy thôi !
Bình luận