iOS 仿 UC 浏览器个人中心 (下拉实现果冻效果)

这篇博客介绍了如何模仿UC浏览器个人中心的下拉果冻效果,该效果也称为阻尼效果。作者通过使用drawRect方法进行底层画线,实现了简单易用的MyHeaderView组件。
摘要由CSDN通过智能技术生成

由于最近没什么项目,所以就试着模仿做了一些 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(头像)时,无法响应下拉效果,这个可以根据需求进行修改!!
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值