繁体   English   中英

在 iOS 视图中检测 UIView 的可见性百分比

[英]Detecting visibility percentage of a UIView in iOS views

我需要找出目标 UIView object 在屏幕上是否可见。 根据我的研究,似乎共识是检查 UIView object 的window属性是否是keyWindow 但这只是部分解决了我的问题,因为一个视图可能被另一个视图 object 部分阻塞。 例如:

灰色正方形的一半被蓝色矩形遮挡,因此灰色正方形对用户的可见度为 50%。

灰色视图被蓝色视图部分遮挡

我正在研究的解决方案基本上如下,但它并不完全正确:

  1. 获取顶部的 UIWindow object:
    UIWindow *topWindow = [[[UIApplication sharedApplication].windows sortedArrayUsingComparator:^NSComparisonResult (UIWindow *win1, UIWindow *win2) {
    if (win1.windowLevel < win2.windowLevel) {
        return NSOrderedAscending;
    } else if (win1.windowLevel > win2.windowLevel) {
        return NSOrderedDescending;
    }
        return NSOrderedSame;
    }] firstObject];

  1. 然后遍历topWindow的所有子视图,找到我的目标视图object之后的所有子视图:

  2. 将 targetView 的 frame 和它之后的所有 subview 转换为topWindow的坐标,用于检测是否有交集。

NSMutableArray *stack = [[NSMutableArray alloc] initWithArray:topWindow.subviews];
UIView *targetView = nil;
NSInteger targetViewTag = 10;
NSMutableArray *postViews = [NSMutableArray array]; // views detected after targetView, used for detection overlap with targetView

while ([stack count] > 0) {
            UIView *curr = [stack lastObject];
            [stack removeObject:curr];

            if (curr.isHidden || curr.window == nil) {
                continue;
            }

            if (curr.tag == targetViewTag) {
                targetView = curr;
            } else if (targetView) {
                [postViews addObject:curr];
            }

            for (UIView *sub in [curr subviews]) {
              [stack addObject:sub];
            }
        }

    // if targetView is found:
    if (targetView) {
      float visiblePercentage = 100;

      for (UIView *pw in postViews) {
                    // convert frames to topWindow for detecting intersection
                    CGRect swFrame = [targetView convertRect:targetView.frame toView:topWindow];
                    CGRect pwFrame = [pw convertRect:pw.frame toView:topWindow];
                    
                    if (CGRectIntersectsRect(swFrame, pwFrame)) {
                        CGRect intersection = CGRectIntersection(swFrame, pwFrame);

                        CGFloat intersectArea = intersection.size.width * intersection.size.height;
                        CGFloat swArea = swFrame.size.width * swFrame.size.height;
                        // update visiblePercentage
                        visiblePercentage = visiblePercentage - (100 * intersectArea / swArea);
                    }
                }

   }

我不确定将不同子视图中的视图帧转换为topWindow坐标是否是个好主意,但是visiblePercentage看起来不正确,因为它给了我负数。 任何人都有更好的方法来计算部分/完全被阻止的视图的可见百分比? 谢谢!

在我的算法上花了更多时间后,我终于意识到为什么它对我不起作用,因为使用stack数据结构遍历视图层次结构的方式会使blocking viewstargetView更快地从堆栈中弹出。 因此,在以下行中进行更改后,可见性百分比的计算对我有用:


while ([stack count] > 0) {
            UIView *curr = [stack lastObject];
            [stack removeObject:curr];

            if (curr.isHidden || curr.window == nil) {
                continue;
            }

            if (curr.tag == targetViewTag) {
                targetView = curr;
            } else if (targetView == nil) { // NOTE: correct this line from else if (targetView)
                [postViews addObject:curr];
            }

            for (UIView *sub in [curr subviews]) {
              [stack addObject:sub];
            }
        }

堆栈数据结构首先在我的targetView顶部弹出这些视图,这是解决我的问题的技巧。 无论如何,感谢您的关注:)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM