Skip to content

Commit fa69303

Browse files
committed
Merge commit '0c079a21b3d03df23ba9779151e06d4971842c3c'
2 parents 4873044 + 0c079a2 commit fa69303

9 files changed

Lines changed: 175 additions & 42 deletions

File tree

QMUI/QMUIKit.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Pod::Spec.new do |s|
22
s.name = "QMUIKit"
3-
s.version = "1.3.1"
3+
s.version = "1.3.2"
44
s.summary = "致力于提高项目 UI 开发效率的解决方案"
55
s.description = <<-DESC
66
QMUI iOS 是一个致力于提高项目 UI 开发效率的解决方案,其设计目的是用于辅助快速搭建一个具备基本设计还原效果的 iOS 项目,同时利用自身提供的丰富控件及兼容处理, 让开发者能专注于业务需求而无需耗费精力在基础代码的设计上。不管是新项目的创建,或是已有项目的维护,均可使开发效率和项目质量得到大幅度提升。

QMUI/QMUIKit/UIComponents/QMUIDialogViewController.m

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,10 @@ - (void)initFooterViewIfNeeded {
290290
}
291291

292292
- (void)addCancelButtonWithText:(NSString *)buttonText block:(void (^)(QMUIDialogViewController *))block {
293+
if (_cancelButton) {
294+
[_cancelButton removeFromSuperview];
295+
}
296+
293297
_cancelButton = [self generateButtonWithText:buttonText];
294298
[self.cancelButton addTarget:self action:@selector(handleCancelButtonEvent:) forControlEvents:UIControlEventTouchUpInside];
295299

@@ -301,6 +305,10 @@ - (void)addCancelButtonWithText:(NSString *)buttonText block:(void (^)(QMUIDialo
301305
}
302306

303307
- (void)addSubmitButtonWithText:(NSString *)buttonText block:(void (^)(QMUIDialogViewController *dialogViewController))block {
308+
if (_submitButton) {
309+
[_submitButton removeFromSuperview];
310+
}
311+
304312
_submitButton = [self generateButtonWithText:buttonText];
305313
[self.submitButton addTarget:self action:@selector(handleSubmitButtonEvent:) forControlEvents:UIControlEventTouchUpInside];
306314

QMUI/QMUIKit/UIComponents/QMUIModalPresentationViewController.m

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,7 @@ - (void)hidingAnimationWithCompletion:(void (^)(BOOL))completion {
416416
self.contentView.transform = CGAffineTransformMakeScale(0.0, 0.0);
417417
} completion:^(BOOL finished) {
418418
if (completion) {
419+
self.contentView.transform = CGAffineTransformIdentity;
419420
completion(finished);
420421
}
421422
}];
@@ -425,6 +426,7 @@ - (void)hidingAnimationWithCompletion:(void (^)(BOOL))completion {
425426
self.contentView.transform = CGAffineTransformMakeTranslation(0, CGRectGetHeight(self.view.bounds) - CGRectGetMinY(self.contentView.frame));
426427
} completion:^(BOOL finished) {
427428
if (completion) {
429+
self.contentView.transform = CGAffineTransformIdentity;
428430
completion(finished);
429431
}
430432
}];

QMUI/QMUIKit/UIComponents/QMUIPopupContainerView.m

Lines changed: 44 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -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

QMUI/QMUIKit/UIKitExtensions/UIButton+QMUI.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,12 @@
1818
*/
1919
- (void)qmui_calculateHeightAfterSetAppearance;
2020

21+
/**
22+
* 通过这个方法设置了 attributes 之后,setTitle:forState: 会自动把文字转成 attributedString 再添加上去,无需每次都自己构造 attributedString
23+
* @note 即使先调用 setTitle:forState: 然后再调用这个方法,之前的 title 仍然会被应用上这些 attributes
24+
* @note 该方法和 setTitleColor:forState: 均可设置字体颜色,如果二者冲突,则代码顺序较后的方法定义的颜色会最终生效
25+
* @note 如果包含了 NSKernAttributeName ,则此方法会自动帮你去掉最后一个字的 kern 效果,否则容易导致文字整体在视觉上不居中
26+
*/
27+
- (void)qmui_setTitleAttributes:(NSDictionary<NSString *, id> *)attributes forState:(UIControlState)state;
28+
2129
@end

0 commit comments

Comments
 (0)