2012-05-02 33 views
8

Tôi đang cố gắng triển khai thanh trượt tùy chỉnh như minh họa trong hình bên dưới.vẽ hình vòng cung dập nổi bằng đồ họa lõi

enter image description here

những gì tôi đã làm cho đến nay trông giống như sau

enter image description here

hãy giúp tôi ra để vẽ vòng cung với hiệu ứng như vậy. mã của tôi là như dưới đây, những gì tôi đang làm là vẽ vòng cung bằng cách sử dụng CGContextAddArc với chiều rộng dòng kLineWidth.

- (void)drawThumbAtPoint:(CGPoint)sliderButtonCenterPoint inContext: (CGContextRef)context { 
UIGraphicsPushContext(context); 
CGContextBeginPath(context); 

CGContextMoveToPoint(context, sliderButtonCenterPoint.x, sliderButtonCenterPoint.y); 

CGImageRef imageRef = [UIImage imageNamed:@"circle25.png"].CGImage; 
CGRect rect = CGRectMake(sliderButtonCenterPoint.x - kThumbRadius, sliderButtonCenterPoint.y - kThumbRadius, kThumbRadius*2, kThumbRadius*2); 
CGContextDrawImage(context, rect, imageRef); 

//CGContextAddArc(context, sliderButtonCenterPoint.x, sliderButtonCenterPoint.y, kThumbRadius, 0.0, 2*M_PI, NO); 

CGContextFillPath(context); 
UIGraphicsPopContext(); 
} 

- (CGPoint)drawArcTrack:(float)track atPoint:(CGPoint)center withRadius:(CGFloat)radius inContext:(CGContextRef)context { 
UIGraphicsPushContext(context); 
CGContextBeginPath(context); 

float angleFromTrack = translateValueFromSourceIntervalToDestinationInterval(track, self.minimumValue, self.maximumValue, 0, M_PI/3);// 2*M_PI 

CGFloat startAngle = (4*M_PI)/3; 
CGFloat endAngle = startAngle + angleFromTrack; 

CGContextAddArc(context, center.x, center.y, radius, startAngle, endAngle, NO); 

CGPoint arcEndPoint = CGContextGetPathCurrentPoint(context); 

CGContextStrokePath(context); 

UIGraphicsPopContext(); 

return arcEndPoint; 
} 

- (void)drawRect:(CGRect)rect { 
    CGContextRef context = UIGraphicsGetCurrentContext(); 

    CGPoint middlePoint; 
    middlePoint.x = self.bounds.origin.x + self.bounds.size.width/2; 
middlePoint.y = self.bounds.origin.y + self.bounds.size.width; 

CGContextSetLineWidth(context, kLineWidth); 

CGFloat radius = [self sliderRadius]; 


[self.maximumTrackTintColor setStroke];   
[self drawArcTrack:self.maximumValue atPoint:middlePoint withRadius:radius inContext:context];   
[self.minimumTrackTintColor setStroke];   
self.thumbCenterPoint = [self drawArcTrack:self.value atPoint:middlePoint withRadius:radius inContext:context];  

[self.thumbTintColor setFill]; 
[self drawThumbAtPoint:self.thumbCenterPoint inContext:context]; 
} 

Trả lời

23

Trừ khi bạn sắp thay đổi hình dạng động, có thể bạn nên tạo hình ảnh trong trình chỉnh sửa hình ảnh. Tôi biết thật dễ dàng để tạo hiệu ứng đó trong Photoshop, Illustrator hoặc Fireworks.

Điều đó nói rằng, vẽ một inner shadow như thế với Core Graphics đòi hỏi một số bước:

  1. Clip với hình dạng (ví dụ sử dụng CGContextClip hoặc CGContextClipToMask).
  2. Tạo đường dẫn hoặc mặt nạ của mọi thứ nhưng hình dạng.
  3. Đặt thông số bóng của bạn (sử dụng CGContextSetShadowWithColor).
  4. Điền đường dẫn hoặc mặt nạ từ bước 2. Đây đã phủ bóng đen bên trong hình dạng, và chỉ cái bóng được rút ra bởi vì bạn gài vào hình dạng trong bước 1.

