Как включить «коснуться и сдвинуть» в UISlider?

То, что я хочу получить, – это UISlider который позволяет пользователю не только сползать, когда он запускается на своем thumbRect , но также и когда он вступает в другое место. Когда пользователь нажимает на ползунок, но за пределами thumbRect , ползунок должен перейти к этому значению, а затем все еще придерживаться раздвижного жеста пользователя .

До сих пор я пытался реализовать подкласс UIGestureRecognizer, как в этом предложении . Он начинается прямо тогда, когда происходит прикосновение к нему где-то вне thumbRect . Проблема в том, что ползунок устанавливает его значение, но затем дальнейшие раздвижные жесты игнорируются, потому что распознающий сенсорный захват украл прикосновение .

Как я могу реализовать слайдер, где вы можете нажимать в любом месте, но все же слайд сразу?


Edit: ali59a было так мило, чтобы добавить пример того, что я сделал сейчас. Для этого нужно снова поднять палец, после чего я могу прикоснуться и перетащить на слайд (крана не то, что я хочу, мне нужно «прикоснуться и сдвинуть» сразу).

Я не уверен, что вы все еще ищете ответ для этого, но я просто смотрел на это сам сегодня; и мне удалось заставить его работать на меня.

Ключ к ней, используя UILongPressGestureRecognizer а не только UITapGestureRecognizer , мы можем установить minimumPressDuration значениеPressDuration распознавателя на 0; заставляя его действовать как распознаватель крана, за исключением того, что теперь вы можете проверить его состояние.

Полагая, что предложенный ali59a будет работать для вас, просто заменив UITapGestureRecognizer на UILongPressGestureRecognizer . Тем не менее, я обнаружил, что это, похоже, не помещало thumbRect прямо под моим пальцем. Мне показалось, что это немного от меня.

Я создал свой собственный подкласс UISlider для моего проекта, и вот как я применил функцию «tap and slide» для меня.

В моем методе init :

 UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(tapAndSlide:)]; longPress.minimumPressDuration = 0; [self addGestureRecognizer:longPress]; 

Затем мой метод tapAndSlide: ::

 - (void)tapAndSlide:(UILongPressGestureRecognizer*)gesture { CGPoint pt = [gesture locationInView: self]; CGFloat thumbWidth = [self thumbRect].size.width; CGFloat value; if(pt.x <= [self thumbRect].size.width/2.0) value = self.minimumValue; else if(pt.x >= self.bounds.size.width - thumbWidth/2.0) value = self.maximumValue; else { CGFloat percentage = (pt.x - thumbWidth/2.0)/(self.bounds.size.width - thumbWidth); CGFloat delta = percentage * (self.maximumValue - self.minimumValue); value = self.minimumValue + delta; } if(gesture.state == UIGestureRecognizerStateBegan){ [UIView animateWithDuration:0.35 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ [self setValue:value animated:YES]; [super sendActionsForControlEvents:UIControlEventValueChanged]; } completion:nil]; } else [self setValue:value]; if(gesture.state == UIGestureRecognizerStateChanged) [super sendActionsForControlEvents:UIControlEventValueChanged]; } 

Где я также использовал метод для возврата рамки моего пользовательского thumbRect:

 - (CGRect)thumbRect { CGRect trackRect = [self trackRectForBounds:self.bounds]; return [self thumbRectForBounds:self.bounds trackRect:trackRect value:self.value]; } 

У меня также есть мой слайдер, приближающийся к позиции, в которой пользователь сначала отбирает, более 0,35 секунды. Я считаю, что это очень мило, поэтому я включил это в этот код. Если вы этого не хотите, попробуйте это:

 - (void)tapAndSlide:(UILongPressGestureRecognizer*)gesture { CGPoint pt = [gesture locationInView: self]; CGFloat thumbWidth = [self thumbRect].size.width; CGFloat value; if(pt.x <= [self thumbRect].size.width/2.0) value = self.minimumValue; else if(pt.x >= self.bounds.size.width - thumbWidth/2.0) value = self.maximumValue; else { CGFloat percentage = (pt.x - thumbWidth/2.0)/(self.bounds.size.width - thumbWidth); CGFloat delta = percentage * (self.maximumValue - self.minimumValue); value = self.minimumValue + delta; } [self setValue:value]; if(gesture.state == UIGestureRecognizerStateChanged) [super sendActionsForControlEvents:UIControlEventValueChanged]; } 

Надеюсь, это имеет смысл и помогает вам.

Я преобразовал ответ, предоставленный DWilliames в Swift

Внутри вашего видаDidAppear ()

 let longPress = UILongPressGestureRecognizer(target: self.slider, action: Selector("tapAndSlide:")) longPress.minimumPressDuration = 0 self.addGestureRecognizer(longPress) 

Файл класса

 class TapUISlider: UISlider { func tapAndSlide(gesture: UILongPressGestureRecognizer) { let pt = gesture.locationInView(self) let thumbWidth = self.thumbRect().size.width var value: Float = 0 if (pt.x <= self.thumbRect().size.width / 2) { value = self.minimumValue } else if (pt.x >= self.bounds.size.width - thumbWidth / 2) { value = self.maximumValue } else { let percentage = Float((pt.x - thumbWidth / 2) / (self.bounds.size.width - thumbWidth)) let delta = percentage * (self.maximumValue - self.minimumValue) value = self.minimumValue + delta } if (gesture.state == UIGestureRecognizerState.Began) { UIView.animateWithDuration(0.35, delay: 0, options: UIViewAnimationOptions.CurveEaseInOut, animations: { self.setValue(value, animated: true) super.sendActionsForControlEvents(UIControlEvents.ValueChanged) }, completion: nil) } else { self.setValue(value, animated: false) } } func thumbRect() -> CGRect { return self.thumbRectForBounds(self.bounds, trackRect: self.bounds, value: self.value) } } 

