IOS 炫酷导航栏解析与使用

原项目地址:

http://code4app.com/forum.php?mod=viewthread&tid=8797&extra=page%3D1%26filter%3Dsortid%26sortid%3D1

效果图:

炫酷导航栏.gif

简要讲解:(只关注导航栏部分)

1.用一个导航控制器包裹该控制器并在导航栏添加两个item
2.用设置空图片的方法来让导航栏隐藏
3.给tableView设置headerView

4.初始显示时:


Paste_Image.png

从图上可知,-64就是tableView的当前的偏移量y值:(因为导航栏会默认让scrollView产生64的偏移量)
所以只有设置headerView背景图片的y值=偏移量y才能完好的覆盖上面整个导航栏和状态栏

5.下拉时:

Paste_Image.png

tableView上面的内容显示的就会越多,-的偏移量就会增大,那么图片就对应的应该被拉伸,图片的frame就等于上图;(!注意设置图片的拉伸模式)

6.上拉时

Paste_Image.png

设定一个最大偏移量值,当偏移量>该值时,通过设置透明度,开始慢慢显示出导航栏上的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
炫酷导航栏.gif
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容

  • 在项目中往往有的时候需要导航栏的状态是变化的,有的时候需要隐藏,为的是显示更多的页面,有的时候需要显示出来,给用户...
    请输入账号名阅读 10,640评论 2 18
  • 我三姨年轻的时候,是十里八村有名的大美人。据我妈说,当时我三姨夫作为县政府的青年才俊,被我三姨迷的神魂颠倒,足足在...
    沧海一只猫阅读 732评论 6 10
  • 早上在睡眼惺忪中起来,啊~~~(我还没睡够呢,在来个5分钟,就5分钟,不行啊要迟到了!),然后坐在餐桌吃完早餐,急...
    四位一体阅读 3,234评论 0 0
  • #幸福是需要修出来的~每天进步1%~幸福实修08班~015-董超-杭州 20170712(24/99) 【幸福三朵...
    julie123阅读 208评论 2 2
  • #import "ViewController.h"#import@interface ViewControlle...
    KAKA_move阅读 288评论 0 0