Nếu bạn làm tất cả điều đó một cách chính xác, bạn có thể có được một kết quả tốt đẹp như thế này:

screen shot of arc with inner shadow

Dưới đây là đoạn code tôi đã viết để vẽ đó. Tôi đã viết nó trong drawRect: của một lớp con xem tùy chỉnh, nhưng bạn có thể dễ dàng sử dụng mã này để vẽ vào bất kỳ ngữ cảnh đồ họa nào.

- (void)drawRect:(CGRect)rect { 
    CGContextRef gc = UIGraphicsGetCurrentContext(); 

Trước tiên, tôi tạo ra một con đường đó chỉ là một vòng cung:

static CGFloat const kArcThickness = 20.0f; 
    CGRect arcBounds = CGRectInset(self.bounds, 10.0f, 10.0f); 
    CGPoint arcCenter = CGPointMake(CGRectGetMidX(arcBounds), CGRectGetMidY(arcBounds)); 
    CGFloat arcRadius = 0.5f * (MIN(arcBounds.size.width, arcBounds.size.height) - kArcThickness); 
    UIBezierPath *arc = [UIBezierPath bezierPathWithArcCenter:arcCenter radius:arcRadius startAngle:-M_PI/3.0 endAngle:-2.0 * M_PI/3.0 clockwise:NO]; 

Tiếp theo, tôi hỏi Lõi đồ họa để tạo ra một con đường mới đó là phác thảo của con đường arc. Lưu ý làm thế nào tôi hỏi nó cho một bề dày nét của kArcThickness và vòng mũ dòng:

CGPathRef shape = CGPathCreateCopyByStrokingPath(arc.CGPath, NULL, kArcThickness, kCGLineCapRound, kCGLineJoinRound, 10.0f); 

Tôi cũng cần nghịch đảo của con đường đó: một con đường mà bao gồm tất cả các điểm trừ các điểm trong shape. Nó sẽ xảy ra (mặc dù tôi không nghĩ rằng nó được ghi lại) rằng CGContextCreateCopyByStrokingPathCGPathAddRect vẽ theo các hướng ngược nhau. Vì vậy, nếu tôi sao chép shape và vẽ một hình chữ nhật khổng lồ xung quanh nó, những khác không quanh co cai trị có nghĩa là con đường mới sẽ là nghịch đảo của shape:

CGMutablePathRef shapeInverse = CGPathCreateMutableCopy(shape); 
    CGPathAddRect(shapeInverse, NULL, CGRectInfinite); 

Bây giờ tôi thực sự có thể bắt đầu vẽ.Trước tiên, tôi sẽ điền vào hình dạng với màu xám nhạt:

CGContextBeginPath(gc); 
    CGContextAddPath(gc, shape); 
    CGContextSetFillColorWithColor(gc, [UIColor colorWithWhite:.9 alpha:1].CGColor); 
    CGContextFillPath(gc); 

Tiếp theo tôi thực sự thực hiện bốn bước tôi liệt kê ở trên. Tôi phải lưu trạng thái đồ họa để tôi có thể hoàn tác các thông số clipping và shadow khi hoàn thành.

CGContextSaveGState(gc); { 

Bước 1: clip vào hình dạng:

 CGContextBeginPath(gc); 
     CGContextAddPath(gc, shape); 
     CGContextClip(gc); 

Bước 2: Vâng, tôi đã làm bước này đã khi tôi tạo shapeInverse.

Bước 3: Tôi thiết lập các thông số bóng:

 CGContextSetShadowWithColor(gc, CGSizeZero, 7, [UIColor colorWithWhite:0 alpha:.25].CGColor); 

Bước 4: Tôi điền vào hình dạng nghịch đảo từ bước 2:

 CGContextBeginPath(gc); 
     CGContextAddPath(gc, shapeInverse); 
     CGContextFillPath(gc); 

Bây giờ tôi khôi phục lại trạng thái đồ họa, mà đặc biệt là phục hồi lại cắt đường dẫn và bỏ các thông số bóng.

} CGContextRestoreGState(gc); 

Cuối cùng, tôi sẽ đột quỵ shape với một màu xám nhạt để làm cho crisper cạnh:

CGContextSetStrokeColorWithColor(gc, [UIColor colorWithWhite:.75 alpha:1].CGColor); 
    CGContextSetLineWidth(gc, 1); 
    CGContextSetLineJoin(gc, kCGLineCapRound); 
    CGContextBeginPath(gc); 
    CGContextAddPath(gc, shape); 
    CGContextStrokePath(gc); 

Tất nhiên là tôi dọn dẹp khi tôi đang thực hiện:

CGPathRelease(shape); 
    CGPathRelease(shapeInverse); 
} 

