2015-04-01 44 views
0

我試圖在UIView中實現時鐘臉 - 沒有太多的運氣。問題是鐘錶上的手完全處於錯誤的位置(即指向錯誤的時間)。我很確定我的代碼的邏輯是正確的 - 但顯然存在明顯的錯誤。在UIView中實現時鐘臉

我的測試應用程序是一個iOS單一視圖應用程序。 ViewController.h看起來是這樣的:

#import <UIKit/UIKit.h> 

@interface Clock : UIView { 
    UIColor* strokeColour; 
    UIColor* fillColour; 
    float strokeWidth; 
    NSDate* clockTime; 
    CGPoint clockCentre; 
    float clockRadius; 
} 
- (id)initWithCentre:(CGPoint)centre 
       radius:(float)radius 
     borderWidth:(float)width 
      facecolour:(UIColor*)fill 
      handcolour:(UIColor*)handFill 
       time:(NSDate*)time; 
@end 

@interface ViewController : UIViewController 

@end 

和ViewController.m看起來是這樣的:

#import "ViewController.h" 

@implementation Clock 

- (id)initWithCentre:(CGPoint)centre 
       radius:(float)radius 
     borderWidth:(float)width 
      facecolour:(UIColor*)fill 
      handcolour:(UIColor*)handFill 
       time:(NSDate*)time { 

    CGRect frame = CGRectMake(centre.x-radius, 
           centre.y-radius, 
           radius*2, 
           radius*2); 

    if (self = [super initWithFrame:frame]) { 
    // Initialization code 
    strokeColour = fill; 
    fillColour = handFill; 
    strokeWidth = width; 
    clockRadius = radius; 
    clockTime = time; 
    clockCentre.x = frame.size.width/2; 
    clockCentre.y = frame.size.height/2; 

    } 
    return self; 
} 

- (void)drawRect:(CGRect)rect { 

    double red, green, blue, alpha; 

    CGRect circleRect; 
    circleRect.origin.x = rect.origin.x+strokeWidth; 
    circleRect.origin.y = rect.origin.y+strokeWidth; 
    circleRect.size.width = rect.size.width - (strokeWidth*2); 
    circleRect.size.height = rect.size.height - (strokeWidth*2); 
    CGContextRef contextRef = UIGraphicsGetCurrentContext(); 

    CGContextSetLineWidth(contextRef, strokeWidth); 

    [fillColour getRed:&red green:&green blue:&blue alpha:&alpha]; 
    CGContextSetRGBFillColor(contextRef, red, green, blue, alpha); 

    [strokeColour getRed:&red green:&green blue:&blue alpha:&alpha]; 
    CGContextSetRGBStrokeColor(contextRef, red, green, blue, alpha); 

    CGContextFillEllipseInRect(contextRef, circleRect); 

    CGContextStrokeEllipseInRect(contextRef, circleRect); 

    CGContextSetLineWidth(contextRef, strokeWidth); 

    [strokeColour getRed:&red green:&green blue:&blue alpha:&alpha]; 
    CGContextSetRGBStrokeColor(contextRef, red, green, blue, alpha); 

    float hourAngle, minuteAngle, secondAngle, angle; 
    double endX, endY; 

    NSCalendar *cal = [[NSCalendar alloc]initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; 
    NSUInteger units = NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond; 
    NSDateComponents *components = [cal components:units fromDate:clockTime]; 
    hourAngle = (components.hour /12.0) * M_PI * 2.0; 
    minuteAngle = (components.minute/60.0) * M_PI * 2.0; 
    secondAngle = (components.second/60.0) * M_PI * 2.0; 

    //minute hand 
    angle = minuteAngle; 
    endX = cos(angle) * (clockRadius*0.85) + clockCentre.x; 
    endY = sin(angle) * (clockRadius*0.85) + clockCentre.y; 
    CGContextMoveToPoint(contextRef,clockCentre.x,clockCentre.y); 
    CGContextAddLineToPoint(contextRef,endX,endY); 
    CGContextStrokePath(contextRef); 

    //hour hand 
    angle = hourAngle; 
    endX = cos(angle) * (clockRadius*0.65) + clockCentre.x; 
    endY = sin(angle) * (clockRadius*0.65) + clockCentre.y; 
    CGContextSetLineWidth(contextRef, strokeWidth*1.5); 
    CGContextMoveToPoint(contextRef,clockCentre.x,clockCentre.y); 
    CGContextAddLineToPoint(contextRef,endX,endY); 
    CGContextStrokePath(contextRef); 
} 

@end 

@interface ViewController() 

@end 

@implementation ViewController 

- (UIView*)drawClockFaceWithCentre:(CGPoint)centre 
          radius:(float)radius 
           time:(NSDate*)time 
          colour:(UIColor*)colour 
        backgroundColour:(UIColor*)bgcolour { 

    UIView* clock = [[Clock alloc]initWithCentre:centre 
              radius:radius 
            borderWidth:6.0 
             facecolour:bgcolour 
             handcolour:colour 
              time:time]; 

    clock.backgroundColor = [UIColor clearColor]; 
    return clock; 
} 

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    // Do any additional setup after loading the view, typically from a nib. 

    CGPoint centre; 
    centre.x=200; 
    centre.y=200; 

    [self.view addSubview:[self drawClockFaceWithCentre:centre 
               radius:100 
                time:[NSDate date] 
               colour:[UIColor blackColor] 
             backgroundColour:[UIColor whiteColor]]]; 
} 

