我有一個名為 CategoryCell 的類,我們使用 UICollectionViewCell。
在 CellForItemAt 函式上:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
drawfunction.draw_Footing(withView: cell.view)
繪圖將在 cell.view 中。
draw_Footing 函式是一個繪制一些線條的函式,它位于 NSObject 的 drawfunction 類中。在同一個類中,我有一個函式呼叫 animateShape,它可以為兩點(CGpoint)之間的一條線設定影片。
func animateShape(view: UIView, p1: CGpoint, p2: CGPoint) {
let shapeLayer = CAShapeLayer()
shapeLayer.removeFromSuperlayer()
// create whatever path you want
shapeLayer.fillColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 0).cgColor
shapeLayer.strokeColor = color.cgColor
shapeLayer.lineWidth = linewidth//CGFloat(1.5)
shapeLayer.path = path.cgPath
// animate it
view.layer.addSublayer(shapeLayer)
let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.fromValue = 0
animation.duration = duration//0.5
shapeLayer.add(animation, forKey: "MyAnimation")
}
我有4個點G1,G2,G3,G4。我需要在這 4 個點之間制作一條線。所以,如果我這樣做:
animateShape(view, p1: G1, p2: G2)
animateShape(view, p1: G2, p2: G3)
animateShape(view, p1: G3, p2: G4)
所有線條將同時影片化。我需要首先對 G1 和 G2 之間的線進行影片處理,完成后,需要對 G2 和 G3 之間的線進行影片處理,而不是同時進行。我試圖包括 dispatchQueue,但我不確定,也不知道怎么做。
有什么建議嗎?
uj5u.com熱心網友回復:
事情是,我看不出是如何path使用你的觀點實際創建p1的p2
無論如何,我假設您的最終目標是在 a 中繪制線條路徑影片,UICollectionViewCell這就是我根據您問題中給出的描述試圖實作的目標。
首先是繪圖類:
class DrawFunction: NSObject
{
weak var shapeLayer: CAShapeLayer?
// Change as you wish
let duration = 2.0
// Responsible for drawing the lines from any number of points
func drawFooting(points: [CGPoint])
{
guard !points.isEmpty else { return }
// Remove old drawings
shapeLayer?.removeFromSuperlayer()
let path = UIBezierPath()
// This is actual drawing path using the points
// I don't see this in your code
for (index, point) in points.enumerated()
{
// first pair of points
if index == 0
{
// Move to the starting point
path.move(to: point)
continue
}
// Draw a line from the previous point to the current
path.addLine(to: point)
}
// Create a shape layer to visualize the path
let shapeLayer = CAShapeLayer()
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.strokeColor = randomColor().cgColor
shapeLayer.lineWidth = 5
shapeLayer.path = path.cgPath
self.shapeLayer = shapeLayer
}
// Animate function to be called after shape has been drawn
// by specifying the view to show this animation in
func animateShape(in view: UIView)
{
if let shapeLayer = shapeLayer
{
view.layer.addSublayer(shapeLayer)
let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.fromValue = 0
animation.duration = duration
shapeLayer.add(animation, forKey: "MyAnimation")
}
}
// You can ignore this function, just for convenience
private func randomColor() -> UIColor
{
let red = CGFloat(arc4random_uniform(256)) / 255.0
let blue = CGFloat(arc4random_uniform(256)) / 255.0
let green = CGFloat(arc4random_uniform(256)) / 255.0
return UIColor(red: red, green: green, blue: blue, alpha: 1.0)
}
}
然后基本的自定義單元設定,沒什么花哨的,只是為了完整性而添加
// Basic Cell, nothing unique here
class CategoryCell: UICollectionViewCell
{
static let identifier = "cell"
override init(frame: CGRect)
{
super.init(frame: frame)
configure()
}
required init?(coder: NSCoder)
{
fatalError("init(coder:) has not been implemented")
}
private func configure()
{
contentView.backgroundColor = .lightGray
contentView.layer.cornerRadius = 5.0
contentView.clipsToBounds = true
}
}
The view controller set up where the most interesting parts are in the willDisplay cell function
class LineAnimateVC: UICollectionViewController
{
// Random points to draw lines
let points = [[CGPoint(x: 0.0, y: 10),
CGPoint(x: UIScreen.main.bounds.midX, y: 10),
CGPoint(x: UIScreen.main.bounds.midX, y: 50)],
[CGPoint(x: 0.0, y: 10),
CGPoint(x: UIScreen.main.bounds.midX, y: 10),
CGPoint(x: UIScreen.main.bounds.midX, y: 50),
CGPoint(x: UIScreen.main.bounds.maxX, y: 50)],
[CGPoint(x: 0.0, y: 10),
CGPoint(x: UIScreen.main.bounds.midX, y: 10),
CGPoint(x: UIScreen.main.bounds.midX, y: 50),
CGPoint(x: UIScreen.main.bounds.midX 40, y: 50),
CGPoint(x: UIScreen.main.bounds.midX 40, y: UIScreen.main.bounds.maxY),
CGPoint(x: UIScreen.main.bounds.maxX, y: UIScreen.main.bounds.maxY)],
[CGPoint(x: 0.0, y: 10),
CGPoint(x: UIScreen.main.bounds.midX, y: 10),
CGPoint(x: UIScreen.main.bounds.midX, y: 50)],
[CGPoint(x: 0.0, y: 10),
CGPoint(x: UIScreen.main.bounds.midX, y: 10),
CGPoint(x: UIScreen.main.bounds.midX, y: 50),
CGPoint(x: UIScreen.main.bounds.midX 40, y: 50),
CGPoint(x: UIScreen.main.bounds.midX 40, y: UIScreen.main.bounds.maxY),
CGPoint(x: UIScreen.main.bounds.maxX, y: UIScreen.main.bounds.maxY)]
]
override func viewDidLoad()
{
super.viewDidLoad()
view.backgroundColor = .white
title = "Line animate"
collectionView.register(CategoryCell.self,
forCellWithReuseIdentifier: CategoryCell.identifier)
collectionView.backgroundColor = .white
}
// Number of cells equals to points we have
override func collectionView(_ collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int
{
return points.count
}
override func collectionView(_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CategoryCell.identifier,
for: indexPath) as! CategoryCell
return cell
}
// Add animation when cell is about to be displayed
override func collectionView(_ collectionView: UICollectionView,
willDisplay cell: UICollectionViewCell,
forItemAt indexPath: IndexPath)
{
let cell = cell as! CategoryCell
// Draw the path and perform the animation
let drawingFunction = DrawFunction()
drawingFunction.drawFooting(points: points[indexPath.row])
drawingFunction.animateShape(in: cell.contentView)
}
}
Just for completeness, my flow layout set up
// Basic set up stuff
extension LineAnimateVC: UICollectionViewDelegateFlowLayout
{
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize
{
return CGSize(width: collectionView.frame.width, height: 300)
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
minimumLineSpacingForSectionAt section: Int) -> CGFloat
{
return 20
}
}
This gives me an animated path in the collectionview cell

