【问题标题】:UIScrollView with touch interceptor for contentSize to control subviewsUIScrollView 与 contentSize 的触摸拦截器来控制子视图
【发布时间】:2015-01-19 13:48:54
【问题描述】:

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

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

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

第一个实验:

我尝试向覆盖 UIScrollView 的 ViewController 添加一个透明的 UIView。 但是,即使直接引用 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 已解决。我没有为平移/捏合手势设置正确的代表。哦!

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

【问题讨论】:

  • 您是否尝试过UIScrollView 缩放功能。它默认支持缩放,你只需要提供将被缩放的视图,所以我认为你只需要确定屏幕上的视图并将其传递给UIScrollView
  • 在 UIScrollView 中缩放似乎更像是一种简单地缩放 UIScrollView 的子视图的解决方案,从而修改它们的大小。不过,这不是我要找的。尺寸必须保持不变,因为只有我的 UIView 的内容需要更改,而这又由 ShinobiChart 本身处理。

标签: ios objective-c uiview uiscrollview uigesturerecognizer


【解决方案1】:

您可以在其他视图之上放置一个透明视图。但是,您需要覆盖另外一种方法。

您想在透明视图上覆盖 hitTest:withEvent。在遍历响应者链以查看哪个视图处理特定区域中的触摸时使用此方法。如果视图处理了该触摸,它会返回它自己。如果它想将它传递给它下面的下一个视图,它会返回 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

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

【讨论】:

  • 不幸的是,这不起作用。 View1 没有收到触摸。 UIScrollView 是否有可能阻止它们?
  • 我刚刚尝试在滚动视图顶部放置一个“拦截器”视图。似乎工作 - 我做了一个示例项目。 (见编辑的答案)
  • 您在 Github 上的项目不包含任何源代码。我的代码看起来确实和你的一模一样,事实上,它的工作方式是 touchesBegan/Moved 在 TargetView 的子类中被调用(我不能直接更改 TargetView,因为它是第三方库的一部分。事情是,我需要 TargetView 来获取手势,这不适用于这种触摸转发方法,或者至少不适用于现在提供的代码。
  • 糟糕!好的,源现在在那里。我认为不同之处在于我明确地创建了另一个手势识别器(在这种情况下通过情节提要),并将其附加到 targetView。我不确定在响应者链中的哪个位置调用 touchesBegan,但手势识别器完全跳过了响应者链。所以,他们拿起一切。 (我想......我自己还是有点模糊)查看源代码(现在它确实存在!)
  • 好吧,我的 TargetView 中的其他手势识别器也会被调用,就像在您的示例中一样。现在的问题是 TargetView 的 superview (ShinobiChart) 没有拾取它们。直接设置 ShinobiChart 而不是使用子类具有相同的效果。好吧,我想这是这个控件特有的问题,对吧?我的意思是对于自定义类,手势被正确拾取,所以你的答案实际上是正确的。感谢那。从这里开始,我想我得回到 shinobicontrols 那边的人那里了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多