XLZoomHeader.m 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. //
  2. // XLZoomHeader.m
  3. // XLZoomHeaderDemo
  4. //
  5. // Created by MengXianLiang on 2018/8/3.
  6. // Copyright © 2018年 mxl. All rights reserved.
  7. //
  8. #import "XLZoomHeader.h"
  9. #import <objc/runtime.h>
  10. static NSString *XLZoomHeaderContentOffsetKey = @"contentOffset";
  11. @interface XLZoomHeader ()
  12. @property (nonatomic, strong) UIImageView *backGroundImageView;
  13. @property (nonatomic, weak) UIScrollView *scrollView;
  14. @end
  15. @implementation XLZoomHeader
  16. - (instancetype)initWithFrame:(CGRect)frame {
  17. if (self = [super initWithFrame:frame]) {
  18. [self initHeaderUI];
  19. }
  20. return self;
  21. }
  22. - (instancetype)init {
  23. if (self = [super init]) {
  24. [self initHeaderUI];
  25. }
  26. return self;
  27. }
  28. - (void)initHeaderUI {
  29. self.backGroundImageView = [[UIImageView alloc] init];
  30. [self addSubview:self.backGroundImageView];
  31. }
  32. - (void)initHeaderRect {
  33. //set frame
  34. CGFloat height = self.bounds.size.height;
  35. CGRect frame = self.frame;
  36. frame.origin.y = -height;
  37. self.frame = frame;
  38. //set scrollView inset
  39. self.scrollView.contentInset = UIEdgeInsetsMake(height, 0, 0, 0);
  40. }
  41. - (void)willMoveToSuperview:(UIView *)newSuperview {
  42. [super willMoveToSuperview:newSuperview];
  43. if (![newSuperview isKindOfClass:[UIScrollView class]]) {return;}
  44. self.scrollView = (UIScrollView *)newSuperview;
  45. [self initHeaderRect];
  46. [self addObservers];
  47. }
  48. #pragma mark -
  49. #pragma mark add observers
  50. - (void)addObservers {
  51. NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld;
  52. [self.scrollView addObserver:self forKeyPath:XLZoomHeaderContentOffsetKey options:options context:nil];
  53. }
  54. - (void)removeObservers {
  55. [self.scrollView removeObserver:self forKeyPath:XLZoomHeaderContentOffsetKey];
  56. }
  57. -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
  58. if ([keyPath isEqualToString:XLZoomHeaderContentOffsetKey]) {
  59. [self scrollViewContentOffsetDidChange:change];
  60. }else{
  61. [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
  62. }
  63. }
  64. #pragma mark -
  65. #pragma mark zoom animation
  66. - (void)scrollViewContentOffsetDidChange:(NSDictionary *)change {
  67. //set top inset
  68. CGFloat top = 0;
  69. if (@available(iOS 11.0, *)) {
  70. top = self.scrollView.adjustedContentInset.top;
  71. }
  72. //move offset
  73. CGFloat offset = fabs(self.scrollView.contentOffset.y) - top;
  74. CGFloat height = [self imageViewRect].size.height + offset;
  75. CGFloat width = height * ([self imageViewRect].size.width/[self imageViewRect].size.height);
  76. //x
  77. CGFloat x = -(width - [self imageViewRect].size.width)/2.0f + [self imageViewRect].origin.x;
  78. //y
  79. CGFloat y = -offset + [self imageViewRect].origin.y;
  80. //set frame
  81. self.backGroundImageView.frame = CGRectMake(x, y, width, height);
  82. //if scrolls upside dont update frame
  83. if (offset <= 0) {
  84. self.backGroundImageView.frame = [self imageViewRect];
  85. }
  86. }
  87. - (CGRect)imageViewRect {
  88. CGRect rect = self.bounds;
  89. rect.origin.x = self.backgroundImageInsets.left;
  90. rect.size.width = rect.size.width - self.backgroundImageInsets.left - self.backgroundImageInsets.right;
  91. rect.origin.y = self.backgroundImageInsets.top;
  92. rect.size.height = rect.size.height - self.backgroundImageInsets.top - self.backgroundImageInsets.bottom;
  93. return rect;
  94. }
  95. #pragma mark -
  96. #pragma mark Setter
  97. - (void)setBackgroundImage:(UIImage *)backgroundImage {
  98. _backgroundImage = backgroundImage;
  99. self.backGroundImageView.image = backgroundImage;
  100. }
  101. - (void)dealloc {
  102. [self removeObservers];
  103. }
  104. @end
  105. static NSString *XLZoomHeaderKey = @"XLZoomHeaderKey";
  106. @implementation UIScrollView (XLZoomHeader)
  107. - (void)setXl_zoomHeader:(XLZoomHeader *)xl_zoomHeader {
  108. if (xl_zoomHeader != self.xl_zoomHeader) {
  109. [self.xl_zoomHeader removeFromSuperview];
  110. [self insertSubview:xl_zoomHeader atIndex:0];
  111. objc_setAssociatedObject(self, &XLZoomHeaderKey,
  112. xl_zoomHeader, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
  113. }
  114. }
  115. - (XLZoomHeader *)xl_zoomHeader {
  116. return objc_getAssociatedObject(self, &XLZoomHeaderKey);
  117. }
  118. @end