Search code examples
iphoneiosxcodeuislider

how to do dual circular slider (clock like function)


i will like to know how to do a dual slider in the attached image.

i am looking at this codes to modified it. i will like to know how to have 2 slider to allow user to choose the desired time.

The problem i encounter are how do i have 2 slider to show something like the image?

http://www.cocoacontrols.com/controls/tb_circularslider

any comment are greatly appreciated here.

enter image description here


Solution

  • for the dual slider positions you have this excerpt in code

    CGContextAddArc(imageCtx, self.frame.size.width/2  , self.frame.size.height/2, radius, 0, ToRad(self.angle), 0);
    

    the first zero (0) is the starting point, so you want to use a different angle here

    CGContextAddArc(imageCtx, self.frame.size.width/2  , self.frame.size.height/2, radius, ToRad(self.startAngle), ToRad(self.endAngle), 0);
    

    (you need those two ivar's in your header of course)

    EDIT: here is the edited code to find the nearest knob and lock it for modification. The old code didn't locked it, so it would change upon hover from one knob to another.
    First of all add the enum above your implementation:

    enum SliderLockType {
        SliderLockedNone = 0,
        SliderLockedStart,
        SliderLockedEnd
    };
    
    #pragma mark - Implementation -
    
    @implementation TBCircularSlider
    enum SliderLockType sliderLock;
    
    // … some code here …
       //Initialize the Angle at 0
       //self.startAngle = 0;
       //self.endAngle = 270;
    
    /** Tracking is started **/
    -(BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event{
        [super beginTrackingWithTouch:touch withEvent:event];
    
        // find nearest knob …
        CGPoint lastPoint = [touch locationInView:self];
        CGPoint pStart = [self centerPointFromAngel:self.startAngle];
        CGPoint pEnd   = [self centerPointFromAngel:self.endAngle];
        float diffA = [self distanceBetween:lastPoint and:pStart];
        float diffB = [self distanceBetween:lastPoint and:pEnd];
    
        // … and lock it
        if (diffA <= TB_LINE_WIDTH) { // the tolerance is the width of the circle
            sliderLock = SliderLockedStart;
        } else if (diffB <= TB_LINE_WIDTH) {
            sliderLock = SliderLockedEnd;
        }
    
        //We need to track continuously
        return YES;
    }
    
    // continueTrackingWithTouch:withEvent: stays unchanged
    
    /** Track is finished **/
    -(void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event{
        [super endTrackingWithTouch:touch withEvent:event];
    
        // reset the lock before starting a new touch event
        sliderLock = SliderLockedNone;
    }
    
    - (CGPoint)centerPointFromAngel:(int)angleInt {
        CGPoint point = [self pointFromAngle:angleInt];
        point.x += TB_LINE_WIDTH/2;
        point.y += TB_LINE_WIDTH/2;
        return point;
    }
    
    - (CGFloat)distanceBetween:(CGPoint)p1 and:(CGPoint)p2 {
        CGFloat xDist = (p2.x - p1.x);
        CGFloat yDist = (p2.y - p1.y);
        return sqrt((xDist * xDist) + (yDist * yDist));
    }
    
    // … some more code …
    
    - (void)drawTheHandle:(CGContextRef)ctx {
    
        CGContextSaveGState(ctx);
    
        //I Love shadows
        CGContextSetShadowWithColor(ctx, CGSizeMake(0, 0), 3, [UIColor blackColor].CGColor);
    
        //Get the handle position!
        CGPoint handleCenterA =  [self pointFromAngle: self.startAngle];
        CGPoint handleCenterB =  [self pointFromAngle: self.endAngle];
    
        //Draw It!
        [[UIColor colorWithWhite:1.0 alpha:0.7]set];
        CGContextFillEllipseInRect(ctx, CGRectMake(handleCenterA.x, handleCenterA.y, TB_LINE_WIDTH, TB_LINE_WIDTH));
        CGContextFillEllipseInRect(ctx, CGRectMake(handleCenterB.x, handleCenterB.y, TB_LINE_WIDTH, TB_LINE_WIDTH));
    
        CGContextRestoreGState(ctx);
    }
    
    - (void)movehandle:(CGPoint)lastPoint {
    
        //Get the center
        CGPoint centerPoint = CGPointMake(self.frame.size.width/2, self.frame.size.height/2);
    
        //Calculate the direction from the center point to an arbitrary position.
        float currentAngle = AngleFromNorth(centerPoint, lastPoint, NO);
        int angleInt = 360 - floor(currentAngle);
    
        if (sliderLock == SliderLockedStart) {
            self.startAngle = angleInt;
        } else if (sliderLock == SliderLockedEnd) {
            self.endAngle = angleInt;
        }
    
        //Redraw
        [self setNeedsDisplay];
    }
    

    the result:
    modified TBCircularSlider Lib

    EDIT2: if you like to have the slider switching from hour to hour you can modify the movehandle: method as follows:

    int angleInt = (int)(360 - floor(currentAngle)) / 30 * 30; // 360/30 = 12 -> hours
    
    if (sliderLock == SliderLockedStart && angleInt%360 != self.endAngle%360) {
        self.startAngle = angleInt;
    } else if (sliderLock == SliderLockedEnd && angleInt%360 != self.startAngle%360) {
        self.endAngle = angleInt;
    }