一.官方sdk實現(xiàn)方法.
iOS中將一個view的frame轉(zhuǎn)換為基于屏幕坐標的方法,蘋果提供了一下sdk.
- (CGPoint)convertPoint:(CGPoint)point toView:(nullable UIView *)view;
- (CGPoint)convertPoint:(CGPoint)point fromView:(nullable UIView *)view;
- (CGRect)convertRect:(CGRect)rect toView:(nullable UIView *)view;
- (CGRect)convertRect:(CGRect)rect fromView:(nullable UIView *)view;

image.png

image.png
官方sdk實現(xiàn)的時候,對于由哪個view調(diào)用方法,point參數(shù)需要傳入什么,view參數(shù)需要傳入什么很是費解.
看了官方的描述之后理解如下:
- [receiver convertRect:rect toView:view];
- 將一個從receiver的對應系統(tǒng)中的rect區(qū)域,轉(zhuǎn)換成為其他的view的坐標.
- [receiver convertRect:rect fromView:view];
- 將另外一個view的對應系統(tǒng)的rect區(qū)域,轉(zhuǎn)換成receiver的區(qū)域.
1.首先方法的調(diào)用者,叫做方法(消息)的接受者,receiver.
2.第一個參數(shù)rect應該是這個view自己內(nèi)部的一塊區(qū)域,這塊區(qū)域如果你想是view自己本身,那么就是用view.bounds,如果你想是他內(nèi)部的一塊空間,你可以自己指定.但是切忌使用self.frame,那么基本上算出來的就是錯誤的結果.
3.第三個參數(shù)是目標view,如果你想把view轉(zhuǎn)成receiver里面的坐標,請用- [receiver convertRect:rect fromView:view];
如果你想把view的坐標轉(zhuǎn)成reciever里面的坐標,請用- [receiver convertRect:rect toView:view];
舉個例子:把當前view的坐標轉(zhuǎn)換成window的坐標,就有一下兩種寫法:(傳入nil表示當前window)
CGRect frame2 = [view convertRect:view.bounds toView:nil];
CGRect frame3 = [[UIApplication sharedApplication].keyWindow convertRect:view.bounds fromView:view];
二.自己的遞歸實現(xiàn)
之前在需求中一直需要這個功能,針對于蘋果提供的sdk計算一直有問題,苦于對蘋果一下接口的不了解.實現(xiàn)了一個自己遞歸的實現(xiàn)版本.
/**
* 計算一個view相對于屏幕的坐標
*/
- (CGRect)relativeFrameForScreenWithView
{
UIView *view = self;
CGFloat x = .0;
CGFloat y = .0;
while (view != [UIApplication sharedApplication].keyWindow && nil != view) {
x += view.frame.origin.x;
y += view.frame.origin.y;
view = view.superview;
if ([view isKindOfClass:[UIScrollView class]]) {
x -= ((UIScrollView *) view).contentOffset.x;
y -= ((UIScrollView *) view).contentOffset.y;
}
}
return CGRectMake(x, y, self.frame.size.width, self.frame.size.height);
}
三.另外附上一個方法,計算當前view是否在屏幕內(nèi).
/**
* 判斷View是否顯示在屏幕上
*/
- (BOOL)isDisplayedInScreen
{
if (self == nil) {
return NO;
}
CGRect screenRect = [UIScreen mainScreen].bounds;
// 轉(zhuǎn)換view對應window的Rect
CGRect rect = [self convertRect:self.bounds toView:nil];
if (CGRectIsEmpty(rect) || CGRectIsNull(rect)) {
return NO;
}
// 若view 隱藏
if (self.hidden) {
return NO;
}
// 若沒有superview
if (self.superview == nil) {
return NO;
}
// 若size為CGrectZero
if (CGSizeEqualToSize(rect.size, CGSizeZero)) {
return NO;
}
// 獲取 該view與window 交叉的 Rect
CGRect intersectionRect = CGRectIntersection(rect, screenRect);
if (CGRectIsEmpty(intersectionRect) || CGRectIsNull(intersectionRect)) {
return NO;
}
return YES;
}