mem*_*cal 15 objective-c uiscrollview uikit ios
我在另一个视图的顶部有一个透明的UIScrollView.
滚动视图包含内容 - 文本和图像,用于显示信息.
它背后的视图有一些用户应该能够点击的图像.使用上面提到的scrollview可以滚动它们上面的内容.
我希望能够正常使用滚动视图(尽管没有缩放),但是当滚动视图实际上没有滚动时,让点击事件通过它后面的视图.
使用触摸和滚动事件的组合,我可以确定何时让水龙头通过.但它背后的观点仍然没有收到它们.
我尝试过为所有触摸事件使用这样的东西:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(@"touchesBegan %@", (_isScrolling ? @"YES" : @"NO"));
if(!_isScrolling)
{
NSLog(@"sending");
[self.viewBehind touchesBegan:touches withEvent:event];
}
}
Run Code Online (Sandbox Code Playgroud)
但它不起作用.
在我的情况下,鉴于我的用例,我无法真正应用hitTest和pointInside解决方案.
Lyn*_*ott 10
首先UIScrollView唯一的固有认识UIPanGestureRecognizerS和UIPinchGestureRecognizerS左右,你需要一个添加UITapGestureRecognizer的UIScrollView,因此它可以识别任何敲击手势,以及:
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
// To prevent the pan gesture of the UIScrollView from swallowing up the
// touch event
tap.cancelsTouchesInView = NO;
[scrollView addGestureRecognizer:tap];
Run Code Online (Sandbox Code Playgroud)
然后,一旦您收到该轻击手势并handleTap:触发动作,您就可以使用locationInView:检测轻击手势的位置实际上是否位于滚动视图下方的一个图像的框架内,例如:
- (void)handleTap:(UITapGestureRecognizer *)recognizer {
// First get the tap gesture recognizers's location in the entire
// view's window
CGPoint tapPoint = [recognizer locationInView:self.view];
// Then see if it falls within one of your below images' frames
for (UIImageView* image in relevantImages) {
// If the image's coordinate system isn't already equivalent to
// self.view, convert it so it has the same coordinate system
// as the tap.
CGRect imageFrameInSuperview = [image.superview convertRect:image toView:self.view]
// If the tap in fact lies inside the image bounds,
// perform the appropriate action.
if (CGRectContainsPoint(imageFrameInSuperview, tapPoint)) {
// Perhaps call a method here to react to the image tap
[self reactToImageTap:image];
break;
}
}
}
Run Code Online (Sandbox Code Playgroud)
这样,上述代码仅在识别出轻击手势时执行,如果点击位置落在图像内,则程序仅响应滚动视图上的点击; 否则,你可以UIScrollView像往常一样滚动你.
在这里,我提出了我的完整解决方案:
这里的界面:
/**
* This subclass of UIScrollView allow views in a deeper Z index to react when touched, even if the scrollview instance is in front of them.
**/
@interface MJForwardingTouchesScrollView : UIScrollView
/**
* Set of Class objects. The scrollview will events pass through if the initial tap is not over a view of the specified classes.
**/
@property (nonatomic, strong) NSSet <Class> *forwardsTouchesToClasses;
/**
* Optional array of underlying views to test touches forward. Default is nil.
* @discussion By default the scroll view will attempt to forward to views located in the same self.superview.subviews array. However, optionally by providing specific views inside this property, the scroll view subclass will check als among them.
**/
@property (nonatomic, strong) NSArray <__kindof UIView*> *underlyingViews;
@end
Run Code Online (Sandbox Code Playgroud)
和实施:
#import "MJForwardingTouchesScrollView.h"
#import "UIView+Additions.h"
@implementation MJForwardingTouchesScrollView
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self != nil)
{
_forwardsTouchesToClasses = [NSSet setWithArray:@[UIControl.class]];
}
return self;
}
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self != nil)
{
_forwardsTouchesToClasses = [NSSet setWithArray:@[UIControl.class]];
}
return self;
}
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
BOOL pointInside = [self mjz_mustCapturePoint:point withEvent:event];
if (!pointInside)
return NO;
return [super pointInside:point withEvent:event];
}
#pragma mark Private Methods
- (BOOL)mjz_mustCapturePoint:(CGPoint)point withEvent:(UIEvent*)event
{
if (![self mjz_mustCapturePoint:point withEvent:event view:self.superview])
return NO;
__block BOOL mustCapturePoint = YES;
[_underlyingViews enumerateObjectsUsingBlock:^(__kindof UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if (![self mjz_mustCapturePoint:point withEvent:event view:obj])
{
mustCapturePoint = NO;
*stop = YES;
}
}];
return mustCapturePoint;
}
- (BOOL)mjz_mustCapturePoint:(CGPoint)point withEvent:(UIEvent *)event view:(UIView*)view
{
CGPoint tapPoint = [self convertPoint:point toView:view];
__block BOOL mustCapturePoint = YES;
[view add_enumerateSubviewsPassingTest:^BOOL(UIView * _Nonnull testView) {
BOOL forwardTouches = [self mjz_forwardTouchesToClass:testView.class];
return forwardTouches;
} objects:^(UIView * _Nonnull testView, BOOL * _Nullable stop) {
CGRect imageFrameInSuperview = [testView.superview convertRect:testView.frame toView:view];
if (CGRectContainsPoint(imageFrameInSuperview, tapPoint))
{
mustCapturePoint = NO;
*stop = YES;
}
}];
return mustCapturePoint;
}
- (BOOL)mjz_forwardTouchesToClass:(Class)class
{
while ([class isSubclassOfClass:NSObject.class])
{
if ([_forwardsTouchesToClasses containsObject:class])
return YES;
class = [class superclass];
}
return NO;
}
@end
Run Code Online (Sandbox Code Playgroud)
唯一使用的额外代码在UIView+Additions.h类别内,其中包含以下方法:
- (void)add_enumerateSubviewsPassingTest:(BOOL (^_Nonnull)(UIView * _Nonnull view))testBlock
objects:(void (^)(id _Nonnull obj, BOOL * _Nullable stop))block
{
if (!block)
return;
NSMutableArray *array = [NSMutableArray array];
[array addObject:self];
while (array.count > 0)
{
UIView *view = [array firstObject];
[array removeObjectAtIndex:0];
if (view != self && testBlock(view))
{
BOOL stop = NO;
block(view, &stop);
if (stop)
return;
}
[array addObjectsFromArray:view.subviews];
}
}
Run Code Online (Sandbox Code Playgroud)
谢谢
| 归档时间: |
|
| 查看次数: |
5874 次 |
| 最近记录: |