Hope this gives you some ideas to achieve your task
Update
Based on OP, Xin Lok's comment:
However still did not get what I want, lets say I have path1 = [p1,p2,p3,p4,p5] and path2 = [m1,m2,m3], if I run drawFooting(points: path1) and drawFooting(path2), both of the 2 paths will be animated in the same time , and this what I don't want, I need to complete animation for Path1, and then after finish to proceed with animation of Path2. I tried to insert sleep, but it did not work
Based on that comment, One way I can think of achieving that is to I think the key is to reuse and persist with the shape layer and the path.
Here are some updates I made based on that conclusion
First I just made a simple struct so we can create lines easily
struct Line
{
var points: [CGPoint] = []
init(_ points: [CGPoint])
{
self.points = points
}
}
Then I create some random lines and grouped them in an array
// Random lines
// Random lines
let line1 = Line([CGPoint(x: 0, y: 10),
CGPoint(x: UIScreen.main.bounds.midX, y: 10)])
let line2 = Line([CGPoint(x: 0, y: 70),
CGPoint(x: UIScreen.main.bounds.midX, y: 70),
CGPoint(x: UIScreen.main.bounds.midX, y: 100)])
let line3 = Line([CGPoint(x: 0, y: 150),
CGPoint(x: UIScreen.main.bounds.midX, y: 110),
CGPoint(x: UIScreen.main.bounds.maxX, y: 190)])
let line4 = Line([CGPoint(x: 0, y: 210),
CGPoint(x: UIScreen.main.bounds.maxX / 4, y: 235),
CGPoint(x: UIScreen.main.bounds.maxX * 0.75, y: 220),
CGPoint(x: UIScreen.main.bounds.maxX,
y: UIScreen.main.bounds.maxY)])
var lineGroups: [[Line]] = []
private func setLines()
{
// First cell, it should draw lines in the order 3 -> 1 -> 2
// Second cell, in the order 4 -> 3 -> 2 -> 1
lineGroups = [[line3, line1, line2],
[line4, line3, line2, line1]]
}
Importantly note the line order in each array, because this is the order they will be drawn
In the drawing class, I made some changes to persist the CAShapeLayer and path
A special mention to jrturton in the comments for suggesting CGMutablePath and simplifying the path creation.
class DrawFunction: NSObject
{
weak var shapeLayer: CAShapeLayer?
var path: CGMutablePath?
// Change as you wish
let duration = 5.0
// Responsible for drawing the lines from any number of points
func drawFooting(line: Line)
{
var shapeLayer = CAShapeLayer()
if self.shapeLayer != nil
{
shapeLayer = self.shapeLayer!
}
if path == nil
{
path = CGMutablePath()
}
// Thank you @jrturton for this
path?.addLines(between: line.points)
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.strokeColor = randomColor().cgColor
shapeLayer.lineWidth = 5
shapeLayer.path = path
self.shapeLayer = shapeLayer
}
// Animate function to be called after shape has been drawn
// by specifying the view to show this animation in
func animateShape(in view: UIView)
{
if let shapeLayer = shapeLayer
{
view.layer.addSublayer(shapeLayer)
let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.fromValue = 0
animation.duration = duration
shapeLayer.add(animation, forKey: "MyAnimation")
}
}
// You can ignore this function, just for convenience
private func randomColor() -> UIColor
{
let red = CGFloat(arc4random_uniform(256)) / 255.0
let blue = CGFloat(arc4random_uniform(256)) / 255.0
let green = CGFloat(arc4random_uniform(256)) / 255.0
return UIColor(red: red, green: green, blue: blue, alpha: 1.0)
}
}
Then some minor changes in the collectionview cell configuration
// Number of cells equals to lines we have
override func collectionView(_ collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int
{
return lineGroups.count
}
override func collectionView(_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
let cell
= collectionView.dequeueReusableCell(withReuseIdentifier: CategoryCell.identifier,
for: indexPath) as! CategoryCell
return cell
}
// Add animation when cell is about to be displayed
override func collectionView(_ collectionView: UICollectionView,
willDisplay cell: UICollectionViewCell,
forItemAt indexPath: IndexPath)
{
let cell = cell as! CategoryCell
let lines = lineGroups[indexPath.item]
// Draw the path and perform the animation
let drawingFunction = DrawFunction()
for line in lines
{
drawingFunction.drawFooting(line: line)
}
drawingFunction.animateShape(in: cell.contentView)
}
Now again, for convenience, remember the order in which they should be drawn:
First cell, it should draw lines in the order 3 -> 1 -> 2
Second cell, in the order 4 -> 3 -> 2 -> 1
The end result:

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/427812.html