- (void)didReceiveMemoryWarning { 
    [super didReceiveMemoryWarning]; 
    // Dispose of any resources that can be recreated. 
} 

@end 

我敢肯定,這是很簡單的東西,我做錯了 - 在我的數學是錯誤的。任何人都可以看到這個錯誤(並且任何其他可以進行改進的建議都會受到歡迎,但要記住(當然),這只是一個簡單的測試工具)。

+0

考慮使用CAShapeLayer作爲鍾針(每個針對一個)並將它們存儲爲變量。然後只是變換旋轉他們 – Kegluneq 2015-04-01 09:05:23

+0

這不會解決問題,但它?因爲我仍然需要旋轉它們 - 這是我的旋轉問題。角度錯了。 – headbanger 2015-04-01 10:17:34

+0

不,但它會使代碼更具可讀性,更易於維護和更輕鬆地進行計算(而不是三角函數,在這種情況下,只需要獲得正確的2pi百分比即可輕鬆搞定錯誤)。 – Kegluneq 2015-04-01 10:42:15

回答

2

正如我在評論中寫的,考慮放下drawRect中的所有內容並使用圖層。另外,不要計算三角函數來繪製正確的路徑,而應考慮在12:00處繪製雙手並以正確的角度旋轉它們。你可以不喜歡這樣的初始化...

CAShapeLayer *faceLayer = [CAShapeLayer layer]; 
faceLayer.frame = self.bounds; 
faceLayer.fillColor = [UIColor whiteColor].CGColor; 
faceLayer.strokeColor = [UIColor blackColor].CGColor; 
faceLayer.path = [UIBezierPath bezierPathWithOvalInRect:faceLayer.bounds].CGPath; 
faceLayer.lineWidth = 3.0; 
[self.layer addSublayer:faceLayer]; 

CGPoint middle = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds)); 

NSCalendar *cal = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; 
NSUInteger units = NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond; 
NSDateComponents *components = [cal components:units fromDate:time]; 

UIBezierPath *path = [UIBezierPath bezierPath]; 
[path moveToPoint:middle]; 
[path addLineToPoint:CGPointMake(middle.x, middle.y-radius*0.5)]; 

CGFloat hourAreaAngle = (2*M_PI)/12.0; 
CAShapeLayer *hourLayer = [CAShapeLayer layer]; 
hourLayer.frame = self.bounds; 
hourLayer.strokeColor = [UIColor redColor].CGColor; 
hourLayer.lineWidth = 3.0; 
hourLayer.path = path.CGPath; 
[self.layer addSublayer:hourLayer]; 
hourLayer.transform = CATransform3DMakeRotation((components.hour/12.0*(M_PI*2.0))+(hourAreaAngle*(components.minute/60.0)), 0.0, 0.0, 1.0); 

[path removeAllPoints]; 
[path moveToPoint:middle]; 
[path addLineToPoint:CGPointMake(middle.x, middle.y-radius*0.8)]; 

CAShapeLayer *minuteLayer = [CAShapeLayer layer]; 
minuteLayer.frame = self.bounds; 
minuteLayer.strokeColor = [UIColor blueColor].CGColor; 
minuteLayer.lineWidth = 2.0; 
minuteLayer.path = path.CGPath; 
[self.layer addSublayer:minuteLayer]; 
minuteLayer.transform = CATransform3DMakeRotation(components.minute/60.0*(M_PI*2.0), 0.0, 0.0, 1.0); 

[path removeAllPoints]; 
[path moveToPoint:middle]; 
[path addLineToPoint:CGPointMake(middle.x, middle.y-radius)]; 

CAShapeLayer *secondsLayer = [CAShapeLayer layer]; 
secondsLayer.frame = self.bounds; 
secondsLayer.strokeColor = [UIColor greenColor].CGColor; 
secondsLayer.lineWidth = 1.0; 
secondsLayer.path = path.CGPath; 
[self.layer addSublayer:secondsLayer]; 
secondsLayer.transform = CATransform3DMakeRotation(components.second/60.0*(M_PI*2.0), 0.0, 0.0, 1.0); 

注意,我把我的顏色和線條寬度,因爲我很懶,不想來檢查你的代碼:P。

如果您想稍後更新指針,只需將指針圖層作爲變量存儲並轉換爲再次旋轉(只需記住先轉換爲標識!)。