欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

IOS编程开发教程:ios双拉杆

程序员文章站 2022-06-16 12:28:00
IOS编程开发教程:ios双拉杆,有机会 我将 开源 android 同样的组件。 // // EFCircularSlider.m // Awake...
IOS编程开发教程:ios双拉杆,有机会 我将 开源 android 同样的组件。

//
//  EFCircularSlider.m
//  Awake
//
//  Created by Eliot Fowler on 12/3/13.
//  Copyright (c) 2013 Eliot Fowler. All rights reserved.
//

#import "EFCircularSlider.h"
#import 
#import 

#define ToRad(deg) 		( (M_PI * (deg)) / 180.0 )
#define ToDeg(rad)		( (180.0 * (rad)) / M_PI )
#define SQR(x)			( (x) * (x) )

@implementation EFCircularSlider {
    CGFloat radius;
    int angle1;
    int angle2;
    int fixedAngle;
    NSMutableDictionary* labelsWithPercents;
    NSArray* labelsEvenSpacing;
}

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Defaults
        _maximumValue = 100.0f;
        _minimumValue = 0.0f;
        _currentValue1 = 0.0f;
        _lineWidth = 55;
        _unfilledColor = [UIColor redColor];
        _filledColor1 = [UIColor redColor];
        _filledColor2 = [UIColor orangeColor];
        _handleColor = [UIColor whiteColor];
        _handleInColor1=_filledColor1;
        _handleInColor2=_filledColor2;
        _labelFont = [UIFont systemFontOfSize:10.0f];
        _snapToLabels = NO;
        _handleType = semiTransparentWhiteCircle;
        _labelColor = [UIColor redColor];
        
//        angle1=360 - (360-165) - 15;
//        _currentValue1=100;
//        _currentValue2=100;
//        angle2=360-(360-30)-150;
        
        angle1= 0;
        _currentValue1=0;
        _currentValue2=0;
        angle2=0;

        
        radius = self.frame.size.height/2 - _lineWidth/2;
        
        self.backgroundColor = [UIColor clearColor];
    }
    return self;
}

-(void)layoutSubviews{
    [super layoutSubviews];
    
    int totalAngle1 = 360 -165 +15;
    
    int currentAngle1 =0;
    
    float percentAngle1 = totalAngle1 * (_currentValue1/_maximumValue);
    if (percentAngle1<=(360-165)) {
        currentAngle1 = 165 + percentAngle1;
    }else{
        currentAngle1 = percentAngle1 - (360-165);
    }
    
    angle1 = 360 - (360-165) - currentAngle1;
    
    int totalAngle2 = 150-30;
    int currentAngle2=0;
    float percentAngle2 = totalAngle2 * (_currentValue2/_maximumValue);
    currentAngle2 = 30+percentAngle2;
    
    angle2=360-(360-30)-currentAngle2;
    

}

#pragma mark - drawing methods

