Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/vb.net/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Iphone UISlider和UIScrollView_Iphone_Uiscrollview_Uislider - Fatal编程技术网

Iphone UISlider和UIScrollView

Iphone UISlider和UIScrollView,iphone,uiscrollview,uislider,Iphone,Uiscrollview,Uislider,我有一个UISlider作为视图的一部分,该视图加载到启用分页的UIScrollView中。我注意到一个意想不到的行为。如果用户尝试快速使用滑块(即按下并移动),它会“激活”滚动视图,导致页面切换。但是,如果按住一秒钟,滑块将“激活”,然后可以调整滑块值。这种行为是不可取的 当加载到UIScrollView时,使UISlider响应的最佳方法是什么?我曾考虑添加一个“拦截器”视图,它只会吞噬滑块下的触摸事件,但不确定这是否是最好的方法。让您的滚动视图检测滑块所占据区域的触摸(覆盖hitTest:

我有一个
UISlider
作为视图的一部分,该视图加载到启用分页的
UIScrollView
中。我注意到一个意想不到的行为。如果用户尝试快速使用滑块(即按下并移动),它会“激活”滚动视图,导致页面切换。但是,如果按住一秒钟,滑块将“激活”,然后可以调整滑块值。这种行为是不可取的


当加载到
UIScrollView
时,使
UISlider
响应的最佳方法是什么?我曾考虑添加一个“拦截器”视图,它只会吞噬滑块下的触摸事件,但不确定这是否是最好的方法。

让您的滚动视图检测滑块所占据区域的触摸(覆盖
hitTest:withEvent:
,您可能需要子类
UIScrollView
)。如果检测到对所述区域的触摸,请告诉您的滚动视图立即将触摸传递到滑块。

无需在
UIScrollView
侧进行点击测试。因为延迟是由
UIScrollView
本身设置的。子类化和实现自定义的
hitTest:withEvent:
不会有帮助,因为它仍然会被延迟触发

我花了几个小时寻找一个优雅的解决方案,因为我想在ios应用程序切换器中模拟苹果自己的volumeslider

诀窍:

yourScrollView.delaysContentTouches = NO;
不幸的是,这会禁用沿
UISliders
轨迹的事件,因此对于这一部分,您的
UIScrollView
不会触发任何触摸事件,因为它们首先被滑块捕获

要传递除
UISliders
thumb rect中的触摸事件以外的其他触摸事件,您必须对
UISlider
进行子类化并添加以下内容:

// get the location of the thumb
- (CGRect)thumbRect 
{
   CGRect trackRect = [self trackRectForBounds:self.bounds];
   CGRect thumbRect = [self thumbRectForBounds:self.bounds
                                  trackRect:trackRect
                                      value:self.value];
   return thumbRect;
}

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{   
   CGRect thumbFrame = [self thumbRect];

      // check if the point is within the thumb
   if (CGRectContainsPoint(thumbFrame, point))
   {
      // if so trigger the method of the super class
      NSLog(@"inside thumb");
      return [super hitTest:point withEvent:event];
   }
   else
   {
      // if not just pass the event on to your superview
      NSLog(@"outside thumb");
      return [[self superview] hitTest:point withEvent:event];
   }
}

您可以将UIScrollView子类化,并覆盖方法
-(BOOL)touchesshouldbeagin:(NSSet*)toucheevent:(UIEvent*)event inContentView:(UIView*)view
,如下所示:

- (BOOL)touchesShouldBegin:(NSSet *)touches withEvent:(UIEvent *)event inContentView:(UIView *)view {
    if ([view isKindOfClass:[UISlider class]]) {
        UITouch *touch = [[event allTouches] anyObject];
        CGPoint location = [touch locationInView:view];
        CGRect thumbRect;
        UISlider *mySlide = (UISlider*) view;
        CGRect trackRect = [mySlide trackRectForBounds:mySlide.bounds];
        thumbRect = [mySlide thumbRectForBounds:mySlide.bounds trackRect:trackRect value:mySlide.value];
        if (CGRectContainsPoint(thumbRect, location))
            return YES;
    }
    return NO;
}

同时设置
yourScrollView.delaysContentTouches=NO属性。

在创建音频播放器时,我遇到了一个
滑动视图的问题,它被添加到
滚动视图中,每当我触摸
滑动视图时,
滚动视图
用于触摸,而不是
滑动视图
滚动视图已移动。为了避免这种情况,当用户触摸
sliderView
时,我禁用了
scrollView
的srcolling,否则将启用滚动

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {

    UIView *result = [super hitTest:point withEvent:event] ;
    if (result == sliderView)
    {
        scrollView.scrollEnabled = NO ;
    }
    else
    {
        scrollView.scrollEnabled = YES ;
    }

    return result ;

}

我的问题是这个问题的一个超集-我在UITableViewCells中有UISliders,整个UITableView是UIScrollView中的一个页面。滑块破坏了与其他两个滑块的交互,子类化解决方案无法工作。我想到了一个非常有效的方法:当滑块移动时发送通知,并在此期间禁用UITableView和UIScrollView滚动。请注意:我的滑块是水平的,我的tableview是垂直的,我的UIScrollView有水平的页面

UITableViewCell为以编程方式创建的滑块拾取事件:

self.numberSlider = [[UISlider alloc] init];
[self.numberSlider addTarget:self action:@selector(sliderValueChanged:) forControlEvents:UIControlEventValueChanged];
[self.numberSlider addTarget:self action:@selector(sliderTouchDown:) forControlEvents:UIControlEventTouchDown];
[self.numberSlider addTarget:self action:@selector(sliderTouchUp:) forControlEvents:UIControlEventTouchUpInside];
[self.numberSlider addTarget:self action:@selector(sliderTouchUp:) forControlEvents:UIControlEventTouchUpOutside];
在本教程中,我们只关注着地和着地:

- (void)sliderTouchDown:(UISlider *)sender
{
    [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFY_SLIDER_TOUCH_BEGAN object:nil];
}

- (void)sliderTouchUp:(UISlider *)sender
{
    [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFY_SLIDER_TOUCH_ENDED object:nil];
}
现在,我们在UITableView中捕获了这些通知(注意,tableview在VC中,但我相信如果您将其子类化,这会起作用):

和UIScrollView(与上面相同,封装在VC中):


我很想听到一个更优雅的解决方案,但这一个肯定能完成任务。使用滑块时,表视图和滚动视图保持静止,单击滑块外部时,表视图和滚动视图按预期移动。另外,请注意,我可以在这个解决方案中使用所有3个组件的非子类实例。希望这对别人有帮助

我想将此作为评论发布,但我的帐户没有代表,因此我不得不发布完整的答案。user762391的答案(包括hitTest覆盖)可以完美地工作。我只想补充一点,您可以像这样重写pointInside:withEvent:而不是重写hitTest(保持thumbRect方法):

或使用Swift:

var thumbRect: CGRect {
    return thumbRectForBounds(bounds, trackRect: trackRectForBounds(bounds), value: value)
}

override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool {
    return thumbRect.contains(point)
}

Swift 3中投票最多的注释代码:)


