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

Detecting visibility percentage of a UIView in iOS views

提问人:TonyW 提问时间:9/26/2022 更新时间:9/27/2022 访问量:255

问:

我需要确定目标 UIView 对象在屏幕上是否可见。从我的研究来看,似乎共识是检查 UIView 对象的属性是否是 .但这只能部分解决我的问题,因为一个视图可能会被它上面的另一个视图对象部分阻止。例如:windowkeyWindow

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

gray view is blocked partially by the blue view

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

  1. 获取顶部的 UIWindow 对象:
    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

  2. 将 targetView 的帧及其后的所有子视图转换为 的坐标,用于检测是否存在交集。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);
                    }
                }

   }

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

iOS Objective-C UIView 交集 重叠

评论


答:

0赞 TonyW 9/27/2022 #1

在我的算法上花了更多的时间后,我终于意识到为什么它对我不起作用,因为使用数据结构遍历视图层次结构的方式会比 .因此,在以下行中进行更改后,可见性百分比的计算对我有用:stackblocking 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