- (void)drawRect:(CGRect)rect
{
    [super drawRect:rect];
    
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    
    //Draw the unfilled circle
//    CGContextAddArc(ctx, self.frame.size.width/2, self.frame.size.height/2, radius, 0, M_PI *2, 0);
    CGContextAddArc(ctx, self.frame.size.width/2  , self.frame.size.height/2, radius, 165*M_PI/180, ToRad(15), 0);
    [_unfilledColor setStroke];
    CGContextSetLineWidth(ctx, _lineWidth);
    CGContextSetLineCap(ctx, kCGLineCapButt);
    CGContextDrawPath(ctx, kCGPathStroke);
    
    CGContextAddArc(ctx, self.frame.size.width/2  , self.frame.size.height/2, radius, M_PI/6,M_PI/6-ToRad(-120), 0);
    [_unfilledColor setStroke];
    CGContextSetLineWidth(ctx, _lineWidth);
    CGContextSetLineCap(ctx, kCGLineCapButt);
    CGContextDrawPath(ctx, kCGPathStroke);
    
    //Draw the filled circle
//    if((_handleType == doubleCircleWithClosedCenter || _handleType == doubleCircleWithOpenCenter) && fixedAngle > 5) {
////        CGContextAddArc(ctx, self.frame.size.width/2  , self.frame.size.height/2, radius, 3*M_PI/2, 3*M_PI/2-ToRad(angle+3), 0);
//        CGContextAddArc(ctx, self.frame.size.width/2  , self.frame.size.height/2, radius, 165*M_PI/180, 165*M_PI/180-ToRad(angle1+3), 0);
//        [_filledColor setStroke];
//        CGContextSetLineWidth(ctx, _lineWidth);
//        CGContextSetLineCap(ctx, kCGLineCapButt);
//        CGContextDrawPath(ctx, kCGPathStroke);
//        CGContextAddArc(ctx, self.frame.size.width/2, self.frame.size.height/2, radius,  M_PI/6, M_PI/6-ToRad(angle2+3), 0);
//        [_filledColor setStroke];
//        CGContextSetLineWidth(ctx, _lineWidth);
//        CGContextSetLineCap(ctx, kCGLineCapButt);
//        CGContextDrawPath(ctx, kCGPathStroke);
//    } else {
//        CGContextAddArc(ctx, self.frame.size.width/2  , self.frame.size.height/2, radius, 3*M_PI/2, 3*M_PI/2-ToRad(angle), 0);
        CGContextAddArc(ctx, self.frame.size.width/2  , self.frame.size.height/2, radius, 165*M_PI/180, 165*M_PI/180-ToRad(angle1), 0);
        [_filledColor1 setStroke];
        CGContextSetLineWidth(ctx, _lineWidth);
        CGContextSetLineCap(ctx, kCGLineCapButt);
        CGContextDrawPath(ctx, kCGPathStroke);
        CGContextAddArc(ctx, self.frame.size.width/2, self.frame.size.height/2, radius,  M_PI/6, M_PI/6-ToRad(angle2), 0);
        [_filledColor2 setStroke];
        CGContextSetLineWidth(ctx, _lineWidth);
        CGContextSetLineCap(ctx, kCGLineCapButt);
        CGContextDrawPath(ctx, kCGPathStroke);
//    }
   
//    CGContextDrawPath(ctx, kCGPathStroke);
    
    //Add the labels (if necessary)
    if(labelsEvenSpacing != nil) {
        [self drawLabels:ctx];
    }
    
    //The draggable part
    [self drawHandle:ctx];
}

-(void) drawHandle:(CGContextRef)ctx{
    CGContextSaveGState(ctx);
    CGPoint handleCenter =  [self pointFromAngle1: angle1];
//    if(_handleType == semiTransparentWhiteCircle) {
//        [[UIColor colorWithWhite:1.0 alpha:0.7] set];
//        CGContextFillEllipseInRect(ctx, CGRectMake(handleCenter.x, handleCenter.y, _lineWidth, _lineWidth));
//    } else if(_handleType == semiTransparentBlackCircle) {
//        [[UIColor colorWithWhite:0.0 alpha:0.7] set];
//        CGContextFillEllipseInRect(ctx, CGRectMake(handleCenter.x, handleCenter.y, _lineWidth, _lineWidth));
//    } else if(_handleType == doubleCircleWithClosedCenter) {
//        [_handleColor set];
//        CGContextAddArc(ctx, handleCenter.x + (_lineWidth)/2, handleCenter.y + (_lineWidth)/2, _lineWidth, 0, M_PI *2, 0);
//        CGContextSetLineWidth(ctx, 7);
//        CGContextSetLineCap(ctx, kCGLineCapButt);
//        CGContextDrawPath(ctx, kCGPathStroke);
//        CGContextFillEllipseInRect(ctx, CGRectMake(handleCenter.x, handleCenter.y, _lineWidth-1, _lineWidth-1));
//    } else if(_handleType == doubleCircleWithOpenCenter) {
//        [_handleColor set];
//        CGContextAddArc(ctx, handleCenter.x + (_lineWidth)/2, handleCenter.y + (_lineWidth)/2, 8, 0, M_PI *2, 0);
//        CGContextSetLineWidth(ctx, 4);
//        CGContextSetLineCap(ctx, kCGLineCapButt);
//        CGContextDrawPath(ctx, kCGPathStroke);
//        
//        CGContextAddArc(ctx, handleCenter.x + _lineWidth/2, handleCenter.y + _lineWidth/2, _lineWidth/2, 0, M_PI *2, 0);
//        CGContextSetLineWidth(ctx, 2);
//        CGContextSetLineCap(ctx, kCGLineCapButt);
//        CGContextDrawPath(ctx, kCGPathStroke);
//    } else if(_handleType == bigCircle) {
//        [_handleColor set];
//        CGContextFillEllipseInRect(ctx, CGRectMake(handleCenter.x-2.5, handleCenter.y-2.5, _lineWidth+5, _lineWidth+5));
//    }
    
//    [_handleColor set];
//    CGContextFillEllipseInRect(ctx, CGRectMake(handleCenter.x-2.5, handleCenter.y-2.5, _lineWidth+5, _lineWidth+5));
//    [_handleInColor set];
    [_handleColor set];
    CGContextAddArc(ctx, handleCenter.x + (_lineWidth)/2, handleCenter.y + (_lineWidth)/2, 8, 0, M_PI *2, 0);
    CGContextSetLineWidth(ctx, 4);
    CGContextSetLineCap(ctx, kCGLineCapButt);
//    CGContextSetShadowWithColor(ctx, CGSizeMake(0, 0), _lineWidth/2, [UIColor blueColor].CGColor);
    CGContextDrawPath(ctx, kCGPathStroke);
    
   
    CGContextAddArc(ctx, handleCenter.x + _lineWidth/2, handleCenter.y + _lineWidth/2, _lineWidth/2, 0, M_PI *2, 0);
    [_handleInColor1 set];
//    [[UIColor redColor] set];
    CGContextSetLineWidth(ctx, 2);
    CGContextSetLineCap(ctx, kCGLineCapButt);
//    CGContextSetShadowWithColor(ctx, CGSizeMake(0, 0), _lineWidth, [UIColor blackColor].CGColor);
     CGContextFillEllipseInRect(ctx, CGRectMake(handleCenter.x-2.5, handleCenter.y-2.5, _lineWidth+5, _lineWidth+5));
//    CGContextDrawPath(ctx, kCGPathStroke);
    CGContextRestoreGState(ctx);
    
    CGContextSaveGState(ctx);
    CGPoint handleCenter2 =  [self pointFromAngle2: angle2];
//    if(_handleType == semiTransparentWhiteCircle) {
//        [[UIColor colorWithWhite:1.0 alpha:0.7] set];
//        CGContextFillEllipseInRect(ctx, CGRectMake(handleCenter.x, handleCenter.y, _lineWidth, _lineWidth));
//    } else if(_handleType == semiTransparentBlackCircle) {
//        [[UIColor colorWithWhite:0.0 alpha:0.7] set];
//        CGContextFillEllipseInRect(ctx, CGRectMake(handleCenter.x, handleCenter.y, _lineWidth, _lineWidth));
//    } else if(_handleType == doubleCircleWithClosedCenter) {
//        [_handleColor set];
//        CGContextAddArc(ctx, handleCenter.x + (_lineWidth)/2, handleCenter.y + (_lineWidth)/2, _lineWidth, 0, M_PI *2, 0);
//        CGContextSetLineWidth(ctx, 7);
//        CGContextSetLineCap(ctx, kCGLineCapButt);
//        CGContextDrawPath(ctx, kCGPathStroke);
//        CGContextFillEllipseInRect(ctx, CGRectMake(handleCenter.x, handleCenter.y, _lineWidth-1, _lineWidth-1));
//    } else if(_handleType == doubleCircleWithOpenCenter) {
//        [_handleColor set];
//        CGContextAddArc(ctx, handleCenter.x + (_lineWidth)/2, handleCenter.y + (_lineWidth)/2, 8, 0, M_PI *2, 0);
//        CGContextSetLineWidth(ctx, 4);
//        CGContextSetLineCap(ctx, kCGLineCapButt);
//        CGContextDrawPath(ctx, kCGPathStroke);
//        
//        CGContextAddArc(ctx, handleCenter.x + _lineWidth/2, handleCenter.y + _lineWidth/2, _lineWidth/2, 0, M_PI *2, 0);
//        CGContextSetLineWidth(ctx, 2);
//        CGContextSetLineCap(ctx, kCGLineCapButt);
//        CGContextDrawPath(ctx, kCGPathStroke);
//    } else if(_handleType == bigCircle) {
//        [_handleColor set];
//        CGContextFillEllipseInRect(ctx, CGRectMake(handleCenter.x-2.5, handleCenter.y-2.5, _lineWidth+5, _lineWidth+5));
//    }
//    [_handleColor set];
//    CGContextFillEllipseInRect(ctx, CGRectMake(handleCenter2.x-2.5, handleCenter2.y-2.5, _lineWidth+5, _lineWidth+5));

    [_handleColor set];
    CGContextAddArc(ctx, handleCenter2.x + (_lineWidth)/2, handleCenter2.y + (_lineWidth)/2, 8, 0, M_PI *2, 0);
    CGContextSetLineWidth(ctx, 4);
    CGContextSetLineCap(ctx, kCGLineCapButt);
    //    CGContextSetShadowWithColor(ctx, CGSizeMake(0, 0), _lineWidth/2, [UIColor blueColor].CGColor);
    CGContextDrawPath(ctx, kCGPathStroke);
    
    
    CGContextAddArc(ctx, handleCenter2.x + _lineWidth/2, handleCenter2.y + _lineWidth/2, _lineWidth/2, 0, M_PI *2, 0);
    [_handleInColor2 set];
    //    [[UIColor redColor] set];
    CGContextSetLineWidth(ctx, 2);
    CGContextSetLineCap(ctx, kCGLineCapButt);
    //    CGContextSetShadowWithColor(ctx, CGSizeMake(0, 0), _lineWidth, [UIColor blackColor].CGColor);
    CGContextFillEllipseInRect(ctx, CGRectMake(handleCenter2.x-2.5, handleCenter2.y-2.5, _lineWidth+5, _lineWidth+5));
    
//    CGContextFillEllipseInRect(ctx, CGRectMake(handleCenter2.x-5, handleCenter2.y-5, _lineWidth+10, _lineWidth+10));
    
    //    CGContextDrawPath(ctx, kCGPathStroke);
    CGContextRestoreGState(ctx);
    
//    CGContextRestoreGState(ctx);
}

