2016-11-15 23 views
5

Tôi đang làm việc trên biểu đồ hình tròn và tôi cần thêm chế độ xem nhỏ ở cuối vòng tròn được đánh dấu (không phải bóng) để trỏ vào giá trị đích. Tôi có thể tìm thấy một vòng tròn (đánh dấu) siêu xem x, y vị trí dựa trên điểm kết thúc đột quỵ?Làm thế nào để có được vị trí giám sát CAShapeLayer?

UIView->Circle (sử dụng CAShapeLayerUIBezierPath). Tôi cần đặt vị trí UIView dựa trên giá trị kết thúc Circle đột quỵ.

Vui lòng tham khảo liên kết này (như 23% với đường chấm chấm) http://support.softwarefx.com/media/74456678-5a6a-e211-84a5-0019b9e6b500/large

Cảm ơn trước! Need to find green end circle position

Cập nhật: Tôi đã thử alexburtnik mã, thực tế đang làm việc trên đồng hồ khôn ngoan đồ thị trong mục tiêu c nhưng điều đó không phải là một vấn đề ở đây. Tôi đã cố gắng như alexburtnik đã đề cập, tôi tin rằng nó hoàn toàn hoạt động cho đồ thị khôn ngoan chống đồng hồ. Chúng ta cần phải thực hiện một số thay đổi trong mã để làm việc cho chiều kim đồng hồ quá, xin vui lòng cho giải pháp nếu bạn biết.

CGFloat radiusCircle = (self.frame.size.height * 0.5) - ([_lineWidth floatValue]/2.0f); 
-(void)addTargetViewWithOptions:(CGFloat)progress andRadius:(CGFloat)radius{ 

CGFloat x = radius * (1 + (cos(M_PI * (2 * progress + 0.5)))); 
CGFloat y = radius * (1 - (sin(M_PI * (2 * progress + 0.5)))); 
UIView *targetView = [[UIView alloc]initWithFrame:CGRectMake(x, y, 40, 30)]; 
targetView.backgroundColor = [UIColor greenColor]; 
[self addSubview:targetView];} 

Please check my orignal graph

Và tôi đã cố gắng như esthepiking đề cập, ở đây tôi thêm mã và ảnh chụp màn hình

-(void)addTargetView{ 

CGFloat endAngle = -90.01f; 
radiusCircle = (self.frame.size.height * 0.5) - ([_lineWidth floatValue]/2.0f); 
endAngleCircle = DEGREES_TO_RADIANS(endAngle);//-1.570971 

// Size for the text 
CGFloat width = 75; 
CGFloat height = 30; 

// Calculate the location of the end of the stroke 
// Cos calculates the x position of the point (in unit coordinates) 
// Sin calculates the y position of the point (in unit coordinates) 
// Then scale this to be on the range [0, 1] to match the view 
CGFloat endX = (cos(endAngleCircle)/2 + 0.5); 
CGFloat endY = (sin(endAngleCircle)/2 + 0.5); 

// Scale the coordinates to match the diameter of the circle 
endX *= radiusCircle * 2; 
endY *= radiusCircle * 2; 

// Translate the coordinates based on the location of the frame 
endX -= self.frame.origin.x; 
endY -= self.frame.origin.y; 

// Vertically align the label 
endY += height; 

// Setup the label 

UIView *targetView = [[UIView alloc]initWithFrame:CGRectMake(endX, endY, width, height)]; 
targetView.backgroundColor = [UIColor redColor]; 
[self addSubview:targetView];} 

Please check this result

+0

convertPoint: toView: nên làm thủ thuật – Alex

Trả lời

5

1. Math

Hãy quên đi iOS trong chốc lát và giải quyết một vấn đề toán học.

Sự cố: tìm điểm (x; y) cho một α cho trước.

Giải pháp: x = cos (α); y = sin (α)

math

2. Thay

điểm khởi đầu của bạn không phải là ở 0 về lượng giác, mà là tại π/2. Cũng góc vòng cung của bạn được xác định bởi tham số tiến bộ, vì vậy nó mang đến cho bạn thế này:

x = cos (tiến * 2 * π + π/2) = -sin (tiến * 2 * π)
y = sin (tiến * 2 * π + π/2) = cos (tiến * 2 * π)

3. Bây giờ chúng ta hãy quay trở lại iOS:

Vì trong iOS nguồn gốc là ở phía trên góc trái của trục y được hoàn nguyên, bạn nên chuyển đổi giải pháp trước đó theo cách này:

x '= 0,5 * (1 + x)
y' = 0,5 * (1 - y)

xanh là dành cho tọa độ toán học, màu xanh là dành cho iOS hệ thống, mà chúng tôi chuyển đến phối hợp :

iOS

Bây giờ tất cả những gì bạn cần làm là để nhân kết quả bằng width và height:

x '= 0,5 * chiều rộng * (1 - sin (tiến * 2 * π))
y' = 0,5 * chiều cao * (1 - cos (tiến * 2 * π))

4 . Mã số:

func point(progress: Double, radius: CGFloat) -> CGPoint { 
    let x = radius * (1 - CGFloat(sin(progress * 2 * Double.pi)))) 
    let y = radius * (1 - CGFloat(cos(progress * 2 * Double.pi)))) 
    return CGPoint(x: x, y: y) 
} 

Sửa

Nếu bạn muốn chuyển đổi nó để chiều kim đồng hồ, chỉ cần nhân góc bằng -1:

012.351.

x = cos (-progress * 2 * π + π/2) = -sin (-progress * 2 * π) = sin (tiến trình * 2 * π)
y = sin (-progress * 2 * π + π/2) = cos (-progress * 2 * π) = cos (tiến trình * 2 * π)