Вы должны добавить жестов кран на свой UISlider .

Пример:

  UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(sliderTapped:)]; [_slider addGestureRecognizer:tapGestureRecognizer]; 

В sliderTapped вы можете получить местоположение и обновить значение ползунка:

 - (void)sliderTapped:(UIGestureRecognizer *)gestureRecognizer { CGPoint pointTaped = [gestureRecognizer locationInView:gestureRecognizer.view]; CGPoint positionOfSlider = _slider.frame.origin; float widthOfSlider = _slider.frame.size.width; float newValue = ((pointTaped.x - positionOfSlider.x) * _slider.maximumValue) / widthOfSlider; [_slider setValue:newValue]; } 

Я создаю пример здесь: https://github.com/ali59a/tap-and-slide-in-a-UISlider

Вот моя модификация:

 class TapUISlider: UISlider { func tapAndSlide(gesture: UILongPressGestureRecognizer) { let pt = gesture.locationInView(self) let thumbWidth = self.thumbRect().size.width var value: Float = 0 if (pt.x <= self.thumbRect().size.width / 2) { value = self.minimumValue } else if (pt.x >= self.bounds.size.width - thumbWidth / 2) { value = self.maximumValue } else { let percentage = Float((pt.x - thumbWidth / 2) / (self.bounds.size.width - thumbWidth)) let delta = percentage * (self.maximumValue - self.minimumValue) value = self.minimumValue + delta } if (gesture.state == UIGestureRecognizerState.Began) { UIView.animateWithDuration(0.35, delay: 0, options: UIViewAnimationOptions.CurveEaseInOut, animations: { self.setValue(value, animated: true) super.sendActionsForControlEvents(UIControlEvents.ValueChanged) }, completion: nil) } else { self.setValue(value, animated: false) super.sendActionsForControlEvents(UIControlEvents.ValueChanged) } } func thumbRect() -> CGRect { return self.thumbRectForBounds(self.bounds, trackRect: self.bounds, value: self.value) } } 

Добавив быструю версию ответа Али А. Б.,

 @IBAction func sliderTappedAction(sender: UITapGestureRecognizer) { if let slider = sender.view as? UISlider { if slider.highlighted { return } let point = sender.locationInView(slider) let percentage = Float(point.x / CGRectGetWidth(slider.bounds)) let delta = percentage * (slider.maximumValue - slider.minimumValue) let value = slider.minimumValue + delta slider.setValue(value, animated: true) } } 

Я выполнил решение @DWilliames для подкласса UISlider содержащего minimum и maximumValueImages .

Кроме того, я реализовал функциональность для пользовательских касаний в областях вне trackArea (означает либо область вокруг minimum либо maximumValueImage ). Прикосновение к этим областям перемещает ползунок / изменяет значение в интервалах.

 - (void) tapAndSlide: (UILongPressGestureRecognizer*) gesture { CGPoint touchPoint = [gesture locationInView: self]; CGRect trackRect = [self trackRectForBounds: self.bounds]; CGFloat thumbWidth = [self thumbRectForBounds: self.bounds trackRect: trackRect value: self.value].size.width; CGRect trackArea = CGRectMake(trackRect.origin.x, 0, trackRect.size.width, self.bounds.size.height); CGFloat value; if (CGRectContainsPoint(trackArea, touchPoint)) { if (touchPoint.x <= trackArea.origin.x + thumbWidth/2.0) { value = self.minimumValue; } else if (touchPoint.x >= trackArea.origin.x + trackArea.size.width - thumbWidth/2.0) { value = self.maximumValue; } else { CGFloat percentage = (touchPoint.x - trackArea.origin.x - thumbWidth/2.0)/(trackArea.size.width - thumbWidth); CGFloat delta = percentage*(self.maximumValue - self.minimumValue); value = self.minimumValue + delta; } if (value != self.value) { if (gesture.state == UIGestureRecognizerStateBegan) { [UIView animateWithDuration: 0.2 delay: 0 options: UIViewAnimationOptionCurveEaseInOut animations: ^{ [self setValue: value animated: YES]; } completion: ^(BOOL finished) { [self sendActionsForControlEvents: UIControlEventValueChanged]; }]; } else { [self setValue: value animated: YES]; [self sendActionsForControlEvents: UIControlEventValueChanged]; } } } else { if (gesture.state == UIGestureRecognizerStateBegan) { if (touchPoint.x <= trackArea.origin.x) { if (self.value == self.minimumValue) return; value = self.value - 1.5; } else { if (self.value == self.maximumValue) return; value = self.value + 1.5; } CGFloat duration = 0.1; [UIView animateWithDuration: duration delay: 0 options: UIViewAnimationOptionCurveEaseInOut animations: ^{ [self setValue: value animated: YES]; } completion: ^(BOOL finished) { [self sendActionsForControlEvents: UIControlEventValueChanged]; }]; } } } 
Interesting Posts
Давайте будем гением компьютера.