-(void) drawLabels:(CGContextRef)ctx {
    if(labelsEvenSpacing == nil || [labelsEvenSpacing count] == 0) {
        return;
    } else {
        NSDictionary *attributes = @{ NSFontAttributeName: _labelFont,
                                      NSForegroundColorAttributeName: _labelColor};
        int distanceToMove = -15;
        
        for (int i=0; i<[labelsEvenSpacing count]; i++) {
            NSString* label = [labelsEvenSpacing objectAtIndex:[labelsEvenSpacing count] - i - 1];
            CGFloat percentageAlongCircle = i/(float)[labelsEvenSpacing count];
            CGFloat degreesForLabel = percentageAlongCircle * 360;
            CGPoint closestPointOnCircleToLabel = [self pointFromAngle1:degreesForLabel];
            
            CGRect labelLocation = CGRectMake(closestPointOnCircleToLabel.x, closestPointOnCircleToLabel.y, [self widthOfString:label withFont:_labelFont], [self heightOfString:label withFont:_labelFont]);
            
            CGPoint centerPoint = CGPointMake(self.frame.size.width/2, self.frame.size.height/2);
            float radiansTowardsCenter = ToRad(AngleFromNorth(centerPoint, closestPointOnCircleToLabel, NO));
            labelLocation.origin.x =  (labelLocation.origin.x + distanceToMove * cos(radiansTowardsCenter)) - labelLocation.size.width/4;
            labelLocation.origin.y = (labelLocation.origin.y + distanceToMove * sin(radiansTowardsCenter))- labelLocation.size.height/4;
            [label drawInRect:labelLocation withAttributes:attributes];
        }
    }
}

#pragma mark - UIControl functions

-(BOOL) beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
    [super beginTrackingWithTouch:touch withEvent:event];
    
    return YES;
}

-(BOOL) continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
    [super continueTrackingWithTouch:touch withEvent:event];
    
    CGPoint lastPoint = [touch locationInView:self];
    [self moveHandle:lastPoint];
    [self sendActionsForControlEvents:UIControlEventValueChanged];
    
    return YES;
}

