由于最近没什么项目,所以就试着模仿做了一些 App 的框架或者效果,今天做的是模仿 UC 浏览器个人中心的下拉效果,也有人称之为果冻效果或者是阻尼效果,本文用到了drawRect进行了底层的画线,不过还是很简单的只要把封装好的 MyHeaderView 放入工程中即可
效果图如下:
实现如下
ViewController.m:
//
// ViewController.m
// PullAnimation
//
// Created by Amydom on 16/10/29.
// Copyright © 2016年 Amydom. All rights reserved.
//
#import "ViewController.h"
#import "MyHeaderView.h"
@interface ViewController () <UITableViewDelegate, UITableViewDataSource>
@property (strong, nonatomic) MyHeaderView *headerView; // 上面蓝色的 view,可以自定义
@property (strong, nonatomic) UITableView *tableView;
@property (assign, nonatomic) CGFloat headerViewHeight; // headerView 高度
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.headerViewHeight = 180;
[self createView];
}
#pragma mark - initView
- (void)createView{
_tableView = [[UITableView alloc] init];
_tableView.frame = self.view.bounds;
_tableView.delegate = self;
_tableView.dataSource = self;
_tableView.rowHeight = 40;
_tableView.sectionHeaderHeight = 20;
_tableView.showsVerticalScrollIndicator = false;
[_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"mycell"];
// 占位用的 view,高度 180
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 1, self.headerViewHeight)];
view.backgroundColor = [UIColor clearColor];
_tableView.tableHeaderView = view;
[self.view addSubview:self.tableView];
// 蓝色的 headerView
_headerView = [[MyHeaderView alloc] init];
self.headerView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.headerViewHeight);
[self.view addSubview:self.headerView];
}
#pragma mark - 监听 tableView.contentOffset,也可以用 kvo 监听
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat offsetY = scrollView.contentOffset.y;
CGRect frame = self.headerView.frame;
if (offsetY < 0) {
frame.size.height = self.headerViewHeight - offsetY;
frame.origin.y = 0; // 及时归零
} else {
frame.size.height = self.headerViewHeight;
frame.origin.y = -offsetY;
}
self.headerView.frame = frame;
}
// scrollViewWillEndDragging,这个方法内判断一下,contentOffset.y 值,如果超过多少值,那么自动回调一个 block,可实现下拉刷新
//松手时触发
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset{
CGFloat offsetY = scrollView.contentOffset.y;
if (-offsetY > 70) {
NSLog(@"11111");
}
}
#pragma mark - tableView代理
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 30;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *indetifier = @"mycell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:indetifier];
cell.textLabel.text = @"Amydom";
return cell;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UITableViewHeaderFooterView *view = [tableView dequeueReusableHeaderFooterViewWithIdentifier:@"UITableViewHeaderFooterViewID"];
if (view == nil) {
view = [[UITableViewHeaderFooterView alloc] initWithReuseIdentifier:@"UITableViewHeaderFooterViewID"];
view.contentView.backgroundColor = [UIColor colorWithWhite:0.92 alpha:1.0];;
}
return view;
}
@end
MyHeaderView.m:
(这里是自定义的 UIView MyHeaderView.h
@interface MyHeaderView : UIView
@end
)//
// MyHeaderView.m
// PullAnimation
//
// Created by Amydom on 16/10/29.
// Copyright © 2016年 Amydom. All rights reserved.
//
#import "MyHeaderView.h"
@interface MyHeaderView ()
@property (strong, nonatomic) UIImageView *imageV; // 随便放一个 imageView
@property (assign, nonatomic) CGFloat headerViewHeight; // headerView 高度
@property (assign, nonatomic) CGFloat screenWidth;
@end
@implementation MyHeaderView
- (UIImageView *)imageV {
if (_imageV == nil) {
_imageV = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"ico_Default"]];
_imageV.contentMode = UIViewContentModeScaleAspectFit;
_imageV.userInteractionEnabled = true;
[_imageV addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(imageViewTapAction:)]];
}
return _imageV;
}
- (void)imageViewTapAction:(id)sender {
NSLog(@"imageView tap");
}
- (instancetype)init {
if (self = [super init]) {
self.backgroundColor = [UIColor clearColor];
self.headerViewHeight = 180;
self.screenWidth = [UIScreen mainScreen].bounds.size.width;
[self addSubview:self.imageV];
}
return self;
}
// 更改 frame 会触发 layoutSubviews
// 触发 layoutSubviews 后,这个 view 里面的控件想怎么变(旋转,位移,缩放),全部这个方法里面就好了
- (void)layoutSubviews {
[super layoutSubviews];
// imageV 是 60 * 60 的
CGFloat y = 60 + (self.frame.size.height - self.headerViewHeight) * 0.6;
self.imageV.frame = CGRectMake((self.screenWidth - 60) * 0.5, y, 60, 60);
[self setNeedsDisplay]; // 重绘
}
// 绘制曲线
- (void)drawRect:(CGRect)rect {
//获取上下文
//CGContextRef 用来保存图形信息.输出目标
CGContextRef context = UIGraphicsGetCurrentContext();
//设置颜色
CGContextSetRGBFillColor(context, 0.00392, 0.54117, 0.85098, 1.0);
CGFloat h1 = self.headerViewHeight;
CGFloat w = rect.size.width;
CGFloat h = rect.size.height;
//起点
CGContextMoveToPoint(context, w, h1);
//画线
CGContextAddLineToPoint(context, w, 0);
CGContextAddLineToPoint(context, 0, 0);
CGContextAddLineToPoint(context, 0, h1);
CGContextAddQuadCurveToPoint(context, w * 0.5, h + (h - h1) * 0.6, w, h1);
//闭合
CGContextClosePath(context);
CGContextDrawPath(context, kCGPathFill);
}
// 这个 view 里面有多少个被点击的控件,把他的 frame 告诉 pointInside 就可以了
//这个函数会被 hitTest 调用,返回 false 表示点击的不是自己,返回 true 表示点击的是自己
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
// 判断点击的点,在不在圆内
CGPoint center = self.imageV.center;
CGFloat r = self.imageV.frame.size.width * 0.5;
CGFloat newR = sqrt((center.x - point.x) * (center.x - point.x) + (center.y - point.y) * (center.y - point.y));
// 浮点数比较不推荐用等号,虽然 ios 底层已经处理了这种情况
if (newR > r) {
return false;
} else {
return true;
}
}
//- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event; hitTest 主要用来做事件分发的,可以实现不规则点击,它在整个 view 结构上是递归的
@end
因为做了判断,所以当点击 imageView(头像)时,无法响应下拉效果,这个可以根据需求进行修改!!