Đối hình dạng phức tạp hơn, bạn có thể xem my answer heremy answer here.

Dưới đây là tất cả các mã cùng nhau để dễ dàng sao chép:

- (void)drawRect:(CGRect)rect { 
    CGContextRef gc = UIGraphicsGetCurrentContext(); 

    static CGFloat const kArcThickness = 20.0f; 
    CGRect arcBounds = CGRectInset(self.bounds, 10.0f, 10.0f); 
    CGPoint arcCenter = CGPointMake(CGRectGetMidX(arcBounds), CGRectGetMidY(arcBounds)); 
    CGFloat arcRadius = 0.5f * (MIN(arcBounds.size.width, arcBounds.size.height) - kArcThickness); 
    UIBezierPath *arc = [UIBezierPath bezierPathWithArcCenter:arcCenter radius:arcRadius startAngle:-M_PI/3.0 endAngle:-2.0 * M_PI/3.0 clockwise:NO]; 
    CGPathRef shape = CGPathCreateCopyByStrokingPath(arc.CGPath, NULL, kArcThickness, kCGLineCapRound, kCGLineJoinRound, 10.0f); 
    CGMutablePathRef shapeInverse = CGPathCreateMutableCopy(shape); 
    CGPathAddRect(shapeInverse, NULL, CGRectInfinite); 

    CGContextBeginPath(gc); 
    CGContextAddPath(gc, shape); 
    CGContextSetFillColorWithColor(gc, [UIColor colorWithWhite:.9 alpha:1].CGColor); 
    CGContextFillPath(gc); 

    CGContextSaveGState(gc); { 
     CGContextBeginPath(gc); 
     CGContextAddPath(gc, shape); 
     CGContextClip(gc); 
     CGContextSetShadowWithColor(gc, CGSizeZero, 7, [UIColor colorWithWhite:0 alpha:.25].CGColor); 
     CGContextBeginPath(gc); 
     CGContextAddPath(gc, shapeInverse); 
     CGContextFillPath(gc); 
    } CGContextRestoreGState(gc); 

    CGContextSetStrokeColorWithColor(gc, [UIColor colorWithWhite:.75 alpha:1].CGColor); 
    CGContextSetLineWidth(gc, 1); 
    CGContextSetLineJoin(gc, kCGLineCapRound); 
    CGContextBeginPath(gc); 
    CGContextAddPath(gc, shape); 
    CGContextStrokePath(gc); 

    CGPathRelease(shape); 
    CGPathRelease(shapeInverse); 
} 
+0

Cảm ơn Rob cho mã này, nó đã thực sự hữu ích .. – Shashank

+0

Làm việc tuyệt vời! Cảm ơn rất nhiều. Một điều tôi cần làm là đặt self.backgroundColor để xóa trong lớp con uiview tùy chỉnh có ma thuật drawRect đó. – Chris

+0

@Shashank bạn có thể di chuyển thanh trượt đó qua đường dẫn đó không? Bạn có thể vui lòng chia sẻ mã của bạn không? – NSCry

2

kiểm tra mã dưới đây để biết phiên bản đầy đủ chức năng của các thành phần trên, làm việc của nó (có thể hơi lộn xộn của nó).

#import "UIArcSlider.h" 

@interface UIArcSlider() 

@property (nonatomic) CGPoint thumbCenterPoint; 

#pragma mark - Init and Setup methods 
- (void)setup; 

#pragma mark - Thumb management methods 
- (BOOL)isPointInThumb:(CGPoint)point; 

