我有一個UIView的有邊界的圈子中,像這樣如何使拉伸在iOS
我想要像伸展它的效果的圓形效果,請參見下面的圖像
它喜歡pullToRefresh效果,有許多庫或opensources來做pullToRefresh,但它們總是屬於tableview。我只是想獨立做出伸展效果。我只是有一個盤旋的UIView和它的拉伸時,我把它
我怎樣才能使它
我有一個UIView的有邊界的圈子中,像這樣如何使拉伸在iOS
我想要像伸展它的效果的圓形效果,請參見下面的圖像
它喜歡pullToRefresh效果,有許多庫或opensources來做pullToRefresh,但它們總是屬於tableview。我只是想獨立做出伸展效果。我只是有一個盤旋的UIView和它的拉伸時,我把它
我怎樣才能使它
目前已經可以爲你的控制: circle with strech
除了上面我會給一個嘗試這種方法也是: 我認爲你可以有完整的拉伸圖像,隱藏在它上面的白色視圖。當用戶向下或向上滑動時,您可以顯示/隱藏部分拉伸圖像。
如果用戶沒有刷過,則顯示未被刷新的圓形圖像,並且如果用戶已經刷新了預測距離,則顯示完全拉伸的圖像。
您可能需要自定義繪圖。只是伸展一個視圖會導致出現鋸齒和視圖變形。
要做到這一點,你應該繼承UIView
並覆蓋drawRect
做一些可以響應用戶交互的繪圖。
我創建了一個示例類:
class CircleRefresh:UIView{
var taperFactor:CGFloat = 0.00{
didSet{
self.setNeedsDisplay()
}
}
var heightFactor: CGFloat = 0.40
{
didSet{
self.setNeedsDisplay()
}
}
var radius:CGFloat
{
return self.frame.size.height * 0.20
}
//Set this to add an arrow or another image to the top circle
var refreshImage:UIImage?{
didSet{
//
self.subviews.forEach{$0.removeFromSuperview()}
if let image = self.refreshImage{
let imageView = UIImageView(frame: CGRect(x:self.frame.size.width * 0.5 - self.radius,y:0.0,width:self.radius * 2.0,height:self.radius * 2.0))
imageView.image = image
imageView.contentMode = .ScaleAspectFit
imageView.layer.cornerRadius = imageView.frame.size.height * 0.5
imageView.layer.masksToBounds = true
self.addSubview(imageView)
}
}
}
override func drawRect(rect:CGRect)
{
UIColor.lightGrayColor().setFill()
let endCenter = CGPoint(x:self.frame.size.width * 0.5,y:self.frame.size.height * heightFactor - radius * taperFactor)
//top arc
let path = UIBezierPath(arcCenter: CGPoint(x:self.frame.size.width * 0.5, y:radius), radius: self.frame.size.height * 0.20, startAngle: 0.0, endAngle: CGFloat(M_PI), clockwise: false)
//left curve
path.addCurveToPoint(CGPoint(x:endCenter.x - radius * taperFactor,y:endCenter.y), controlPoint1: CGPoint(x:endCenter.x - radius, y:radius * 2.0), controlPoint2: CGPoint(x: endCenter.x - radius * taperFactor, y: radius * 2.0))
//bottom arc
path.addArcWithCenter(endCenter, radius: radius * taperFactor, startAngle: CGFloat(M_PI), endAngle: 0.0, clockwise: false)
//right curve
path.addCurveToPoint(CGPoint(x:endCenter.x + radius,y:radius), controlPoint1: CGPoint(x: endCenter.x + radius * taperFactor, y: radius * 2.0),controlPoint2: CGPoint(x:endCenter.x + radius, y:radius * 2.0))
path.fill()
}
}
這將畫一個圓,但改變taperFactor
和heightFactor
會給一個拉伸效果。將heightFactor
設置爲1.0將意味着圖形將佔據視圖的整個高度,並將taperFactor
設置爲1.0將導致圖形的尾部與頂部圓形一樣寬。
要獲得如何改變heightFactor
和taperFactor
改變圖紙的感覺,你可以再添加一個平移手勢識別這一觀點,並在它的行動這樣說:
@IBAction func pan(sender: UIPanGestureRecognizer) {
let location = sender.locationInView(self.view)
circle.heightFactor = location.y/self.view.frame.size.height
circle.taperFactor = circle.heightFactor * 0.5 - 0.20
}
您可以更改heightFactor
和taperFactor
達到不同的效果。這只是如何做一個刷新控制器的一部分,但似乎是你的問題的主旨。
基本的想法是使用貝塞爾路徑來勾勒出您要查找的精確形狀。然後,您可以使用手勢來改變外形和使用顯示器鏈接到動畫拉伸圓的返回回其圓形形式:
@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
}
}
這使得類似:
顯然,可以隨意隨意找到合適的路徑,添加像旋轉箭頭或其他任何東西等額外的繁榮,但這說明了構建貝塞爾路徑,用手勢拉伸它,並將其恢復爲圓形形狀的基礎知識。
如何通過輪廓線製作此動畫?並在左右兩邊 –
我不明白你的意思是「等高線」。我實際上建議你只是發表你自己的問題...... – Rob