不允许在 Circular Slider iOS 中从 1% 滑动到 100%,反之亦然
Posted
技术标签:
【中文标题】不允许在 Circular Slider iOS 中从 1% 滑动到 100%,反之亦然【英文标题】:Not allow slide from 1% to 100% and vice versa in Circular Slider iOS 【发布时间】:2014-12-25 17:05:08 【问题描述】:我正在使用这个类来创建一个圆形滑块,但是我有一个问题,当用户从 1% 滑到 100% 时,如何不允许,反之亦然?请帮我解决这个问题。提前致谢。
代码如下:
@interface SLCircularSlider()
@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)drawCircularTrack:(float)track atPoint:(CGPoint)point withRadius:(CGFloat)radius inContext:(CGContextRef)context;
- (CGPoint)drawPieTrack:(float)track atPoint:(CGPoint)point withRadius:(CGFloat)radius inContext:(CGContextRef)context;
@end
#pragma mark -
@implementation SLCircularSlider
@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];
if (self.isContinuous)
[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 minimumTrackTintColor = _minimumTrackTintColor;
- (void)setMinimumTrackTintColor:(UIColor *)minimumTrackTintColor
if (![minimumTrackTintColor isEqual:_minimumTrackTintColor])
_minimumTrackTintColor = minimumTrackTintColor;
[self setNeedsDisplay];
@synthesize maximumTrackTintColor = _maximumTrackTintColor;
- (void)setMaximumTrackTintColor:(UIColor *)maximumTrackTintColor
if (![maximumTrackTintColor isEqual:_maximumTrackTintColor])
_maximumTrackTintColor = maximumTrackTintColor;
[self setNeedsDisplay];
@synthesize thumbTintColor = _thumbTintColor;
- (void)setThumbTintColor:(UIColor *)thumbTintColor
if (![thumbTintColor isEqual:_thumbTintColor])
_thumbTintColor = thumbTintColor;
[self setNeedsDisplay];
@synthesize continuous = _continuous;
@synthesize sliderStyle = _sliderStyle;
- (void)setSliderStyle:(UICircularSliderStyle)sliderStyle
if (sliderStyle != _sliderStyle)
_sliderStyle = sliderStyle;
[self setNeedsDisplay];
@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 = 1.0;
/*self.minimumTrackTintColor = [UIColor blueColor];
self.maximumTrackTintColor = [UIColor whiteColor];
self.thumbTintColor = [UIColor darkGrayColor];*/
self.minimumTrackTintColor = [UIColor clearColor];
self.maximumTrackTintColor = [UIColor clearColor];
self.thumbTintColor = [UIColor clearColor];
self.continuous = YES;
self.thumbCenterPoint = CGPointZero;
/**
* This tapGesture isn't used yet but will allow to jump to a specific location in the circle
*/
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 5.0
#define kThumbRadius 12.0
- (CGFloat)sliderRadius
CGFloat radius = MIN(self.bounds.size.width/2, self.bounds.size.height/2);
radius -= MAX(kLineWidth, kThumbRadius);
return radius;
- (void)drawThumbAtPoint:(CGPoint)sliderButtonCenterPoint inContext:(CGContextRef)context
UIGraphicsPushContext(context);
CGContextBeginPath(context);
CGContextMoveToPoint(context, sliderButtonCenterPoint.x, sliderButtonCenterPoint.y);
CGContextAddArc(context, sliderButtonCenterPoint.x, sliderButtonCenterPoint.y, kThumbRadius, 0.0, 2*M_PI, NO);
CGContextFillPath(context);
UIGraphicsPopContext();
- (CGPoint)drawCircularTrack:(float)track atPoint:(CGPoint)center withRadius:(CGFloat)radius inContext:(CGContextRef)context
UIGraphicsPushContext(context);
CGContextBeginPath(context);
float angleFromTrack = translateValueFromSourceIntervalToDestinationInterval(track, self.minimumValue, self.maximumValue, 0, 2*M_PI);
CGFloat startAngle = -M_PI_2;
CGFloat endAngle = startAngle + angleFromTrack;
CGContextAddArc(context, center.x, center.y, radius, startAngle, endAngle, NO);
CGPoint arcEndPoint = CGContextGetPathCurrentPoint(context);
CGContextStrokePath(context);
UIGraphicsPopContext();
return arcEndPoint;
- (CGPoint)drawPieTrack:(float)track atPoint:(CGPoint)center withRadius:(CGFloat)radius inContext:(CGContextRef)context
UIGraphicsPushContext(context);
float angleFromTrack = translateValueFromSourceIntervalToDestinationInterval(track, self.minimumValue, self.maximumValue, 0, 2*M_PI);
CGFloat startAngle = -M_PI_2;
CGFloat endAngle = startAngle + angleFromTrack;
CGContextMoveToPoint(context, center.x, center.y);
CGContextAddArc(context, center.x, center.y, radius, startAngle, endAngle, NO);
CGPoint arcEndPoint = CGContextGetPathCurrentPoint(context);
CGContextClosePath(context);
CGContextFillPath(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.height/2;
CGContextSetLineWidth(context, kLineWidth);
CGFloat radius = [self sliderRadius];
switch (self.sliderStyle)
case UICircularSliderStylePie:
[self.maximumTrackTintColor setFill];
[self drawPieTrack:self.maximumValue atPoint:middlePoint withRadius:radius inContext:context];
[self.minimumTrackTintColor setStroke];
[self drawCircularTrack:self.maximumValue atPoint:middlePoint withRadius:radius inContext:context];
[self.minimumTrackTintColor setFill];
self.thumbCenterPoint = [self drawPieTrack:self.value atPoint:middlePoint withRadius:radius inContext:context];
break;
case UICircularSliderStyleCircle:
default:
[self.maximumTrackTintColor setStroke];
[self drawCircularTrack:self.maximumValue atPoint:middlePoint withRadius:radius inContext:context];
[self.minimumTrackTintColor setStroke];
self.thumbCenterPoint = [self drawCircularTrack:self.value atPoint:middlePoint withRadius:radius inContext:context];
break;
[self.thumbTintColor setFill];
[self drawThumbAtPoint:self.thumbCenterPoint inContext:context];
/** @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];
/* UILabel* percentlbl =(UILabel*) [self.superview viewWithTag:10];
NSLog(@"percentlbl frame %f",percentlbl.frame.origin.y
);
if (CGRectContainsPoint(percentlbl.frame, tapLocation))
NSLog(@"Tapped label");
*/
switch (panGestureRecognizer.state)
case UIGestureRecognizerStateChanged:
CGFloat radius = [self sliderRadius];
CGPoint sliderCenter = CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2);
CGPoint sliderStartPoint = CGPointMake(sliderCenter.x, sliderCenter.y - radius);
CGFloat angle = angleBetweenThreePoints(sliderCenter, sliderStartPoint, tapLocation);
if (angle < 0)
angle = -angle;
else
angle = 2*M_PI - angle;
self.value = translateValueFromSourceIntervalToDestinationInterval(angle, 0, 2*M_PI, self.minimumValue, self.maximumValue);
break;
case UIGestureRecognizerStateEnded:
if (!self.isContinuous)
[self sendActionsForControlEvents:UIControlEventValueChanged];
if ([self isPointInThumb:tapLocation])
[self sendActionsForControlEvents:UIControlEventTouchUpInside];
else
[self sendActionsForControlEvents:UIControlEventTouchUpOutside];
break;
default:
break;
- (void)tapGestureHappened:(UITapGestureRecognizer *)tapGestureRecognizer
if (tapGestureRecognizer.state == UIGestureRecognizerStateEnded)
CGPoint tapLocation = [tapGestureRecognizer locationInView:self];
if ([self isPointInThumb:tapLocation])
else
/** @name Touches Methods */
#pragma mark - Touches Methods
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
[super touchesBegan:touches withEvent:event];
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInView:self];
if ([self isPointInThumb:touchLocation])
[self sendActionsForControlEvents:UIControlEventTouchDown];
@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;
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;
【问题讨论】:
@synthesize
的用法很奇怪。
【参考方案1】:
您需要做的是在手势识别中添加一个阶段,您可以在其中确定用户是在增加还是减少计数器。如果减少,一旦值降至零以下,不要响应减少的变化(您可能希望能够达到零,而不是停止在 1,尽管问题说了什么?)。如果增加,一旦值达到 100%,不要响应增加的变化。当然,您需要确保在最大情况下,如果用户更改为减小值,并且在为零时增加值,您仍能继续响应。
【讨论】:
以上是关于不允许在 Circular Slider iOS 中从 1% 滑动到 100%,反之亦然的主要内容,如果未能解决你的问题,请参考以下文章
iOS 音频通话 APP 使用 Circular Buffer 的原因是啥?
iOS 设备中 Flutter TabBarView 覆盖底部区域(Slider)
Slider FileReader JS 多张图片上传(递增索引)