#pragma mark - Drawing methods 
- (CGFloat)sliderRadius; 
- (void)drawThumbAtPoint:(CGPoint)sliderButtonCenterPoint inContext:(CGContextRef)context; 
- (CGPoint)drawTheArcTrack:(float)track atPoint:(CGPoint)center withRadius:(CGFloat)radius AndColor:(Boolean) isWhite inContext:(CGContextRef)context; 
- (CGPoint)drawTheLineTrack:(float)track withColor:(Boolean) isWhite inContext:(CGContextRef)context; 

@end 

#pragma mark - 
@implementation UIArcSlider 

@synthesize sliderStyle = _sliderStyle; 
- (void)setSliderStyle:(UISliderStyle)sliderStyle { 
    if (sliderStyle != _sliderStyle) { 
     _sliderStyle = sliderStyle; 
     [self setNeedsDisplay]; 
    } 
} 

@synthesize value = _value; 
- (void)setValue:(float)value { 
    if (value != _value) { 
     if (value > self.maximumValue) { value = self.maximumValue; } 
     if (value < self.minimumValue) { value = self.minimumValue; } 
     _value = value; 
     [self setNeedsDisplay]; 
     [self sendActionsForControlEvents:UIControlEventValueChanged]; 
    } 
} 
@synthesize minimumValue = _minimumValue; 
- (void)setMinimumValue:(float)minimumValue { 
    if (minimumValue != _minimumValue) { 
     _minimumValue = minimumValue; 
     if (self.maximumValue < self.minimumValue) { self.maximumValue = self.minimumValue; } 
     if (self.value < self.minimumValue)   { self.value = self.minimumValue; } 
    } 
} 
@synthesize maximumValue = _maximumValue; 
- (void)setMaximumValue:(float)maximumValue { 
    if (maximumValue != _maximumValue) { 
     _maximumValue = maximumValue; 
     if (self.minimumValue > self.maximumValue) { self.minimumValue = self.maximumValue; } 
     if (self.value > self.maximumValue)   { self.value = self.maximumValue; } 
    } 
} 

@synthesize thumbCenterPoint = _thumbCenterPoint; 

/** @name Init and Setup methods */ 
#pragma mark - Init and Setup methods 
- (id)initWithFrame:(CGRect)frame { 
    self = [super initWithFrame:frame]; 
    if (self) { 
     [self setup]; 
    } 
    return self; 
} 
- (void)awakeFromNib { 
    [self setup]; 
} 

- (void)setup { 
    self.value = 0.0; 
    self.minimumValue = 0.0; 
    self.maximumValue = 100.0; 
    self.thumbCenterPoint = CGPointZero; 

    UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureHappened:)]; 
    [self addGestureRecognizer:tapGestureRecognizer]; 

    UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureHappened:)]; 
    panGestureRecognizer.maximumNumberOfTouches = panGestureRecognizer.minimumNumberOfTouches; 
    [self addGestureRecognizer:panGestureRecognizer]; 
} 

/** @name Drawing methods */ 
#pragma mark - Drawing methods 
#define kLineWidth 22.0 
#define kThumbRadius 20.0 
#define kPadding 20.0 

- (CGFloat)sliderRadius { 
    CGFloat radius = self.bounds.size.width; 
    radius -= MAX(kLineWidth + kPadding, kThumbRadius + kPadding); 
    return radius; 
} 

-(CGFloat)sliderWidth {  
    return self.bounds.size.width - kThumbRadius*2; 
} 

- (void)drawThumbAtPoint:(CGPoint)sliderButtonCenterPoint inContext:(CGContextRef)context { 
    UIGraphicsPushContext(context); 
    CGContextBeginPath(context);  

    CGContextMoveToPoint(context, sliderButtonCenterPoint.x, sliderButtonCenterPoint.y); 

    CGRect rect = CGRectMake(sliderButtonCenterPoint.x - kThumbRadius, sliderButtonCenterPoint.y - kThumbRadius, kThumbRadius*2, kThumbRadius*2); 
    CGImageRef imageRef = [UIImage imageNamed:@"circle25.png"].CGImage; 

    CGContextDrawImage(context, rect, imageRef); 

    UIGraphicsPopContext();   
} 