x '= 0.5 * chiều rộng * (1 + sin (tiến độ * 2 * π))
y'= 0,5 * chiều cao * (1 - cos (tiến * 2 * π))

func point(progress: Double, radius: CGFloat) -> CGPoint { 
    let x = radius * (1 + CGFloat(sin(progress * 2 * Double.pi)))) 
    let y = radius * (1 - CGFloat(cos(progress * 2 * Double.pi)))) 
    return CGPoint(x: x, y: y) 
} 

Hope this helps.

+0

Cảm ơn bạn đã trả lời! Trên thực tế đang làm việc trên đồ thị đồng hồ khôn ngoan trong mục tiêu c nhưng đó không phải là một vấn đề ở đây. Tôi đã thử như bạn đã đề cập, tôi tin rằng nó hoạt động hoàn hảo cho đồ thị thông minh chống đồng hồ. Chúng ta cần phải thực hiện một số thay đổi trong mã để làm việc cho chiều kim đồng hồ quá, xin vui lòng cho giải pháp nếu bạn biết. Tôi đã thêm mã và ảnh chụp màn hình của mình vào câu hỏi ban đầu ở trên. – Gopik

+0

Sau đó, câu hỏi của bạn gây hiểu nhầm vì ảnh chụp màn hình không giống như thanh tiến trình theo chiều kim đồng hồ. – alexburtnik

+0

Vâng, đó là lỗi của tôi. Xin lỗi vì chuyện đó! Bạn có thể có một đồng hồ giải pháp khôn ngoan quá? – Gopik

2

Để có được điểm, bạn sẽ cần phải làm một chút bit của toán học.

Khi bạn xác định vòng cung trong UIBezierPath, bạn chuyển vào startAngleendAngle. Trong trường hợp này, tôi tin rằng bạn muốn xếp hàng một chế độ xem khác khi kết thúc hành trình.

UIBezierPath(arcCenter center: CGPoint, radius: CGFloat, startAngle: CGFloat, endAngle: CGFloat, clockwise: Bool) 

Bây giờ, bạn sẽ cần lấy sin và cos của thông số endAngle đó. Sine của góc kết thúc sẽ cho bạn vị trí y trong tọa độ đơn vị, aka trên phạm vi [-1, 1] và cosin của góc cuối cùng sẽ cho bạn vị trí x cũng trong tọa độ đơn vị. Sau đó, các tọa độ đó có thể được thu nhỏ theo kích thước của vòng cung và được điều chỉnh sao cho nó khớp với khung nhìn, sau đó được dịch chuyển theo vị trí của khung nhìn để có được vị trí kết thúc hành trình.

Đây là một sân chơi mẫu cho hiệu ứng này. Tôi căn chỉnh một nhãn UILabel để văn bản được căn giữa trên điểm kết thúc. Dán phần này vào một sân chơi iOS để tự mình thử.

Demonstrating the centered view

import UIKit 
import PlaygroundSupport 

PlaygroundPage.current.needsIndefiniteExecution = true 

// Frame to wrap all of this inside of 
let frame = UIView(frame: CGRect(x: 0, y: 0, width: 300, height: 300)) 
frame.backgroundColor = .white 

let radius = 100 as CGFloat 

// Outermost gray circle 
let grayCircle = CAShapeLayer() 
grayCircle.frame = frame.frame 
grayCircle.path = UIBezierPath(arcCenter: frame.center, radius: radius, startAngle: 0, endAngle: CGFloat(M_PI * 2), clockwise: true).cgPath 
grayCircle.strokeColor = UIColor.lightGray.cgColor 
grayCircle.lineWidth = 10 
grayCircle.fillColor = UIColor.clear.cgColor 

frame.layer.addSublayer(grayCircle) 

// Ending angle for the arc 
let endAngle = CGFloat(M_PI/5) 

// Inner green arc 
let greenCircle = CAShapeLayer() 
greenCircle.frame = frame.frame 
greenCircle.path = UIBezierPath(arcCenter: frame.center, radius: radius, startAngle: CGFloat(-M_PI_2), endAngle: endAngle, clockwise: false).cgPath 
greenCircle.strokeColor = UIColor.green.cgColor 
greenCircle.lineWidth = 10 
greenCircle.fillColor = UIColor.clear.cgColor 
greenCircle.lineCap = kCALineCapRound 

frame.layer.addSublayer(greenCircle) 

// Size for the text 
let width = 75 as CGFloat 
let height = 30 as CGFloat 

// Calculate the location of the end of the stroke 
// Cos calculates the x position of the point (in unit coordinates) 
// Sin calculates the y position of the point (in unit coordinates) 
// Then scale this to be on the range [0, 1] to match the view 
var endX = (cos(endAngle)/2 + 0.5) 
var endY = (sin(endAngle)/2 + 0.5) 

// Scale the coordinates to match the diameter of the circle 
endX *= radius * 2 
endY *= radius * 2 

// Translate the coordinates based on the location of the frame 
endX -= frame.frame.origin.x 
endY -= frame.frame.origin.y 

// Vertically align the label 
endY += height 

// Setup the label 
let text = UILabel(frame: CGRect(x: endX, y: endY, width: width, height: height)) 
text.text = "Stroke end!" 
text.font = UIFont.systemFont(ofSize: 14) 
frame.addSubview(text) 

PlaygroundPage.current.liveView = frame 
+0

Cảm ơn sự giúp đỡ của bạn. Tôi đã thêm kết quả của mình ở trên. Bạn có thể vui lòng kiểm tra xem nó. – Gopik

+0

@ user1591698 có vẻ như bạn đã làm việc hoặc ít nhất là khá gần. Có thể bạn cần loại bỏ 'endY + = height' cho trường hợp sử dụng của bạn. – esthepiking

+0

Có! Cảm ơn một lần nữa :) – Gopik

Các vấn đề liên quan