UIView+GJRatioAutoLayout.m 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. //
  2. // UIView+GJRatioAutoLayout.m
  3. // GJRatioAutoLayout
  4. //
  5. // Created by wangyutao on 15/12/30.
  6. // Copyright © 2015年 wangyutao. All rights reserved.
  7. //
  8. #import "UIView+GJRatioAutoLayout.h"
  9. #import "GJRatioAutoLayoutDefine.h"
  10. #import <objc/runtime.h>
  11. void GJExchangeImplementations(Class class, SEL newSelector, SEL oldSelector) {
  12. Method oldMethod = class_getInstanceMethod(class, newSelector);
  13. Method newMethod = class_getInstanceMethod(class, oldSelector);
  14. method_exchangeImplementations(oldMethod, newMethod);
  15. };
  16. #pragma mark - NSLayoutConstaint Category
  17. @interface NSLayoutConstraint (_GJRatioAutoLayout)
  18. /**
  19. * gj_isRatio mark the constant is origin or scaled.
  20. */
  21. @property (nonatomic, assign) BOOL gj_isRatio;
  22. @end
  23. @implementation NSLayoutConstraint (_GJRatioAutoLayout)
  24. + (void)load {
  25. GJExchangeImplementations(self, @selector(gj_constant), @selector(constant));
  26. }
  27. - (CGFloat)gj_constant {
  28. CGFloat constant = [self gj_constant];
  29. if (self.gj_isRatio) {
  30. constant *= GJ_Scale;
  31. }
  32. return constant;
  33. }
  34. - (void)setGj_isRatio:(BOOL)gj_isRatio {
  35. if (self.gj_isRatio == gj_isRatio) return;
  36. objc_setAssociatedObject(self, @selector(gj_isRatio), @(gj_isRatio), OBJC_ASSOCIATION_RETAIN);
  37. }
  38. - (BOOL)gj_isRatio {
  39. return [objc_getAssociatedObject(self, _cmd) boolValue];
  40. }
  41. @end
  42. #pragma mark - UiView Category
  43. @implementation UIView (GJRatioAutoLayout)
  44. + (void)load {
  45. GJExchangeImplementations(self, @selector(addConstraint:), @selector(gj_AddConstraint:));
  46. }
  47. - (BOOL)gj_aLRatio {
  48. return [objc_getAssociatedObject(self, _cmd) boolValue];
  49. }
  50. - (void)setGj_aLRatio:(BOOL)aLRatio {
  51. objc_setAssociatedObject(self, @selector(gj_aLRatio), @(aLRatio), OBJC_ASSOCIATION_RETAIN);
  52. }
  53. /**
  54. * set aLRatio
  55. */
  56. - (void)setALRatio:(BOOL)aLRatio {
  57. if (self.gj_aLRatio == aLRatio) return;
  58. self.gj_aLRatio = aLRatio;
  59. if (self.gj_aLRatio) {
  60. //if state is on, set all constraints constant scale
  61. for (NSLayoutConstraint * constraint in [self.gj_constraints allObjects]) {
  62. if (!constraint.gj_isRatio) {
  63. constraint.gj_isRatio = YES;
  64. }
  65. }
  66. }
  67. }
  68. /**
  69. * gj_constraints is a hash table that collect constraints himself
  70. *
  71. * @return hash table, week array.
  72. */
  73. - (NSHashTable *)gj_constraints {
  74. NSHashTable *array = objc_getAssociatedObject(self, _cmd);
  75. if (!array) {
  76. array = [NSHashTable weakObjectsHashTable];
  77. objc_setAssociatedObject(self, _cmd, array, OBJC_ASSOCIATION_RETAIN);
  78. }
  79. return array;
  80. }
  81. - (void)gj_AddConstraint:(NSLayoutConstraint *)constraint {
  82. if ([constraint isMemberOfClass:NSClassFromString(@"NSContentSizeLayoutConstraint")] &&
  83. ([self isKindOfClass:[UILabel class]] ||
  84. [self isKindOfClass:[UISlider class]] ||
  85. [self isKindOfClass:[UISwitch class]] ||
  86. [self isKindOfClass:[UIActivityIndicatorView class]] ||
  87. [self isKindOfClass:[UIPageControl class]] ||
  88. ([self isKindOfClass:[UIProgressView class]] &&
  89. constraint.firstAttribute == NSLayoutAttributeHeight))) {
  90. [self gj_AddConstraint:constraint];
  91. return;
  92. }
  93. if ([constraint isMemberOfClass:[NSLayoutConstraint class]] ||
  94. [constraint isMemberOfClass:NSClassFromString(@"MASLayoutConstraint")] ||
  95. [constraint isMemberOfClass:NSClassFromString(@"NSIBPrototypingLayoutConstraint")] ||
  96. [constraint isMemberOfClass:NSClassFromString(@"NSContentSizeLayoutConstraint")]) {
  97. //如果两个item有一个open,则这个constraint也open
  98. if ([self checkALRatioWithFirstItem:constraint.firstItem
  99. secondItem:constraint.secondItem]) {
  100. if (!constraint.gj_isRatio) {
  101. constraint.gj_isRatio = YES;
  102. }
  103. }
  104. //set item's constraints
  105. if (constraint.firstItem &&
  106. [constraint.firstItem isKindOfClass:[UIView class]]) {
  107. [((UIView *)constraint.firstItem).gj_constraints addObject:constraint];
  108. }
  109. if (constraint.secondItem &&
  110. [constraint.secondItem isKindOfClass:[UIView class]]) {
  111. [((UIView *)constraint.secondItem).gj_constraints addObject:constraint];
  112. }
  113. }
  114. [self gj_AddConstraint:constraint];
  115. }
  116. - (BOOL)checkALRatioWithFirstItem:(id)firstItem
  117. secondItem:(id)secondItem {
  118. BOOL firstRatio = NO;
  119. if (firstItem && [firstItem isKindOfClass:[UIView class]]) {
  120. UIView *firstView = firstItem;
  121. firstRatio = firstView.gj_aLRatio;
  122. }
  123. BOOL secondRatio = NO;
  124. if (secondItem && [secondItem isKindOfClass:[UIView class]]) {
  125. UIView *secondView = secondItem;
  126. secondRatio = secondView.gj_aLRatio;
  127. }
  128. return firstRatio || secondRatio;
  129. }
  130. @end