例子1
Controller的view中有一個tableView,tableView的cell上有一個button,現在需要將button的frame轉為在Controller的view中的frame,怎么實現呢?
CGRect rect = [self.view convertRect:_button.frame fromView:_button.superview];
CGRect rect = [_button.superview convertRect:_button.frame toView:self.view];
注意1.
button的frame是相對於其superview來確定的,frame確定了button在其superview的位置和大小
注意2.
現在轉換后,我們肉眼觀察到的,所有屏幕上的控件的布局並不會改變,但是此時以上兩個方法返回的frame代表着,button在self.view上的大小和位置
注意3.
這里應該使用的是_button.frame而不能是_button.bounds
注意4.
這里2個方法是可逆的,2個方法的區別就是消息的接收者和view參數顛倒
注意5.
這里_button雖然是在tableView上的,但是不能寫toView的消息接收者不能是tableView,因為_button的superview並不是tableView
注意6.
注意理解消息的接收者,即第一行代碼的self.view和第二行代碼的_button.superview
一般來說,toView方法中,消息的接收者為被轉換的frame所在的控件的superview;fromView方法中,消息的接收者為即將轉到的目標view
注意7.
涉及的所有view的UIWindow必須是同一個對象!否則轉換失敗
例子2
現在需要將一個觸摸事件的點screenPoint(觸摸事件的點的坐標系是相對於當前的屏幕——UIWindow),轉化為屏幕里某個tableView上的點。即我想知道,我現在觸摸的屏幕位置,是在這個tableView的什么位置上
CGPoint tablePT = [_tableView convertPoint:screenPoint fromView:nil];
注意1.
當參數view為nil的時候,系統會自動幫你轉換為當前窗口的基本坐標系(即view參數為整個屏幕,原點為(0,0),寬高是屏幕的寬高)
注意2.
當view不為nil的時候,消息的接收者和參數view都必須是在同一個UIWindow對象里
If view is nil, this method instead converts to window base coordinates. Otherwise, both view and the receiver must belong to the same UIWindow object.
例子3
responseDragbackAtScreenPoint方法用於判斷是否響應橫滑返回消息,screenPoint是觸摸事件的點
現在tableView上的cell中有一個橫滑列表(UIScrollView),現在需要判斷觸摸點是否在UIScrollView的區域上,再根據其他條件判斷是否需要橫滑返回

- (BOOL)responseDragbackAtScreenPoint:(CGPoint)screenPoint { //將當前觸摸點轉化為tableView上的點 CGPoint tablePT = [tableView convertPoint:screenPoint fromView:nil]; //根據tableView上的點定位到當前點的IndexPath NSIndexPath *pathIndex = [tableView indexPathForRowAtPoint:tablePT]; //根據IndexPath找到當前觸摸位置的cell UITableViewCell *cell = [tableView cellForRowAtIndexPath:pathIndex]; //遍歷該cell上的所有subView NSArray *subViews = [cell.contentView subviews]; for (UIView *itemView in subViews) { //找打當前cell上的UIScrollView,目前業務上只有1個 if ([itemView isKindOfClass:[UIScrollView class]]) { UIScrollView *itemScrollView = (UIScrollView *)itemView; //將當前的scrollView的frame轉為相對於整個屏幕上的frame CGRect rc = [itemScrollView.superview convertRect:itemScrollView.frame toView:nil]; //因為screenPoint和rc是同一個坐標系下的,所以可以用來判斷screenPoint是否在rc的區域內 //1.當scrollView的cell超過屏幕的時候 2.當觸摸點在scrollView的區域上的時候 3.當不是以下情況:scrollView還未被滑動的時候手指在上面向右滑 1.2.3都滿足的情況下才不響應橫滑返回 if (itemScrollView.contentSize.width > itemScrollView.width && CGRectContainsPoint(rc, screenPoint) && !(itemScrollView.contentOffset.x == -itemScrollView.contentInset.left)) return NO; } } return YES; }
匯總
iOS中,常用的坐標轉換和frame轉換如下:
// 將像素point由point所在視圖轉換到目標視圖view中,返回在目標視圖view中的像素值 - (CGPoint)convertPoint:(CGPoint)point toView:(UIView *)view; // 將像素point從view中轉換到當前視圖中,返回在當前視圖中的像素值 - (CGPoint)convertPoint:(CGPoint)point fromView:(UIView *)view; // 將rect由rect所在視圖轉換到目標視圖view中,返回在目標視圖view中的rect - (CGRect)convertRect:(CGRect)rect toView:(UIView *)view; // 將rect從view中轉換到當前視圖中,返回在當前視圖中的rect - (CGRect)convertRect:(CGRect)rect fromView:(UIView *)view;