如何获取部分平移到屏幕外的 UIView 的可见部分?

Posted

技术标签:

【中文标题】如何获取部分平移到屏幕外的 UIView 的可见部分?【英文标题】:How do I get the visible portion of a UIView that is partially panned off the screen? 【发布时间】:2018-09-27 02:00:39 【问题描述】:

我有一个 UIView,我用平移手势移动到屏幕的一侧,现在 UIView 仅部分显示在屏幕上。如何在原始视图的坐标中获取仅包含 UIView 可见部分的 CGRect?

我尝试将CGRectIntersect() 组合成UIView.frame 矩形和[UIScreen mainscreen].bounds 矩形,如下所示:

CGRect rect = CGRectIntersection([UIScreen mainScreen].bounds,
                                 view.frame);

我无法正确解决坐标系匹配问题。

【问题讨论】:

你可以尝试使用CGRectIntersection(view.frame, [UIScreen mainScreen].bounds); @QuocNguyen 如果视图嵌套在更多视图中,这些视图的位移可能与 viewController 的视图不同,这可能不起作用。 :) “我无法正确解决匹配坐标系的问题。”你已经完全理解了这个问题!这就是此方法的用途:developer.apple.com/documentation/uikit/uiview/… 使用它将您的矩形置于同一坐标系中,然后然后将它们相交。 【参考方案1】:

您首先需要将置换视图的 CGRect 转换到主屏幕的坐标系。

你可以试试

if let mainVC = UIApplication.shared.keyWindow?.rootViewController 
        let translatedRect = mainVC.view.convert(myTestView.frame, from: view)
        let intersection = translatedRect.intersection(mainVC.view.frame)

这首先找到主rootViewController,并将您的视图框架转换为rootViewController的坐标系,然后找到交点。即使您的置换视图嵌套在多层视图中,这也可以工作。

【讨论】:

感谢 UIApplication rootViewController 提示。我用那个。但我确实要求使用 Objective C,并且我希望结果 rect 位于目标视图的坐标中。 @ByteSlinger 我认为翻译成 Obj-C 应该没有那么难。 :) 您可以通过相同的convert 函数将其转换回destinationView。像destinationView.convert(intersection, from:mainVC.view) 这样的东西。总是乐于助人。 :)【参考方案2】:

经过一些(数小时)的实验,我想出了这个解决方案:

// return the part of the passed view that is visible
- (CGRect)getVisibleRect:(UIView *)view 
    // get the root view controller (and it's view is vc.view)
    UIViewController *vc = UIApplication.sharedApplication.keyWindow.rootViewController;

    // get the view's frame in the root view's coordinate system
    CGRect frame = [vc.view convertRect:view.frame fromView:view.superview];

    // get the intersection of the root view bounds and the passed view frame
    CGRect intersection = CGRectIntersection(vc.view.bounds, frame);

    // adjust the intersection coordinates thru any nested views
    UIView *loopView = view;
    do 
        intersection = [loopView convertRect:intersection fromView:loopView.superview];

        loopView = loopView.superview;
     while (loopView != vc.view);

    return intersection; // may be same as the original view frame

我首先尝试将根视图转换为目标视图的坐标,然后在视图框架上执行 CGRectIntersect,但没有成功。但是我让它以相反的方式为 UIViews 以根视图作为它们的父视图。然后经过一番探索,我发现我必须通过视图层次结构导航子视图。

它适用于超级视图是根视图的 UIView,也适用于作为其他视图的子视图的 UIView。

我通过在初始视图上围绕这些可见矩形绘制边框对其进行了测试,并且效果很好。

但是...如果 UIView 被缩放 (!=1) 和另一个 UIView 的子视图而不是根视图,它就不能正常工作。结果可见矩形的原点偏移了一点。如果视图位于子视图中,我尝试了几种不同的方法来调整原点,但我无法找到一种干净的方法。

我已将此方法添加到我的实用程序 UIView 类别中,以及我一直在开发或获取的所有其他“缺失”的 UIView 方法。 (Erica Sadun的变换方法……我不配……)

这确实解决了我正在解决的问题。所以我将发布另一个关于缩放问题的问题。

编辑: 在处理扩展问题的问答时,我也为这个问题想出了一个更好的答案:

// return the part of the passed view that is visible
- (CGRect)getVisibleRect:(UIView *)view 
    // get the root view controller (and it's view is vc.view)
    UIViewController *vc = UIApplication.sharedApplication.keyWindow.rootViewController;

    // get the view's frame in the root view's coordinate system
    CGRect rootRect = [vc.view convertRect:view.frame fromView:view.superview];

    // get the intersection of the root view bounds and the passed view frame
    CGRect rootVisible = CGRectIntersection(vc.view.bounds, rootRect);

    // convert the rect back to the initial view's coordinate system
    CGRect visible = [view convertRect:rootVisible fromView:vc.view];

    return visible; // may be same as the original view frame

【讨论】:

以上是关于如何获取部分平移到屏幕外的 UIView 的可见部分?的主要内容,如果未能解决你的问题,请参考以下文章

VoiceOver不能在横向滚动到屏幕外的元素?

父视图外的 UIView 阴影

如何以全分辨率从 UIImageView 获取旋转、缩放和平移的图像?

使用平移手势在屏幕的有限区域中移动 UIView

如何让我的 UIView 在 Xcode 的 Storyboard 编辑器中可见?

视图不在屏幕时的 UIView 动画 alpha 不起作用