实现无需触摸UISlider滑块即可在UICollectionViewCell内拖动
解决方案:UICollectionViewCell内自定义UISlider实现全域平滑拖动
需求:在UICollectionViewCell中自定义了旋转90度的UISlider,希望触摸单元格任意区域(紫色区域)即可拖动滑块,且滑块从当前位置平滑滑动,而非直接跳转至触摸位置。
问题分析
现有代码仅在触摸滑块thumb附近区域时触发跟踪逻辑,且默认UISlider触摸非thumb区域会直接将value跳转到触摸位置对应的数值,无法实现平滑过渡。需要修改触摸跟踪逻辑,通过计算触摸偏移量逐步更新slider的value。
修改后的实现代码
@implementation CDCFaderSlider { CGPoint _initialTouchPoint; float _initialValue; } - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame: frame]; if (self) { [self setOpaque: YES]; [self setTransform: CGAffineTransformMakeRotation((CGFloat)(M_PI * -0.5f))]; [self constructSlider]; } return self; } - (id)initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder: aDecoder]; if (self) { [self setTransform: CGAffineTransformMakeRotation((CGFloat)(M_PI * -0.5f))]; [self constructSlider]; } return self; } #pragma mark - UIControl touch event tracking - (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event { _initialTouchPoint = [touch locationInView:self]; _initialValue = self.value; // 开启全域触摸跟踪 [self positionAndUpdateValueView]; [self fadeValueViewInAndOut: YES]; return YES; } - (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event { CGPoint currentTouchPoint = [touch locationInView:self]; // 计算Y轴偏移(滑块旋转90度后,轨道高度对应原X轴长度) CGFloat deltaY = currentTouchPoint.y - _initialTouchPoint.y; // 计算每像素对应的value变化比例 CGRect trackRect = [self trackRectForBounds:self.bounds]; CGFloat trackHeight = trackRect.size.height; CGFloat valueRange = self.maximumValue - self.minimumValue; CGFloat valuePerPixel = valueRange / trackHeight; // 计算并限制新value范围 float newValue = _initialValue + deltaY * valuePerPixel; newValue = MAX(self.minimumValue, MIN(newValue, self.maximumValue)); // 平滑更新滑块值 self.value = newValue; [self positionAndUpdateValueView]; return YES; } - (void)cancelTrackingWithEvent:(UIEvent *)event { [self fadeValueViewInAndOut: NO]; [super cancelTrackingWithEvent: event]; } - (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event { [self fadeValueViewInAndOut: NO]; [super endTrackingWithTouch: touch withEvent: event]; } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { [self fadeValueViewInAndOut: NO]; [super touchesEnded: touches withEvent: event]; } - (BOOL) pointInside:(CGPoint)point withEvent:(UIEvent*)event { CGRect bounds = self.bounds; bounds = CGRectInset(bounds, 0, -70); return CGRectContainsPoint(bounds, point); } #pragma mark - Helper methods - (void)constructSlider { self.valueView = [[CDCFaderValueView alloc] initWithFrame: CGRectZero]; self.valueView.backgroundColor = UIColor.clearColor; self.valueView.alpha = 0.0; self.valueView.transform = CGAffineTransformMakeRotation((CGFloat)(M_PI * 0.5)); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [self addSubview: self.valueView]; }); } - (void)fadeValueViewInAndOut:(BOOL)aFadeIn { [UIView animateWithDuration: 0.5 animations:^{ self.valueView.alpha = aFadeIn ? 0.8 : 0.0; } completion:nil]; } - (void)positionAndUpdateValueView { CGRect thumbRect = self.thumbRect; CGRect popupRect = CGRectOffset(thumbRect, floor(thumbRect.size.width * 0.2), -floor(thumbRect.size.height * 0.5)); self.valueView.frame = CGRectInset(popupRect, -30, -10); self.valueView.value = faderDBValues[(NSInteger)self.value]; } #pragma mark - Property - (CGRect)thumbRect { CGRect trackRect = [self trackRectForBounds: self.bounds]; return [self thumbRectForBounds:self.bounds trackRect:trackRect value:self.value]; } - (void)sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event { // 保留原有action节流逻辑 if (self.count > 4) { [super sendAction:action to:target forEvent:event]; self.count = 0; } else { self.count++; } if (!self.tracking) { [super sendAction:action to:target forEvent:event]; } } @end
关键修改说明
- 新增实例变量:
_initialTouchPoint和_initialValue记录触摸初始状态,用于后续偏移量计算。 - 全域触摸开启:移除
beginTrackingWithTouch:中的thumb区域判断,直接返回YES允许任意区域触发跟踪。 - 平滑值计算:在
continueTrackingWithTouch:中通过触摸偏移量和轨道比例,逐步计算滑块新值,避免直接跳转。 - 代码简化:优化
fadeValueViewInAndOut:的写法,保持逻辑简洁。
内容的提问来源于stack exchange,提问作者NaKh
相关产品推荐
相关产品推荐

