2016-11-15 1 views
5

원형 차트에서 작업 중이며 대상 값을 가리 키기 위해 그림자가 아닌 강조 표시된 원의 끝에 작은보기를 추가해야합니다. 스트로크 종점을 기준으로 원 (강조 표시) 수퍼 뷰 x, y 위치를 찾을 수 있습니까?CAShapeLayer 수퍼 뷰 위치 얻는 방법?

UIView->Circle (CAShapeLayerUIBezierPath을 사용). Circle 획 값을 기준으로 UIView의 위치를 ​​가져와야합니다.

(점선과 같은 23 %)이 링크 미리 http://support.softwarefx.com/media/74456678-5a6a-e211-84a5-0019b9e6b500/large

감사를 참조하십시오! Need to find green end circle position

업데이트 : 나는 사실 객관적인 C에서 시계 방향 그래프에서하고 있어요 alexburtnik 코드를 시도하지만 여기에 문제가되지 않습니다. 내가 언급 한 것처럼 alexburtnik, 나는 완벽하게 반 시계 현명한 그래프에 대한 작동 믿습니다. 시계 방향으로 작업하려면 코드를 약간 변경해야합니다. 알고 있다면 해결책을주십시오.

Please check my orignal graph

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];} 
와 나는 언급 esthepiking로, 여기에 내가

-(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 : 트릭을 수행해야합니다. – Alex

답변

5

1. 수학

의 잠시가 iOS 잊고 수학 문제를 해결하자.

문제 : 주어진 α에 대해 (x; y) 점을 찾습니다.

해결책 : x = cos (α); Y = 죄 (α)

math

2. 대체

귀하의 출발점은 삼각 함수의 관점에서 0이 아니라에서 π/2. 또한 아크 각도를 진행 매개 변수에 의해 정의, 그래서이 당신을 가져온다 :

X = COS (진행 * 2 * π + π/2) = -sin (진행 * 2 * π)
Y = 죄 (진행 * 2 * π + π/2) = COS (진행 * 2 * π) 이제

3의 아이폰 OS로 돌아가 보자

이후 아이폰 OS에서 기원 상단에 왼쪽 구석에 y 축을 되 돌리면 이전 방법을 다음과 같이 변환해야합니다.

,

X '= 0.5 * (1 + X)
Y'= 0.5 * - iOS의 우리로 변환 좌표계 (1 Y)

녹색 수학 좌표 블루되어있다 :

:

iOS

지금 당신이해야 할 모든 폭과 높이에 의해 결과를 곱하는 것입니다

X '= 0.5 * 폭 * (1 - 죄 (진행 * 2 * π))
Y'= 0.5 * 높이 * (1 - COS (진행 * 2 * π))

4 . 코드 :

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) 
} 

편집

그냥 -1에 의해 각도를 곱하면, 시계 방향으로 전환하려면 :

X = COS (-progress * 2 * π + π/2) = -sin (-progress * 2 * π) = 죄 (진행 * 2 * π)
죄 Y = (2 * -progress 2 * π) = cos (진행 * 2 * π)

x '= 0.5 * width * (1 + sin (진행 * 2 * π))
Y '= 0.5 * 높이 * (1 - COS (진행 * 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) 
} 

바란다.

+0

답장을 보내 주셔서 감사합니다! 사실 목표 C에서 시계 방향 그래프로 작업하고 있지만 여기에는 문제가 없습니다. 내가 언급 한대로 시도했지만, 그것은 반 시계 현명한 그래프에서 완벽하게 작동한다고 믿습니다. 시계 방향으로 작업하려면 코드를 약간 변경해야합니다. 알고 있다면 해결책을주십시오. 위의 원래 질문에서 코드 및 스크린 샷을 추가했습니다. – Gopik

+0

그런 다음 스크린 샷이 시계 방향 진행 바처럼 보이지 않으므로 질문에 오해의 소지가 있습니다. – alexburtnik

+0

네, 저의 실수였습니다. 그 죄송합니다! 솔루션 시계를 현명하게 사용할 수도 있습니까? – Gopik

2

는 점을 얻으려면 코드 및 스크린 샷을 추가했는데, 당신은 조금을 수행해야합니다 수학의 비트.

UIBezierPath에서 호를 정의 할 때 startAngleendAngle을 전달합니다. 이 경우 뇌졸중이 끝나면 다른 뷰를 정렬하고 싶다고 생각합니다.

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

이제 endAngle 매개 변수의 사인과 코사인을 가져와야합니다. 끝 각도의 사인은 단위 좌표에서 y 위치를 지정합니다. 범위 [-1, 1]에 지정하고 끝 각도의 코사인을 사용하면 단위 좌표에서도 x 위치를 얻을 수 있습니다. 그런 다음 좌표를 호의 크기로 조절하고 뷰와 일치하도록 조정 한 다음 뷰의 위치로 이동하여 획 끝의 위치를 ​​가져올 수 있습니다.

다음은이 효과를위한 놀이터의 예입니다. 텍스트가 끝점의 중앙에 오도록 UILabel을 정렬했습니다. 이것을 iOS 놀이터에 붙여 넣어 직접 사용해보십시오.

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

도움 주셔서 감사합니다. 위에 결과를 추가했습니다. 확인해 주시겠습니까? – Gopik

+0

@ user1591698 당신이 일하는 것처럼 보이거나, 적어도 꽤 가까이에있는 것처럼 보입니다. 당신의 유스 케이스에 대해'endY + = height'를 제거 할 필요가있을 수 있습니다. – esthepiking

+0

예! 다시 한 번 감사드립니다 :) – Gopik

관련 문제