谢谢,最后还是那样做了。然而,另一个奇怪之处。。。这种行为似乎只在模拟器上表现出来。一旦我在设备上安装了它,它在没有fix.FWIW的情况下运行良好,我在模拟器(iOS 6)和设备(iOS 5.1)上看到了完全相同的行为(如原始问题中所述)。在拖动滑块之前,我必须轻按并保持片刻,否则我将获得滚动视图拖动。谢谢Sebastian,这正是我要寻找的!谢谢,它实际上节省了我在SWIFT中转换objective-c代码的时间。非常感谢你,杰夫。在过去的两个小时里,我一直在努力解决这个问题。你的解决方案对我有效。我只需要为Swift 5更新它。var thumbRect:CGRect{return thumbRect(forBounds:bounds,trackRect:trackRect(forBounds:bounds,value:value)}重写func point(内部点:CGPoint,带有event:UIEvent?->Bool{return thumbRect.contains(point)}在何处添加此方法?
- (void)viewDidLoad
{
    // other stuff

    // Register for slider notifications
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(disableScrolling:) name:NOTIFY_SLIDER_TOUCH_BEGAN object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(enableScrolling:) name:NOTIFY_SLIDER_TOUCH_ENDED object:nil];
}

- (void)disableScrolling:(NSNotification *)notify
{
    self.scrollView.scrollEnabled = NO;
}

- (void)enableScrolling:(NSNotification *)notify
{
    self.scrollView.scrollEnabled = YES;
}
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent * _Nullable)event {
    return CGRectContainsPoint([self thumbRect], point)
}
var thumbRect: CGRect {
    return thumbRectForBounds(bounds, trackRect: trackRectForBounds(bounds), value: value)
}

override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool {
    return thumbRect.contains(point)
}
import Foundation

class UISliderForScrollView:UISlider {
    var thumbRect:CGRect {
        let trackRect = self.trackRect(forBounds: bounds)
        return thumbRect(forBounds: bounds, trackRect: trackRect, value: value)
    }

    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        if thumbRect.contains(point) {
            return super.hitTest(point, with: event)
        } else {
            return superview?.hitTest(point, with: event)
        }
    }
}