- (CGPoint)drawTheArcTrack:(float)track atPoint:(CGPoint)center withRadius:(CGFloat)radius AndColor:(Boolean) isWhite inContext:(CGContextRef)context 
{ 
    static CGFloat const kArcThickness = kLineWidth; 
    CGPoint arcCenter = center; 
    CGFloat arcRadius = radius; 

    float angleFromTrack = translateValueFromSourceIntervalToDestinationInterval(track, self.minimumValue, self.maximumValue, 0, M_PI/3);// 2*M_PI 

    CGFloat startAngle = (4*M_PI)/3; 
    CGFloat endAngle = startAngle + angleFromTrack; 

    UIBezierPath *arc = [UIBezierPath bezierPathWithArcCenter:arcCenter radius:arcRadius startAngle:startAngle endAngle:endAngle clockwise:YES]; 

    CGPathRef shape = CGPathCreateCopyByStrokingPath(arc.CGPath, NULL, kArcThickness, kCGLineCapRound, kCGLineJoinRound, 10.0f); 
    CGMutablePathRef shapeInverse = CGPathCreateMutableCopy(shape); 
    CGPathAddRect(shapeInverse, NULL, CGRectInfinite); 

    CGPoint arcEndPoint = [arc currentPoint]; 

    CGContextBeginPath(context); 
    CGContextAddPath(context, shape); 

    if (isWhite) { 
     CGContextSetFillColorWithColor(context, [UIColor colorWithWhite:.9 alpha:1].CGColor); 
    } else {//70,172, 220 
     CGContextSetFillColorWithColor(context, [UIColor colorWithRed:70/255.0 green:172/255.0 blue:220/255.0 alpha:1].CGColor); 
    }  

    CGContextFillPath(context); 

    CGContextSaveGState(context); { 
     CGContextBeginPath(context); 
     CGContextAddPath(context, shape); 
     CGContextClip(context); 
     if (isWhite) { 
      CGContextSetShadowWithColor(context, CGSizeZero, 7, [UIColor colorWithWhite:0 alpha:.25].CGColor); 
     } else { 
      CGContextSetShadowWithColor(context, CGSizeZero, 7, [UIColor colorWithRed:85/255.0 green:183/255.0 blue:230/255.0 alpha:.25].CGColor); 
     }  
     CGContextBeginPath(context); 
     CGContextAddPath(context, shapeInverse); 
     CGContextFillPath(context); 
    } CGContextRestoreGState(context); 

    if (isWhite) { 
     CGContextSetStrokeColorWithColor(context, [UIColor colorWithWhite:.75 alpha:1].CGColor); 
    } else { 
     CGContextSetStrokeColorWithColor(context, [UIColor colorWithRed:62/255.0 green:135/255.0 blue:169/255.0 alpha:1].CGColor); 
    } 

    CGContextSetLineWidth(context, 1); 
    CGContextSetLineJoin(context, kCGLineCapRound); 
    CGContextBeginPath(context); 
    CGContextAddPath(context, shape); 
    CGContextStrokePath(context); 

    CGPathRelease(shape); 
    CGPathRelease(shapeInverse);   

    return arcEndPoint;  
} 


