@@ -128,8 +128,8 @@ - (void)setHighlighted:(BOOL)highlighted {
128128}
129129
130130- (CGSize)sizeThatFits : (CGSize)size {
131- size.width = fminf (size.width , CGRectGetWidth (self.superviewIfExist .bounds ) - UIEdgeInsetsGetHorizontalValue (self.safetyMarginsOfSuperview ));
132- size.height = fminf (size.height , CGRectGetHeight (self.superviewIfExist .bounds ) - UIEdgeInsetsGetVerticalValue (self.safetyMarginsOfSuperview ));
131+ size.width = fmin (size.width , CGRectGetWidth (self.superviewIfExist .bounds ) - UIEdgeInsetsGetHorizontalValue (self.safetyMarginsOfSuperview ));
132+ size.height = fmin (size.height , CGRectGetHeight (self.superviewIfExist .bounds ) - UIEdgeInsetsGetVerticalValue (self.safetyMarginsOfSuperview ));
133133
134134 CGSize contentLimitSize = [self contentSizeInSize: size];
135135 CGSize contentSize = [self sizeThatFitsInContentView: contentLimitSize];
@@ -185,7 +185,7 @@ - (void)layoutDefaultSubviews {
185185 self.contentView .frame = CGRectMake (self.borderWidth + self.contentEdgeInsets .left , (self.currentLayoutDirection == QMUIPopupContainerViewLayoutDirectionAbove ? self.borderWidth : self.arrowSize .height + self.borderWidth ) + self.contentEdgeInsets .top , CGRectGetWidth (self.bounds ) - self.borderWidth * 2 - UIEdgeInsetsGetHorizontalValue (self.contentEdgeInsets ), CGRectGetHeight (self.bounds ) - self.arrowSize .height - self.borderWidth * 2 - UIEdgeInsetsGetVerticalValue (self.contentEdgeInsets ));
186186 // contentView的圆角取一个比整个path的圆角小的最大值(极限情况下如果self.contentEdgeInsets.left比self.cornerRadius还大,那就意味着contentView不需要圆角了)
187187 // 这么做是为了尽量去掉contentView对内容不必要的裁剪,以免有些东西被裁剪了看不到
188- CGFloat contentViewCornerRadius = fabs (fminf (CGRectGetMinX (self.contentView .frame ) - self.cornerRadius , 0 ));
188+ CGFloat contentViewCornerRadius = fabs (fmin (CGRectGetMinX (self.contentView .frame ) - self.cornerRadius , 0 ));
189189 self.contentView .layer .cornerRadius = contentViewCornerRadius;
190190
191191 BOOL isImageViewShowing = [self isSubviewShowing: _imageView];
@@ -207,37 +207,43 @@ - (void)layoutWithTargetView:(UIView *)targetView {
207207 CGRect targetViewFrameInMainWindow = CGRectZero;
208208 UIWindow *mainWindow = [[[UIApplication sharedApplication ] delegate ] window ];
209209 if (targetView.window == mainWindow) {
210- targetViewFrameInMainWindow = [targetView convertRect: targetView.bounds toView: mainWindow ];
210+ targetViewFrameInMainWindow = [targetView convertRect: targetView.bounds toView: targetView.window ];
211211 } else {
212212 CGRect targetViewFrameInLocalWindow = [targetView convertRect: targetView.bounds toView: targetView.window];
213213 targetViewFrameInMainWindow = [mainWindow convertRect: targetViewFrameInLocalWindow fromWindow: targetView.window];
214214 }
215- [self layoutWithTargetRectInScreenCoordinate : targetViewFrameInMainWindow];
215+ [self layoutWithTargetRect : targetViewFrameInMainWindow inReferenceWindow: targetView.window ];
216216}
217217
218218- (void )layoutWithTargetRectInScreenCoordinate : (CGRect)targetRect {
219+ [self layoutWithTargetRect: targetRect inReferenceWindow: [[[UIApplication sharedApplication ] delegate ] window ]];
220+ }
221+
222+ - (void )layoutWithTargetRect : (CGRect)targetRect inReferenceWindow : (UIWindow *)window {
219223 UIView *superview = self.superviewIfExist ;
224+ BOOL isLayoutInWindowMode = !(self.superview && !self.popupWindow );
225+ CGRect superviewBoundsInWindow = isLayoutInWindowMode ? window.bounds : [superview convertRect: superview.bounds toView: window];
220226
221227 CGSize tipSize = [self sizeThatFits: CGSizeMake (self .maximumWidth, self .maximumHeight)];
222228 CGFloat preferredTipWidth = tipSize.width ;
223229
224230 // 保护tips最往左只能到达self.safetyMarginsOfSuperview.left
225231 CGFloat a = CGRectGetMidX (targetRect) - tipSize.width / 2 ;
226- CGFloat tipMinX = fmaxf ( self.safetyMarginsOfSuperview .left , a);
232+ CGFloat tipMinX = fmax ( CGRectGetMinX (superviewBoundsInWindow) + self.safetyMarginsOfSuperview .left , a);
227233
228234 CGFloat tipMaxX = tipMinX + tipSize.width ;
229- if (tipMaxX + self.safetyMarginsOfSuperview .right > CGRectGetWidth (superview. bounds )) {
235+ if (tipMaxX + self.safetyMarginsOfSuperview .right > CGRectGetMaxX (superviewBoundsInWindow )) {
230236 // 右边超出了
231237 // 先尝试把右边超出的部分往左边挪,看是否会令左边到达临界点
232- CGFloat distanceCanMoveToLeft = tipMaxX - (CGRectGetWidth (superview. bounds ) - self.safetyMarginsOfSuperview .right );
233- if (tipMinX - distanceCanMoveToLeft >= self.safetyMarginsOfSuperview .left ) {
238+ CGFloat distanceCanMoveToLeft = tipMaxX - (CGRectGetMaxX (superviewBoundsInWindow ) - self.safetyMarginsOfSuperview .right );
239+ if (tipMinX - distanceCanMoveToLeft >= CGRectGetMinX (superviewBoundsInWindow) + self.safetyMarginsOfSuperview .left ) {
234240 // 可以往左边挪
235241 tipMinX -= distanceCanMoveToLeft;
236242 } else {
237243 // 不可以往左边挪,那么让左边靠到临界点,然后再把宽度减小,以让右边处于临界点以内
238- tipMinX = self.safetyMarginsOfSuperview .left ;
239- tipMaxX = CGRectGetWidth (superview. bounds ) - self.safetyMarginsOfSuperview .right ;
240- tipSize.width = fminf (tipSize.width , tipMaxX - tipMinX);
244+ tipMinX = CGRectGetMinX (superviewBoundsInWindow) + self.safetyMarginsOfSuperview .left ;
245+ tipMaxX = CGRectGetMaxX (superviewBoundsInWindow ) - self.safetyMarginsOfSuperview .right ;
246+ tipSize.width = fmin (tipSize.width , tipMaxX - tipMinX);
241247 }
242248 }
243249
@@ -255,9 +261,9 @@ - (void)layoutWithTargetRectInScreenCoordinate:(CGRect)targetRect {
255261
256262 if (!canShowAtAbove && !canShowAtBelow) {
257263 // 上下都没有足够的空间,所以要调整maximumHeight
258- CGFloat maximumHeightAbove = CGRectGetMinY (targetRect) - self.distanceBetweenTargetRect - self.safetyMarginsOfSuperview .top ;
259- CGFloat maximumHeightBelow = CGRectGetHeight (superview. bounds ) - self.safetyMarginsOfSuperview .bottom - self.distanceBetweenTargetRect - CGRectGetMaxY (targetRect);
260- self.maximumHeight = fmaxf (self.minimumHeight , fmaxf (maximumHeightAbove, maximumHeightBelow));
264+ CGFloat maximumHeightAbove = CGRectGetMinY (targetRect) - CGRectGetMinY (superviewBoundsInWindow) - self.distanceBetweenTargetRect - self.safetyMarginsOfSuperview .top ;
265+ CGFloat maximumHeightBelow = CGRectGetMaxY (superviewBoundsInWindow ) - self.safetyMarginsOfSuperview .bottom - self.distanceBetweenTargetRect - CGRectGetMaxY (targetRect);
266+ self.maximumHeight = fmax (self.minimumHeight , fmax (maximumHeightAbove, maximumHeightBelow));
261267 tipSize.height = self.maximumHeight ;
262268 _currentLayoutDirection = maximumHeightAbove > maximumHeightBelow ? QMUIPopupContainerViewLayoutDirectionAbove : QMUIPopupContainerViewLayoutDirectionBelow;
263269
@@ -273,15 +279,26 @@ - (void)layoutWithTargetRectInScreenCoordinate:(CGRect)targetRect {
273279
274280 // 当上下的剩余空间都比最小高度要小的时候,tip会靠在safetyMargins范围内的上(下)边缘
275281 if (_currentLayoutDirection == QMUIPopupContainerViewLayoutDirectionAbove) {
276- CGFloat tipMinYIfAlignSafetyMarginTop = self.safetyMarginsOfSuperview .top ;
277- tipMinY = fmaxf (tipMinY, tipMinYIfAlignSafetyMarginTop);
282+ CGFloat tipMinYIfAlignSafetyMarginTop = CGRectGetMinY (superviewBoundsInWindow) + self.safetyMarginsOfSuperview .top ;
283+ tipMinY = fmax (tipMinY, tipMinYIfAlignSafetyMarginTop);
278284 } else if (_currentLayoutDirection == QMUIPopupContainerViewLayoutDirectionBelow) {
279- CGFloat tipMinYIfAlignSafetyMarginBottom = CGRectGetHeight (superview. bounds ) - self.safetyMarginsOfSuperview .bottom - tipSize.height ;
280- tipMinY = fminf (tipMinY, tipMinYIfAlignSafetyMarginBottom);
285+ CGFloat tipMinYIfAlignSafetyMarginBottom = CGRectGetMaxY (superviewBoundsInWindow ) - self.safetyMarginsOfSuperview .bottom - tipSize.height ;
286+ tipMinY = fmin (tipMinY, tipMinYIfAlignSafetyMarginBottom);
281287 }
282288
289+ // 上面计算得出的 tipMinX、tipMinY 是处于 window 坐标系里的,而浮层可能是以 addSubview: 的方式显示在某个 superview 上,所以要做一次坐标系转换
290+ CGPoint origin = CGPointMake (tipMinX, tipMinY);
291+ origin = [window convertPoint: origin toView: superview];
292+ tipMinX = origin.x ;
293+ tipMinY = origin.y ;
294+
283295 self.frame = CGRectFlatMake (tipMinX, tipMinY, tipSize.width , tipSize.height );
284- [self setArrowMinXWithLayoutTargetCenter: CGPointMake (CGRectGetMidX (targetRect), CGRectGetMidY (targetRect))];
296+
297+ // 调整浮层里的箭头的位置
298+ CGPoint targetRectCenter = CGPointMake (CGRectGetMidX (targetRect), CGRectGetMidY (targetRect));
299+ CGFloat selfMidX = targetRectCenter.x - (CGRectGetMinX (superviewBoundsInWindow) + CGRectGetMinX (self.frame ));
300+ _arrowMinX = selfMidX - self.arrowSize .width / 2 ;
301+ [self setNeedsLayout ];
285302
286303 if (self.debug ) {
287304 self.contentView .backgroundColor = UIColorTestGreen;
@@ -313,13 +330,6 @@ - (BOOL)canTipShowAtSpecifiedLayoutDirect:(QMUIPopupContainerViewLayoutDirection
313330 return canShow;
314331}
315332
316- // 根据布局时需要对准的中心点去调整箭头的水平坐标x
317- - (void )setArrowMinXWithLayoutTargetCenter : (CGPoint)layoutReferenceTargetCenter {
318- CGFloat selfMidX = layoutReferenceTargetCenter.x - CGRectGetMinX (self.frame );// 将 superview 坐标系里的 layoutReferenceTargetCenter 转换到 self 坐标系里的 point(因为有时候 self.superview 可能为空,无法进行 convertPoint 的计算)
319- _arrowMinX = selfMidX - self.arrowSize .width / 2 ;
320- [self setNeedsLayout ];
321- }
322-
323333- (void )showWithAnimated : (BOOL )animated {
324334 [self showWithAnimated: animated completion: nil ];
325335}
@@ -461,13 +471,13 @@ - (CGSize)contentSizeInSize:(CGSize)size {
461471// / 根据内容大小和外部限制的大小,计算出合适的self size(包含箭头)
462472- (CGSize)sizeWithContentSize : (CGSize)contentSize sizeThatFits : (CGSize)sizeThatFits {
463473 CGFloat resultWidth = contentSize.width + UIEdgeInsetsGetHorizontalValue (self.contentEdgeInsets ) + self.borderWidth * 2 ;
464- resultWidth = fminf (resultWidth, sizeThatFits.width );// 宽度不能超过传进来的size.width
465- resultWidth = fmaxf ( fminf (resultWidth, self.maximumWidth ), self.minimumWidth );// 宽度必须在最小值和最大值之间
474+ resultWidth = fmin (resultWidth, sizeThatFits.width );// 宽度不能超过传进来的size.width
475+ resultWidth = fmax ( fmin (resultWidth, self.maximumWidth ), self.minimumWidth );// 宽度必须在最小值和最大值之间
466476 resultWidth = ceil (resultWidth);
467477
468478 CGFloat resultHeight = contentSize.height + UIEdgeInsetsGetVerticalValue (self.contentEdgeInsets ) + self.arrowSize .height + self.borderWidth * 2 ;
469- resultHeight = fminf (resultHeight, sizeThatFits.height );
470- resultHeight = fmaxf ( fminf (resultHeight, self.maximumHeight ), self.minimumHeight );
479+ resultHeight = fmin (resultHeight, sizeThatFits.height );
480+ resultHeight = fmax ( fmin (resultHeight, self.maximumHeight ), self.minimumHeight );
471481 resultHeight = ceil (resultHeight);
472482
473483 return CGSizeMake (resultWidth, resultHeight);
@@ -513,10 +523,10 @@ - (CGSize)sizeThatFitsInContentView:(CGSize)size {
513523 CGSize textLabelLimitSize = CGSizeMake (size.width - resultSize.width - self.imageEdgeInsets .right , size.height );
514524 CGSize textLabelSize = [_textLabel sizeThatFits: textLabelLimitSize];
515525 resultSize.width += (isImageViewShowing ? self.imageEdgeInsets .right : 0 ) + ceil (textLabelSize.width ) + self.textEdgeInsets .left ;
516- resultSize.height = fmaxf (resultSize.height , ceil (textLabelSize.height ) + self.textEdgeInsets .top );
526+ resultSize.height = fmax (resultSize.height , ceil (textLabelSize.height ) + self.textEdgeInsets .top );
517527 }
518- resultSize.width = fminf (size.width , resultSize.width );
519- resultSize.height = fminf (size.height , resultSize.height );
528+ resultSize.width = fmin (size.width , resultSize.width );
529+ resultSize.height = fmin (size.height , resultSize.height );
520530 return resultSize;
521531}
522532
0 commit comments