Horizantal slider with tick marks on iOS

2020-04-08 13:46发布

问题:

Can i realise a horizontal slider with tick marks on iOS? There is not such option like in MacOS.

回答1:

I actually wrote a tutorial on how to do this on my company's website:

http://fragmentlabs.com/blog/making-talking2trees-part-3-77

The quick answer for this is a custom method I wrote, and which is explained in the article above:

-(UIView*)tickMarksViewForSlider:(UISlider*)slider View:(UIView *)view
{
// set up vars
int ticksDivider = (slider.maximumValue > 10) ? 10 : 1;
int ticks = (int) slider.maximumValue / ticksDivider;
int sliderWidth = 364;
float offsetOffset = (ticks < 10) ? 1.7 : 1.1;
offsetOffset = (ticks > 10) ? 0 : offsetOffset;
float offset = sliderWidth / ticks - offsetOffset;
float xPos = 0;

// initialize view to return
view.frame = CGRectMake(view.frame.origin.x, view.frame.origin.y+1,
    slider.frame.size.width, slider.frame.size.height);
view.backgroundColor = [UIColor clearColor];

// make a UIImageView with tick for each tick in the slider
for (int i=0; i < ticks; i++)
{
    if (i == 0) {
        xPos += offset+5.25;
    }
    else
    {
        UIView *tick = [[UIView alloc] initWithFrame:CGRectMake(xPos, 3, 2, 16)];
        tick.backgroundColor = [UIColor colorWithWhite:0.7 alpha:1];
        tick.layer.shadowColor = [[UIColor whiteColor] CGColor];
        tick.layer.shadowOffset = CGSizeMake(0.0f, 1.0f);
        tick.layer.shadowOpacity = 1.0f;
        tick.layer.shadowRadius = 0.0f;
        [view insertSubview:tick belowSubview:slider];
        xPos += offset - 0.4;
    }
}

// return the view
return view;
}

You'd basically apply this method to a view that sits behind your UISlider, and it creates the tick marks at the appropriate intervals. You can change how many ticks are visible by modifying the ticksDivider variable. The above example creates one per slider value unless the slider's maximumValue property is greater than 10 (my sliders had values of 5, 40 and 120), in which case I divided the value by 10.

You have to play with the offsetOffset value and the float value after xPos += offset+... to account for the width of your thumb image and slider cap insets (so the thumb button appears to be centered over each).



回答2:

From @CarlGoldsmith - You'd have to program that yourself; UISliders on iOS don't have that functionality.



回答3:

While ctlockey's solution certainly works, I wanted something simpler but also that allowed the thumb to snap to whichever tick mark it is closest to when the user releases it.

My solution is below. It is a subclass of UISlider that only overrides two methods. It is bare bones but would be a foundation for a more complex version.

-(void)endTrackingWithTouch:(UITouch *)touch
                  withEvent:(UIEvent *)event
{
    [super endTrackingWithTouch:touch withEvent:event];
    if (self.value != floorf(self.value))
    {
        CGFloat roundedFloat = (float)roundf(self.value);
        [self setValue:roundedFloat animated:YES];
    }
}

-(void)drawRect:(CGRect)rect
{    
    CGFloat thumbOffset = self.currentThumbImage.size.width / 2.0f;
    NSInteger numberOfTicksToDraw = roundf(self.maximumValue - self.minimumValue) + 1;
    CGFloat distMinTickToMax = self.frame.size.width - (2 * thumbOffset);
    CGFloat distBetweenTicks = distMinTickToMax / ((float)numberOfTicksToDraw - 1);

    CGFloat xTickMarkPosition = thumbOffset; //will change as tick marks are drawn across slider
    CGFloat yTickMarkStartingPosition = self.frame.size.height / 2; //will not change
    CGFloat yTickMarkEndingPosition = self.frame.size.height; //will not change
    UIBezierPath *tickPath = [UIBezierPath bezierPath];
    for (int i = 0; i < numberOfTicksToDraw; i++)
    {
        [tickPath moveToPoint:CGPointMake(xTickMarkPosition, yTickMarkStartingPosition)];
        [tickPath addLineToPoint:CGPointMake(xTickMarkPosition, yTickMarkEndingPosition)];
        xTickMarkPosition += distBetweenTicks;
    }
    [tickPath stroke];
}