- (CGPoint)drawTheLineTrack:(float)track withColor:(Boolean) isWhite inContext:(CGContextRef)context 
{   
    CGFloat sliderWidth = [self sliderWidth]; 
    CGFloat xStart = self.bounds.origin.x + (self.bounds.size.width - sliderWidth)/2; 
    CGFloat lineRectX = (self.bounds.size.width - sliderWidth)/2; 
    CGFloat lineThickness = kLineWidth/2; 
    CGFloat lineRectY = (self.bounds.size.height - lineThickness)/2; 

    CGFloat xPoint = translateValueToPoint(track, xStart, self.maximumValue, sliderWidth); 
    sliderWidth = xPoint; 

    CGRect lineRect = CGRectMake(lineRectX, lineRectY, sliderWidth, lineThickness); 
    UIBezierPath *line = [UIBezierPath bezierPathWithRoundedRect:lineRect cornerRadius:lineThickness/2]; 

    CGPathRef shape = CGPathCreateCopyByStrokingPath(line.CGPath, NULL, lineThickness, kCGLineCapRound, kCGLineJoinRound, 10.0f); 
    CGMutablePathRef shapeInverse = CGPathCreateMutableCopy(shape); 
    CGPathAddRect(shapeInverse, NULL, CGRectInfinite); 

    CGPoint arcEndPoint = CGPointMake(lineRectX + xPoint, lineRectY + (lineThickness/2)); 

    CGContextBeginPath(context); 
    CGContextAddPath(context, shape); 

    if (isWhite) { 
     CGContextSetFillColorWithColor(context, [UIColor colorWithWhite:.9 alpha:1].CGColor); 
    } else {//70,172, 220 
     CGContextSetFillColorWithColor(context, [UIColor colorWithRed:70/255.0 green:172/255.0 blue:220/255.0 alpha:1].CGColor); 
    }  

    CGContextFillPath(context); 

    CGContextSaveGState(context); { 
     CGContextBeginPath(context); 
     CGContextAddPath(context, shape); 
     CGContextClip(context); 
     if (isWhite) { 
      CGContextSetShadowWithColor(context, CGSizeZero, 7, [UIColor colorWithWhite:0 alpha:.25].CGColor); 
     } else { 
      CGContextSetShadowWithColor(context, CGSizeZero, 7, [UIColor colorWithRed:85/255.0 green:183/255.0 blue:230/255.0 alpha:.25].CGColor); 
     }  
     CGContextBeginPath(context); 
     CGContextAddPath(context, shapeInverse); 
     CGContextFillPath(context); 
    } CGContextRestoreGState(context); 

    if (isWhite) { 
     CGContextSetStrokeColorWithColor(context, [UIColor colorWithWhite:.75 alpha:1].CGColor); 
    } else { 
     CGContextSetStrokeColorWithColor(context, [UIColor colorWithRed:62/255.0 green:135/255.0 blue:169/255.0 alpha:1].CGColor); 
    } 

    CGRect outlineRect = CGRectMake(lineRectX - (lineThickness/2), lineRectY - (lineThickness/2), sliderWidth + lineThickness, lineThickness * 2); 
    UIBezierPath *outline = [UIBezierPath bezierPathWithRoundedRect:outlineRect cornerRadius:lineThickness]; 
    CGContextSetLineWidth(context, 1); 
    CGContextSetLineJoin(context, kCGLineCapSquare); 
    CGContextBeginPath(context); 
    CGContextAddPath(context, outline.CGPath); 
    CGContextStrokePath(context); 

    CGPathRelease(shape); 
    CGPathRelease(shapeInverse);   

    return arcEndPoint;  
} 

- (void)drawRect:(CGRect)rect { 
    CGContextRef context = UIGraphicsGetCurrentContext(); 
    CGPoint middlePoint; 

    switch (self.sliderStyle) { 
     case UISliderStyleLine: 

      [self drawTheLineTrack:self.maximumValue withColor:YES inContext:context]; 
      self.thumbCenterPoint = [self drawTheLineTrack:self.value withColor:NO inContext:context]; 

      [self drawThumbAtPoint:self.thumbCenterPoint inContext:context]; 
      break; 

     case UISliderStyleArc: 
     default: 
      middlePoint.x = self.bounds.origin.x + self.bounds.size.width/2; 
      middlePoint.y = self.bounds.origin.y + self.bounds.size.width; 

      CGFloat radius = [self sliderRadius];     
      [self drawTheArcTrack:self.maximumValue atPoint:middlePoint withRadius:radius AndColor:YES inContext:context]; 

      self.thumbCenterPoint = [self drawTheArcTrack:self.value atPoint:middlePoint withRadius:radius AndColor:NO inContext:context]; 

      [self drawThumbAtPoint:self.thumbCenterPoint inContext:context]; 
      break; 
    } 
} 

