gpt4 book ai didi

ios - 如何在ios上制作拉伸(stretch)圆圈效果

转载 作者:行者123 更新时间:2023-11-28 18:53:19 25 4
gpt4 key购买 nike

我有一个以圆为界的 UIView,像这样

enter image description here

我想做一个像拉伸(stretch)一样的效果,看下图

enter image description here

它喜欢 pullToRefresh 效果,有很多库或开源可以制作 pullToRefresh,但它们始终属于 tableview。我只想独立制作拉伸(stretch)效果。我只有一个带圆圈的 UIView,当我拉它时它被拉伸(stretch)了

我该怎么做

最佳答案

基本思想是使用贝塞尔曲线路径勾勒出您要寻找的精确形状。然后,您可以使用手势来更改该形状并使用显示链接来动画化拉伸(stretch)的圆返回到其圆形形式:

@IBDesignable
class RefreshView: UIView {

private let shapeLayer = CAShapeLayer()

@IBInspectable
var fillColor: UIColor = UIColor.lightGrayColor() {
didSet {
shapeLayer.fillColor = fillColor.CGColor
}
}

@IBInspectable
var strokeColor: UIColor = UIColor.clearColor() {
didSet {
shapeLayer.strokeColor = strokeColor.CGColor
}
}

@IBInspectable
var lineWidth: CGFloat = 0.0 {
didSet {
shapeLayer.strokeColor = strokeColor.CGColor
}
}

/// Center of main circle is in center top

private var pullDownCenter: CGPoint {
return CGPoint(x: bounds.size.width / 2.0, y: bounds.size.width / 2.0)
}

/// Radius of view spans width of view

private var radius: CGFloat {
return bounds.size.width / 2.0
}

override var frame: CGRect {
get {
return super.frame
}
set {
super.frame = newValue
updatePath()
}
}

override init(frame: CGRect) {
super.init(frame: frame)
configureView()
}

required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
configureView()
}

/// Update the path, add shape layer, and add gesture recognizer

private func configureView() {
shapeLayer.fillColor = fillColor.CGColor
shapeLayer.strokeColor = strokeColor.CGColor
shapeLayer.lineWidth = lineWidth

updatePath()
layer.addSublayer(shapeLayer)

let pan = UIPanGestureRecognizer(target: self, action: #selector(RefreshView.handlePan(_:)))
addGestureRecognizer(pan)
}

/// Update path

private func updatePath() {
shapeLayer.path = stretchyCirclePathWithCenter(pullDownCenter, radius: radius, yOffset: yOffset).CGPath
}

override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
yOffset = yOffsetMax
}

// MARK: Gesture Recognizer

private var yOffset: CGFloat = 0.0 { didSet { updatePath() } }
private var yOffsetMax: CGFloat { return bounds.size.width * 1.5 }
private var yOldOffset: CGFloat = 0.0

func handlePan(gesture: UIPanGestureRecognizer) {
if gesture.state == .Began {
yOldOffset = yOffset
} else if gesture.state == .Changed {
yOffset = yOldOffset + max(0, min(gesture.translationInView(gesture.view).y, yOffsetMax))
} else if gesture.state == .Ended || gesture.state == .Cancelled {
animateBackToCircle()
}
}

// MARK: Animation

private var displayLink: CADisplayLink?
private var duration: CGFloat?
private var startTime: CFAbsoluteTime?
private var originalOffset: CGFloat?

private func animateBackToCircle() {
displayLink = CADisplayLink(target: self, selector: #selector(RefreshView.handleDisplayLink(_:)))
duration = 0.5
originalOffset = yOffset
startTime = CFAbsoluteTimeGetCurrent()
displayLink?.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)
}

func handleDisplayLink(displayLink: CADisplayLink) {
let percent = CGFloat(CFAbsoluteTimeGetCurrent() - startTime!) / duration!

if percent < 1.0 {
yOffset = originalOffset! * (1.0 - sin(percent * CGFloat(M_PI_2)))
} else {
self.displayLink?.invalidate()
self.displayLink = nil
updatePath()
}
}

// MARK: Stretch circle path

private func stretchyCirclePathWithCenter(center: CGPoint, radius: CGFloat, yOffset: CGFloat = 0.0) -> UIBezierPath {
func pointWithCenter(center: CGPoint, radius: CGFloat, angle: CGFloat) -> CGPoint {
return CGPoint(x: center.x + radius * cos(angle), y: center.y + radius * sin(angle))
}

if yOffset == 0 {
return UIBezierPath(arcCenter: center, radius: radius, startAngle: 0, endAngle: 2.0 * CGFloat(M_PI), clockwise: true)
}

let lowerRadius = radius * (1 - yOffset / yOffsetMax * 0.5)
let yOffsetTop = yOffset / 4
let yOffsetBottom = yOffset / 1.5
let path = UIBezierPath(arcCenter: center, radius: radius, startAngle: CGFloat(M_PI), endAngle: 0, clockwise: true)
path.addCurveToPoint(CGPoint(x: center.x + lowerRadius, y:center.y + yOffset), controlPoint1: CGPoint(x: center.x + radius, y:center.y + yOffsetTop), controlPoint2: CGPoint(x: center.x + lowerRadius, y:center.y + yOffset - yOffsetBottom))
path.addArcWithCenter(CGPoint(x: center.x, y:center.y + yOffset), radius: lowerRadius, startAngle: 0, endAngle: CGFloat(M_PI), clockwise: true)
path.addCurveToPoint(CGPoint(x: center.x - radius, y:center.y), controlPoint1: CGPoint(x: center.x - lowerRadius, y:center.y + yOffset - yOffsetBottom), controlPoint2: CGPoint(x: center.x - radius, y:center.y + yOffsetTop))

return path
}

}

这会呈现如下内容:

enter image description here

很明显,您可以根据自己的喜好随意调整路径,添加额外的花饰,例如旋转箭头或其他任何东西。但这说明了构建贝塞尔曲线路径的基础知识,用手势拉伸(stretch)它,并将其动画化回它的圆形。

关于ios - 如何在ios上制作拉伸(stretch)圆圈效果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37281627/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com