-(void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event{
    [super endTrackingWithTouch:touch withEvent:event];
//    if(_snapToLabels && labelsEvenSpacing != nil) {
//        CGPoint bestGuessPoint;
//        float minDist = 360;
//        for (int i=0; i<[labelsEvenSpacing count]; i++) {
//            CGFloat percentageAlongCircle = i/(float)[labelsEvenSpacing count];
//            CGFloat degreesForLabel = percentageAlongCircle * 360;
//            if(abs(fixedAngle - degreesForLabel) < minDist) {
//                minDist = abs(fixedAngle - degreesForLabel);
//                bestGuessPoint = [self pointFromAngle:degreesForLabel + 90 + 180];
//            }
//        }
//        CGPoint centerPoint = CGPointMake(self.frame.size.width/2, self.frame.size.height/2);
//        angle = floor(AngleFromNorth(centerPoint, bestGuessPoint, NO));
//        _currentValue = [self valueFromAngle];
//        [self setNeedsDisplay];
//    }
}

-(void)moveHandle:(CGPoint)point {
    CGPoint centerPoint = CGPointMake(self.frame.size.width/2, self.frame.size.height/2);
    int currentAngle = floor(AngleFromNorth(centerPoint, point, NO));
    if ((currentAngle>=165&¤tAngle<=360)||(currentAngle>=0&¤tAngle<=15)) {
        angle1 = 360 - (360-165) - currentAngle;//148
    }else if(currentAngle>=30&¤tAngle<=150){
        angle2=360-(360-30)-currentAngle;
    }
//    NSLog(@"%d-angle1-",angle1);
//    NSLog(@"%d-angle2-",angle2);
    _currentValue1 = [self valueFromAngle1];
    _currentValue2 = [self valueFromAngle2];
    [self setNeedsDisplay];
}

#pragma mark - helper functions

-(CGPoint)pointFromAngle1:(int)angleInt{
    
    //Define the Circle center
    CGPoint centerPoint = CGPointMake(self.frame.size.width/2 - _lineWidth/2, self.frame.size.height/2 - _lineWidth/2);
    
    //Define The point position on the circumference
    CGPoint result;
    result.y = round(centerPoint.y + radius * sin(ToRad(-angleInt-(180+15)))) ;//90
    result.x = round(centerPoint.x + radius * cos(ToRad(-angleInt-(180+15))));
    
    return result;
}

-(CGPoint)pointFromAngle2:(int)angleInt{
    
    //Define the Circle center
    CGPoint centerPoint = CGPointMake(self.frame.size.width/2 - _lineWidth/2, self.frame.size.height/2 - _lineWidth/2);
    
    //Define The point position on the circumference
    CGPoint result;
    result.y = round(centerPoint.y + radius * sin(ToRad(-angleInt-(360-30)))) ;//90
    result.x = round(centerPoint.x + radius * cos(ToRad(-angleInt-(360-30))));
    
    return result;
}

static inline float AngleFromNorth(CGPoint p1, CGPoint p2, BOOL flipped) {
    CGPoint v = CGPointMake(p2.x-p1.x,p2.y-p1.y);
    float vmag = sqrt(SQR(v.x) + SQR(v.y)), result = 0;
    v.x /= vmag;
    v.y /= vmag;
    double radians = atan2(v.y,v.x);
    result = ToDeg(radians);
    return (result >=0  ? result : result + 360.0);
}

-(float) valueFromAngle1 {
    if(angle1 <=0) {
        _currentValue1 = -angle1;
    } else {
        _currentValue1 = 15+180+(165-angle1);
    }
    fixedAngle = _currentValue1;
    return (_currentValue1*(_maximumValue - _minimumValue))/210;
}

-(float) valueFromAngle2 {
    if(angle2 <0) {
        _currentValue2 = -angle2;
    }
    fixedAngle = _currentValue2;
    return (_currentValue2*(_maximumValue - _minimumValue))/120;
}

- (CGFloat) widthOfString:(NSString *)string withFont:(UIFont*)font {
    NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:font, NSFontAttributeName, nil];
    return [[[NSAttributedString alloc] initWithString:string attributes:attributes] size].width;
}

- (CGFloat) heightOfString:(NSString *)string withFont:(UIFont*)font {
    NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:font, NSFontAttributeName, nil];
    return [[[NSAttributedString alloc] initWithString:string attributes:attributes] size].height;
}

#pragma mark - public methods
-(void)setInnerMarkingLabels:(NSArray*)labels{
    labelsEvenSpacing = labels;
    [self setNeedsDisplay];
}

@end