原项目地址:
http://code4app.com/forum.php?mod=viewthread&tid=8797&extra=page%3D1%26filter%3Dsortid%26sortid%3D1
效果图:
简要讲解:(只关注导航栏部分)
1.用一个导航控制器包裹该控制器并在导航栏添加两个item
2.用设置空图片的方法来让导航栏隐藏
3.给tableView设置headerView
4.初始显示时:
从图上可知,-64就是tableView的当前的偏移量y值:(因为导航栏会默认让scrollView产生64的偏移量)
所以只有设置headerView背景图片的y值=偏移量y才能完好的覆盖上面整个导航栏和状态栏
5.下拉时:
tableView上面的内容显示的就会越多,-的偏移量就会增大,那么图片就对应的应该被拉伸,图片的frame就等于上图;(!注意设置图片的拉伸模式)
6.上拉时
设定一个最大偏移量值,当偏移量>该值时,通过设置透明度,开始慢慢显示出导航栏上的overlayer(overlayer是通过runtime嵌套在navigationBar中的,其y=-20,这样就可以覆盖statusBar);
使用
UIViewController
#define Max_OffsetY 0
#define WeakSelf(x) __weak typeof (self) x = self //用于创建自身弱引用
#define HalfF(x) ((x)/2.0f) //求半函数
#define kScreenWidth [UIScreen mainScreen].bounds.size.width
#define kScreenHeight [UIScreen mainScreen].bounds.size.height
#define Statur_HEIGHT [[UIApplication sharedApplication] statusBarFrame].size.height //状态栏高度
#define NAVIBAR_HEIGHT (self.navigationController.navigationBar.frame.size.height) //导航栏高度
#define INVALID_VIEW_HEIGHT (Statur_HEIGHT + NAVIBAR_HEIGHT) //相当于是64
#import "ViewController.h"
#import "UINavigationBar+PS.h"
#import "UIView+PS.h"
@interface ViewController () <UITableViewDelegate,UITableViewDataSource,UIScrollViewDelegate>
@property (nonatomic,strong)UITableView *tableView;
@property (nonatomic,strong)UIImageView * avatarView;//头像
@property (nonatomic,strong)UILabel * messageLabel;//头像下面的label
@property (nonatomic,strong)UIView * headBackView;//整个背景view
@property (nonatomic,strong)UIImageView * headImageView;//背景图片
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//1.设置头部view
[self resetHeaderView];
//2.添加控件
//->将headBackView设置为tableView的头部view
self.tableView.tableHeaderView = self.headBackView;
[self.view addSubview:self.tableView];
//3.初始化导航栏
//->设置导航透明:(设置导航栏背景图片为空)
[self.navigationController.navigationBar ps_setBackgroundColor:[UIColor clearColor]];
//->去掉导航栏上的横线:
[self.navigationController.navigationBar setShadowImage:[UIImage new]];
//->设置导航栏上左右两个item
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"左边" style:(UIBarButtonItemStylePlain) target:nil action:nil];
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"右边" style:(UIBarButtonItemStylePlain) target:nil action:nil];
}
#pragma mark tableView代理
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return 50;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString * cellIdentity = @"cell";
UITableViewCell * tableViewCell = [tableView dequeueReusableCellWithIdentifier:cellIdentity];
if (!tableViewCell) {
tableViewCell = [[UITableViewCell alloc] initWithStyle:(UITableViewCellStyleDefault) reuseIdentifier:cellIdentity];
}
tableViewCell.textLabel.text = @"图片下拉放大,导航上拉渐变";
return tableViewCell;
}
#pragma mark 懒加载
- (UITableView*)tableView //tableView
{
if (!_tableView) {
_tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:(UITableViewStylePlain)];
_tableView.delegate = self;
_tableView.dataSource = self;
_tableView.showsVerticalScrollIndicator = NO;
}
return _tableView;
}
- (UIView*)headBackView //整个背景view
{
if (!_headBackView) {
_headBackView = [UIView new];
_headBackView.userInteractionEnabled = YES;
_headBackView.frame = CGRectMake(0, 0, kScreenWidth,200);
}
return _headBackView;
}
- (UIImageView*)headImageView //背景图片
{
if (!_headImageView)
{
_headImageView = [UIImageView new];
_headImageView.image = [UIImage imageNamed:@"bg"];
_headImageView.contentMode = UIViewContentModeScaleAspectFill;//图片拉伸模式
_headImageView.clipsToBounds = YES;
_headImageView.backgroundColor = [UIColor orangeColor];
}
return _headImageView;
}
- (UIImageView*)avatarView //头像
{
if (!_avatarView) {
_avatarView = [UIImageView new];
_avatarView.image = [UIImage imageNamed:@"qyc"];
_avatarView.contentMode = UIViewContentModeScaleToFill;
_avatarView.size = CGSizeMake(80, 80);
[_avatarView setLayerWithCr:HalfF(_avatarView.width)];
[_avatarView setBorderWithColor:[UIColor whiteColor] width:2];
return _avatarView;
}
- (UILabel*)messageLabel //标签
{
if (!_messageLabel) {
_messageLabel = [UILabel new];
_messageLabel.textAlignment = NSTextAlignmentCenter;
_messageLabel.font = [UIFont systemFontOfSize:16];
_messageLabel.textColor = [UIColor whiteColor];
}
return _messageLabel;
}
#pragma mark --
- (void)resetHeaderView
{
self.headImageView.frame = self.headBackView.bounds;
[self.headBackView addSubview:self.headImageView];
self.avatarView.centerX = self.headBackView.centerX;
self.avatarView.centerY = self.headBackView.centerY - HalfF(70);
[self.headBackView addSubview:self.avatarView];
self.messageLabel.text = @"丁昌江 : 1137975808";
self.messageLabel.y = CGRectGetMaxY(self.avatarView.frame) + HalfF(20);
self.messageLabel.size = CGSizeMake(kScreenWidth - HalfF(30), 30);
self.messageLabel.centerX = self.headBackView.centerX;
[self.headBackView addSubview:self.messageLabel];
}
#pragma mark --
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGFloat offset_Y = scrollView.contentOffset.y;
NSLog(@"上下偏移量 OffsetY:%f ->",offset_Y);
//1.处理图片放大
CGFloat imageH = self.headBackView.size.height;
CGFloat imageW = kScreenWidth;
//下拉:(一开始执行也算下拉,因为offset_Y == -64)
if (offset_Y < 0)
{
CGFloat totalOffset = imageH + ABS(offset_Y);//头部view的高度+偏移量
CGFloat f = totalOffset / imageH;//比例
//如果想下拉固定头部视图不动,y和h 是要等比都设置。如不需要则y可为0
self.headImageView.frame = CGRectMake(-HalfF((imageW * f - imageW)), offset_Y, imageW * f, totalOffset);
}
//2.处理导航颜色渐变 3.底部工具栏动画
if (offset_Y > Max_OffsetY)//当往上推到一定数值后,开始慢慢显示导航条
{
CGFloat alpha = MIN(1, 1 - ((Max_OffsetY + INVALID_VIEW_HEIGHT - offset_Y) / INVALID_VIEW_HEIGHT));
/*
为什么MIN第二个参数要1-XXX
因为当tableView上拉时,offset_Y会一直增大,导航栏透明度应该变大;
然后offset_Y越大算式分子会越小,alpha会越小,
所以用1-XXX得到相反值
*/
[self.navigationController.navigationBar ps_setBackgroundColor:[NavigationBarBGColor colorWithAlphaComponent:alpha]];
self.title = alpha > 0.8? @"丁昌江":@"";
}
else
{
[self.navigationController.navigationBar ps_setBackgroundColor:[NavigationBarBGColor colorWithAlphaComponent:0]];
}
}
@end
UINavigationBar+PS
#import "UINavigationBar+PS.h"
#import <objc/runtime.h>
@implementation UINavigationBar (PS)
#warning 用runtime给navigatinoBar添加了一个子控件overlayer
static char overlayerkey;
- (UIView*)overlayer
{
return objc_getAssociatedObject(self, &overlayerkey);
}
- (void)setOverlayer:(UIView*)overlayer
{
objc_setAssociatedObject(self, &overlayerkey, overlayer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
#pragma mark --
/**
* 给导航栏设置颜色
*/
- (void)ps_setBackgroundColor:(UIColor *)backgroundColor
{
if (!self.overlayer)
{
[self setBackgroundImage:[UIImage new] forBarMetrics:(UIBarMetricsDefault)];
self.overlayer = [[UIView alloc] initWithFrame:CGRectMake(0, -20, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds) + 20)];
/*
为什么Y要-20,H要+20呢?
因为,overlayer要覆盖statusBar
*/
self.overlayer.userInteractionEnabled = NO;
self.overlayer.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
[self insertSubview:self.overlayer atIndex:0];
}
self.overlayer.backgroundColor = backgroundColor;
}
/**
* 设置导航栏位置
*/
- (void)ps_setTranslationY:(CGFloat)translationY
{
self.transform = CGAffineTransformMakeTranslation(0, translationY);
}
/**
* 还原导航栏位置
*/
- (void)ps_setTransformIdentity
{
self.transform = CGAffineTransformIdentity;
}
/**
* 设置导航栏上子控件的透明度
*/
- (void)ps_setElementsAlpha:(CGFloat)alpha
{
[[self valueForKey:@"_leftViews"] enumerateObjectsUsingBlock:^(UIView *view, NSUInteger i, BOOL *stop) {
view.alpha = alpha;
}];
[[self valueForKey:@"_rightViews"] enumerateObjectsUsingBlock:^(UIView *view, NSUInteger i, BOOL *stop) {
view.alpha = alpha;
}];
UIView *titleView = [self valueForKey:@"_titleView"];
titleView.alpha = alpha;
// when viewController first load, the titleView maybe nil
[[self subviews] enumerateObjectsUsingBlock:^(UIView *obj, NSUInteger idx, BOOL *stop) {
if ([obj isKindOfClass:NSClassFromString(@"UINavigationItemView")]) {
obj.alpha = alpha;
*stop = YES;
}
}];
}
/**
* 重置导航栏
*/
- (void)ps_reset
{
[self setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault];
[self.overlayer removeFromSuperview];
self.overlayer = nil;
}
@end
UIView+PS
#import "UIView+PS.h"
@implementation UIView (PS)
- (CGFloat)x
{
return self.frame.origin.x;
}
- (void)setX:(CGFloat)x
{
CGRect r = self.frame;
r.origin.x = x;
self.frame = r;
}
- (CGFloat)y
{
return self.frame.origin.y;
}
- (void)setY:(CGFloat)y
{
CGRect rect = self.frame;
rect.origin.y = y ;
self.frame = rect;
}
- (CGFloat)width
{
return self.frame.size.width;
}
- (void)setWidth:(CGFloat)width;
{
CGRect rect = self.frame;
rect.size.width = width;
self.frame = rect;
}
- (CGFloat)height
{
return self.frame.size.height;
}
- (void)setHeight:(CGFloat)height
{
CGRect rect = self.frame;
rect.size.height = height;
self.frame = rect;
}
- (CGFloat)centerX
{
return self.center.x;
}
- (void)setCenterX:(CGFloat)centerX
{
CGPoint center = self.center;
center.x = centerX;
self.center = center;
}
- (CGFloat)centerY
{
return self.center.y;
}
- (void)setCenterY:(CGFloat)centerY
{
CGPoint center = self.center;
center.y = centerY;
self.center = center;
}
- (CGPoint)origin
{
return self.frame.origin;
}
- (void)setOrigin:(CGPoint)origin;
{
CGRect rect = self.frame;
rect.origin = origin;
self.frame = rect;
}
- (CGSize)size
{
return self.frame.size;
}
- (void)setSize:(CGSize)size
{
CGRect rect = self.frame;
rect.size = size;
self.frame = rect;
}
#pragma mark -Method-
/**
* 设置圆角
*/
- (void)setLayerWithCr:(CGFloat)cornerRadius
{
self.layer.masksToBounds = YES; //没这句话它圆不起来
self.layer.cornerRadius = cornerRadius; //设置图片圆角的尺度。
}
/**
* 设置图层边框颜色
*/
- (void)setBorderWithColor: (UIColor *)color width: (CGFloat)width
{
self.layer.borderColor = [color CGColor];
self.layer.borderWidth = width;
}
@end