带有触摸拦截器的UIScrollView,用于控制子视图的contentSize

时间:2014-11-21 12:02:07

标签: ios objective-c uiview uiscrollview uigesturerecognizer

假设我有以下视图层次结构;

enter image description here

这些视图实际上是ShinobiCharts,它们是UIView的子类。 View1充当用户可以触摸的主图表(捏,平移,长按等)。该视图依次控制其他视图(View2,View3等)与特定的依赖于触摸的属性(用户平移View1,因此视图2和3 ......必须相应地操作并平移)。 但是,一旦用户滚动UIScrollView,View1可能会从屏幕上消失,只留下视图2,3等可见,这些视图没有相应的手势识别器,因此用户无法再与图表交互,不好用户体验。 我确定也可以为这些附加图表添加识别器,但是在收缩期间,这意味着两个手指必须位于单个视图内,用户不能只是触摸他想要的位置以便再次捏合和缩放,糟糕的用户体验。

简而言之,我需要某种覆盖UIScrollView整个内容区域的触摸拦截器,以便当用户捏或平移时,相应的触摸将被转发到主图表(View1),而这反过来可以更新其他子视图。 应始终可以垂直滚动UIScrollView。

第一次实验:

我尝试将透明的UIView添加到覆盖UIScrollView的ViewController。 但是,即使直接引用View1,触摸也不会被转发。

-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [self.chartReference touchesBegan:touches withEvent:event];
}

我不确定这是否是实现此目的的正确方法。

第二次实验:

在UIScrollView中禁用图表子视图上的userInteraction,并将我自己的捏合和平移手势(在UIViewController中)添加到UIScrollView。

有关的问题;  1. UIScrollView不再滚动。  2.如何将这些手势转发到View1?

我担心此时无法提供更多示例代码,因为还没有太多相关代码可供展示。

修改 实验二小注; 手势识别器已添加如下;

UIPinchGestureRecognizer *pinchGestureRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchGesture:)];
pinchGestureRecognizer.cancelsTouchesInView = NO;
[scrollView addGestureRecognizer:pinchGestureRecognizer];

已启用UIViewController上的同时手势识别;

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;

}

修改

实验2的问题2已经解决。我没有为pan / pinch手势设置正确的委托。 D'哦!

剩下的是如何转发捏/手势。

1 个答案:

答案 0 :(得分:1)

您可以将透明视图置于其他视图之上。但是,您需要重写一个方法。

您想要在透明视图上覆盖hitTest:withEvent。遍历响应者链时使用此方法以查看哪个视图处理特定区域中的触摸。如果视图处理该触摸,则返回Itself。如果它想将它传递给它下面的下一个视图,它将返回nil。如果它知道另一个视图处理触摸,它可以返回该视图。

因此,在您的情况下,如果该点位于顶部透明视图的目标区域中,则返回view1。然后应该调用View1的手势识别器。

示例

InterceptorView是一个位于scrollView顶部的透明视图。 TargetView是scrollView中的一个视图,并附有一个TapGestureRecognizer。

class InterceptorView: UIView {

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    @IBOutlet weak var targetView1: UIView?

    override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
        print("[Interceptor] Testing point: \(point) ")
        if self.pointInside(point, withEvent: event) {
            println("Hit")
            return targetView1
        }
        else {
            println()
            return nil;
        }
    }
}

-

class TargetView: UIView {

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

     @IBAction func handleGesture(gestureRecognizer: UIGestureRecognizer) {
        let location = gestureRecognizer.locationInView(self)
        print("[TargetView] Got gesture.  Location \(location) ")
        if (pointInside(location, withEvent: nil)) {
            println("Inside");
        }
        else {
            println("Outside");
        }
    }
}

这是项目: https://github.com/annabd351/GestureForwarding

(那里还有一些其他东西,但它有效!)