/** @name Thumb management methods */ 
#pragma mark - Thumb management methods 
- (BOOL)isPointInThumb:(CGPoint)point { 
    CGRect thumbTouchRect = CGRectMake(self.thumbCenterPoint.x - kThumbRadius, self.thumbCenterPoint.y - kThumbRadius, kThumbRadius*2, kThumbRadius*2); 
    return CGRectContainsPoint(thumbTouchRect, point); 
} 

/** @name UIGestureRecognizer management methods */ 
#pragma mark - UIGestureRecognizer management methods 
- (void)panGestureHappened:(UIPanGestureRecognizer *)panGestureRecognizer { 
    CGPoint tapLocation = [panGestureRecognizer locationInView:self]; 
    switch (panGestureRecognizer.state) { 
     case UIGestureRecognizerStateChanged: { 

      CGFloat radius; 
      CGPoint sliderCenter; 
      CGPoint sliderStartPoint; 
      CGFloat angle; 


      CGFloat xStart; 
      CGFloat maximumValue; 
      CGFloat sliderWidth; 
      CGFloat point; 

      switch (self.sliderStyle) { 
       case UISliderStyleLine: 

        sliderWidth = [self sliderWidth]; 
        xStart = self.bounds.origin.x + (self.bounds.size.width - sliderWidth)/2; 
        maximumValue = self.maximumValue; 
        point = tapLocation.x; 

        self.value = translatePointToValue(point, xStart, maximumValue, sliderWidth); 

        break; 

       case UISliderStyleArc: 
       default: 

        radius = [self sliderRadius]; 
        sliderCenter = CGPointMake(self.bounds.size.width/2, self.bounds.size.width); 
        sliderStartPoint = CGPointMake(sliderCenter.x - (radius * 1.15), sliderCenter.y - (radius * 2.1)); 
        angle = angleBetweenThreePoints(sliderCenter, sliderStartPoint, tapLocation); 

        if (angle < 0) { 
         angle = -angle; 
        } 
        else { 
         angle = 0.0; 
         //angle = M_PI/3 - angle; 
        } 

        self.value = translateValueFromSourceIntervalToDestinationInterval(angle, 0, M_PI/3, self.minimumValue, self.maximumValue); 
        break; 
      } 
     } 
     default: 
      break; 
    } 
} 
- (void)tapGestureHappened:(UITapGestureRecognizer *)tapGestureRecognizer { 
    if (tapGestureRecognizer.state == UIGestureRecognizerStateEnded) { 
     CGPoint tapLocation = [tapGestureRecognizer locationInView:self]; 
     if ([self isPointInThumb:tapLocation]) { 
      // do something on tap 
     } 
     else { 
     } 
    } 
} 

@end 

/** @name Utility Functions */ 
#pragma mark - Utility Functions 
float translateValueFromSourceIntervalToDestinationInterval(float sourceValue, float sourceIntervalMinimum, float sourceIntervalMaximum, float destinationIntervalMinimum, float destinationIntervalMaximum) { 
    float a, b, destinationValue; 

    a = (destinationIntervalMaximum - destinationIntervalMinimum)/(sourceIntervalMaximum - sourceIntervalMinimum); 
    b = destinationIntervalMaximum - a*sourceIntervalMaximum; 

    destinationValue = a*sourceValue + b; 

    return destinationValue; 
} 

float translateValueToPoint(float value, float xStart, float maximum, float width) 
{ 
    float point = (width * value)/maximum; 
//  
// point = xStart + point; 
//  
    return point; 
} 

float translatePointToValue(float point, float xStart, float maximum, float width) 
{ 
    float value = (point) * maximum; 
    value = value/width; 

    return value; 
} 


CGFloat angleBetweenThreePoints(CGPoint centerPoint, CGPoint p1, CGPoint p2) { 
    CGPoint v1 = CGPointMake(p1.x - centerPoint.x, p1.y - centerPoint.y); 
    CGPoint v2 = CGPointMake(p2.x - centerPoint.x, p2.y - centerPoint.y); 

    CGFloat angle = atan2f(v2.x*v1.y - v1.x*v2.y, v1.x*v2.x + v1.y*v2.y); 

    return angle; 
} 

Bạn sẽ đòi hỏi hình ảnh ngón tay cái cũng enter image description here

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