Add typing indicator animation.

pull/1/head
Matthew Chen 7 years ago
parent 63d88ef5cb
commit 37ae4ef360

@ -56,7 +56,6 @@ public class TypingIndicatorCell: ConversationViewCell {
bubbleView.bubbleColor = conversationStyle.bubbleColor(isIncoming: true) bubbleView.bubbleColor = conversationStyle.bubbleColor(isIncoming: true)
typingIndicatorView.startAnimation() typingIndicatorView.startAnimation()
typingIndicatorView.addBackgroundView(withBackgroundColor: UIColor.red)
viewConstraints.append(contentsOf: [ viewConstraints.append(contentsOf: [
bubbleView.autoPinEdge(toSuperviewEdge: .leading, withInset: conversationStyle.gutterLeading), bubbleView.autoPinEdge(toSuperviewEdge: .leading, withInset: conversationStyle.gutterLeading),

@ -31,9 +31,9 @@
super.init(frame: .zero) super.init(frame: .zero)
// init(arrangedSubviews:...) is not a designated initializer. // init(arrangedSubviews:...) is not a designated initializer.
addArrangedSubview(dot1) for dot in dots() {
addArrangedSubview(dot2) addArrangedSubview(dot)
addArrangedSubview(dot3) }
self.axis = .horizontal self.axis = .horizontal
self.spacing = kDotMaxHSpacing self.spacing = kDotMaxHSpacing
@ -45,12 +45,22 @@
return CGSize(width: TypingIndicatorView.kMaxRadiusPt * 3 + kDotMaxHSpacing * 2, height: TypingIndicatorView.kMaxRadiusPt) return CGSize(width: TypingIndicatorView.kMaxRadiusPt * 3 + kDotMaxHSpacing * 2, height: TypingIndicatorView.kMaxRadiusPt)
} }
private func dots() -> [DotView] {
return [dot1, dot2, dot3]
}
@objc @objc
public func startAnimation() { public func startAnimation() {
for dot in dots() {
dot.startAnimation()
}
} }
@objc @objc
public func stopAnimation() { public func stopAnimation() {
for dot in dots() {
dot.stopAnimation()
}
} }
private enum DotType { private enum DotType {
@ -82,18 +92,86 @@
autoSetDimension(.width, toSize: kMaxRadiusPt) autoSetDimension(.width, toSize: kMaxRadiusPt)
autoSetDimension(.height, toSize: kMaxRadiusPt) autoSetDimension(.height, toSize: kMaxRadiusPt)
self.layer.addSublayer(shapeLayer) layer.addSublayer(shapeLayer)
updateLayer()
} }
private func updateLayer() { fileprivate func startAnimation() {
shapeLayer.fillColor = UIColor.ows_signalBlue.cgColor stopAnimation()
let margin = (TypingIndicatorView.kMaxRadiusPt - TypingIndicatorView.kMinRadiusPt) * 0.5 let timeIncrement: CFTimeInterval = 0.15
let bezierPath = UIBezierPath(ovalIn: CGRect(x: margin, y: margin, width: TypingIndicatorView.kMinRadiusPt, height: TypingIndicatorView.kMinRadiusPt)) var colorValues = [CGColor]()
shapeLayer.path = bezierPath.cgPath var pathValues = [CGPath]()
var keyTimes = [CFTimeInterval]()
var animationDuration: CFTimeInterval = 0
let addDotKeyFrame = { (keyFrameTime: CFTimeInterval, progress: CGFloat) in
let dotColor = UIColor(rgbHex: 0x636467).withAlphaComponent(CGFloatLerp(0.4, 1.0, progress))
colorValues.append(dotColor.cgColor)
let radius = CGFloatLerp(TypingIndicatorView.kMinRadiusPt, TypingIndicatorView.kMaxRadiusPt, progress)
let margin = (TypingIndicatorView.kMaxRadiusPt - radius) * 0.5
let bezierPath = UIBezierPath(ovalIn: CGRect(x: margin, y: margin, width: radius, height: radius))
pathValues.append(bezierPath.cgPath)
keyTimes.append(keyFrameTime)
animationDuration = max(animationDuration, keyFrameTime)
}
// All animations in the group apparently need to have the same number
// of keyframes, and use the same timing.
switch dotType {
case .dotType1:
addDotKeyFrame(0 * timeIncrement, 0.0)
addDotKeyFrame(1 * timeIncrement, 0.5)
addDotKeyFrame(2 * timeIncrement, 1.0)
addDotKeyFrame(3 * timeIncrement, 0.5)
addDotKeyFrame(4 * timeIncrement, 0.0)
addDotKeyFrame(5 * timeIncrement, 0.0)
addDotKeyFrame(6 * timeIncrement, 0.0)
addDotKeyFrame(10 * timeIncrement, 0.0)
break
case .dotType2:
addDotKeyFrame(0 * timeIncrement, 0.0)
addDotKeyFrame(1 * timeIncrement, 0.0)
addDotKeyFrame(2 * timeIncrement, 0.5)
addDotKeyFrame(3 * timeIncrement, 1.0)
addDotKeyFrame(4 * timeIncrement, 0.5)
addDotKeyFrame(5 * timeIncrement, 0.0)
addDotKeyFrame(6 * timeIncrement, 0.0)
addDotKeyFrame(10 * timeIncrement, 0.0)
break
case .dotType3:
addDotKeyFrame(0 * timeIncrement, 0.0)
addDotKeyFrame(1 * timeIncrement, 0.0)
addDotKeyFrame(2 * timeIncrement, 0.0)
addDotKeyFrame(3 * timeIncrement, 0.5)
addDotKeyFrame(4 * timeIncrement, 1.0)
addDotKeyFrame(5 * timeIncrement, 0.5)
addDotKeyFrame(6 * timeIncrement, 0.0)
addDotKeyFrame(10 * timeIncrement, 0.0)
break
}
let makeAnimation: (String, [Any]) -> CAKeyframeAnimation = { (keyPath, values) in
let animation = CAKeyframeAnimation()
animation.keyPath = keyPath
animation.values = values
animation.duration = animationDuration
return animation
}
let groupAnimation = CAAnimationGroup()
groupAnimation.animations = [
makeAnimation("fillColor", colorValues),
makeAnimation("path", pathValues)
]
groupAnimation.duration = animationDuration
groupAnimation.repeatCount = MAXFLOAT
shapeLayer.add(groupAnimation, forKey: UUID().uuidString)
}
fileprivate func stopAnimation() {
shapeLayer.removeAllAnimations()
} }
} }
} }

Loading…
Cancel
Save