UISlider that snaps to a fixed number of steps (like Text Size in the iOS 7 Settings app)

前端 未结 6 2212
情深已故
情深已故 2020-12-04 06:31

I\'m trying to create a UISlider that lets you choose from an array of numbers. Each slider position should be equidistant and the slider should snap to each po

6条回答
  •  日久生厌
    2020-12-04 07:01

    Some of the other answers work, but this will give you the same fixed space between every position in your slider. In this example you treat the slider positions as indexes to an array which contains the actual numeric values you are interested in.

    @interface MyViewController : UIViewController {
        UISlider *slider;
        NSArray *numbers;
    }
    @end
    
    @implementation MyViewController
    - (void)viewDidLoad {
        [super viewDidLoad];
        slider = [[UISlider alloc] initWithFrame:self.view.bounds];
        [self.view addSubview:slider];
    
        // These number values represent each slider position
        numbers = @[@(-3), @(0), @(2), @(4), @(7), @(10), @(12)];
        // slider values go from 0 to the number of values in your numbers array
        NSInteger numberOfSteps = ((float)[numbers count] - 1);
        slider.maximumValue = numberOfSteps;
        slider.minimumValue = 0;
    
        // As the slider moves it will continously call the -valueChanged: 
        slider.continuous = YES; // NO makes it call only once you let go
        [slider addTarget:self
                   action:@selector(valueChanged:)
         forControlEvents:UIControlEventValueChanged];
    }
    - (void)valueChanged:(UISlider *)sender {
        // round the slider position to the nearest index of the numbers array
        NSUInteger index = (NSUInteger)(slider.value + 0.5);
        [slider setValue:index animated:NO];
        NSNumber *number = numbers[index]; // <-- This numeric value you want
        NSLog(@"sliderIndex: %i", (int)index);
        NSLog(@"number: %@", number);
    }
    

    I hope that helps, good luck.

    Edit: Here's a version in Swift 4 that subclasses UISlider with callbacks.

    class MySliderStepper: UISlider {
        private let values: [Float]
        private var lastIndex: Int? = nil
        let callback: (Float) -> Void
    
        init(frame: CGRect, values: [Float], callback: @escaping (_ newValue: Float) -> Void) {
            self.values = values
            self.callback = callback
            super.init(frame: frame)
            self.addTarget(self, action: #selector(handleValueChange(sender:)), for: .valueChanged)
    
            let steps = values.count - 1
            self.minimumValue = 0
            self.maximumValue = Float(steps)
        }
    
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    
        @objc func handleValueChange(sender: UISlider) {
            let newIndex = Int(sender.value + 0.5) // round up to next index
            self.setValue(Float(newIndex), animated: false) // snap to increments
            let didChange = lastIndex == nil || newIndex != lastIndex!
            if didChange {
                lastIndex = newIndex
                let actualValue = self.values[newIndex]
                self.callback(actualValue)
            }
        }
    }
    

提交回复
热议问题