NavigationBar Playground

可动态调整大小的导航条

要想调整导航条(NavigationBar)的大小或位置,只需改变他的frame即可。 但怎样让导航条上的那些控件(按钮、标题、searchbar之类的)也能成一定比例的缩小或者消失呢?当然是对这些视图做仿射变换(CGAfineTransfrom)。 我们知道UIBarButtonItem继承自UIBarItem,UIBarItem继承自NSObject,不能对它做一些UIView能做的仿射变换。 但是NavigationController.navigationItem有一个属性:titleView可作为我们自定义控件(所有继承自UIView的控件)的容器。 实现动态导航条的思路:当检测要触发调整导航条的事件时(scrollView向下向上滚动或Tap导航条等等),1、将导航条向上移动20个Point(因为状态栏的宽度是20),当然移动多少个Point你随意。2、对titleView上的控件做仿射变换

我们先来给导航条布局,以下代码可放在ViewDidLoad里

    UIView *contentView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 44)];
    contentView.tag = 1;
    self.navigationItem.titleView = contentView;

    UIButton *leftButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 50, 33)];
    leftButton.center = CGPointMake(13, 22);//设置frame不行调整,但center确行
    leftButton.tag = 4;
    [leftButton setTitle:@"left" forState:UIControlStateNormal];
    [leftButton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
    [leftButton setTitleColor:[UIColor grayColor] forState:UIControlStateHighlighted];
    [contentView addSubview:leftButton];

    UIButton *rightButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 50, 33)];
    rightButton.tag = 2;
    [rightButton setTitle:@"right" forState:UIControlStateNormal];
    [rightButton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
    [rightButton setTitleColor:[UIColor grayColor] forState:UIControlStateHighlighted];
    rightButton.center = CGPointMake(280, 22);
    [contentView addSubview:rightButton];

    UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
    titleLabel.tag = 3;
    titleLabel.text = @"title";
    [titleLabel sizeToFit];
    titleLabel.center = CGPointMake(contentView.frame.size.width / 2, 22);
    [contentView addSubview:titleLabel];

创建控件的代码都很简单,比较蛋疼的就是计算它们的位置。还有不要忘了给他们上个tag以便下面能得到这些视图的引用。
如果给titleView上个背景色,我们可以发现titleView的Frame,感觉有点奇怪,不知道苹果为什么这样做。但这并不意味着你的Subview只能在这个Frame以内,把Subview.frame.origin.x设置为负数就可以在它之外了,效果如下图(我把导航条的背景色设置成了粉红) 下面实现调整导航条大小

static BOOL isShirink = 0;  
- (void)shrinkNavBar{
    UIView *contentView = [self.navigationItem.titleView viewWithTag:1];

    UILabel *titleLabel = (UILabel *)[contentView viewWithTag:3];
    UIButton *leftButton = (UIButton *)[contentView viewWithTag:4];
    UIButton *rightButton = (UIButton *)[contentView viewWithTag:2];

    CGPoint labelCenter = titleLabel.center;
    CGPoint leftButtonCenter = leftButton.center;
    CGPoint rightButtonCenter = rightButton.center;

    CGRect navBarFrame = self.navigationController.navigationBar.frame;

    CGAffineTransform labelTransform = CGAffineTransformMakeScale(0.9, 0.9);
    CGAffineTransform buttonTransform = CGAffineTransformMakeScale(0.01, 0.01);
    if (!isShirink) {

        navBarFrame.origin.y -= 20;

        labelCenter.y += 5;
        leftButtonCenter.x -= 5;
        rightButtonCenter.x += 5;

        [UIView animateWithDuration:0.5 animations:^{
            titleLabel.transform = labelTransform;
            leftButton.transform = buttonTransform;
            rightButton.transform = buttonTransform;
            self.navigationController.navigationBar.frame = navBarFrame;
            titleLabel.center = labelCenter;
            leftButton.center = leftButtonCenter;
            rightButton.center = rightButtonCenter;
        }];
        isShirink = ! isShirink;
    }else{
        navBarFrame.origin.y += 20;
        labelCenter.y -= 5;
        leftButtonCenter.x += 5;
        rightButtonCenter.x -= 5;


        [UIView animateWithDuration:0.5 animations:^{
            titleLabel.transform = CGAffineTransformIdentity;
            leftButton.transform = CGAffineTransformIdentity;
            rightButton.transform = CGAffineTransformIdentity;
            self.navigationController.navigationBar.frame = navBarFrame;
            titleLabel.center = labelCenter;
            leftButton.center = leftButtonCenter;
            rightButton.center = rightButtonCenter;
        }];
        isShirink = !isShirink;
    }
}

说明:用一个static的bool变量检查导航条的状态。 如果导航条没有被压缩,就用UIView的 +animateWithDuration:animations:^(void)animation{}做压缩的动画效果。这里有个问题:导航条向上移动了,那么它的所有子视图也向上移动,这样使得titleLabel太靠近状态栏,我们想把它的位置往下调一些怎么做?
CGAfineTransformMakeScale是以view.layer.anchorPoint(锚点)为基准进行变换,这个点默认是(0.5,0.5)。view还有一个属性center,如果在scale变换的同时改变center的值,就可以调整它的位置,labelCenter.y += 5 向下调整5个单位。 注意以下,CGAfineTransform和center相互关联,并且都会改变frame的值,这之间的关系可以自己思考以下。
如果导航条已经被压缩,将以上操作倒过来就OK了。CGAffineTransformIdentity可以把view恢复成没做仿射变换,这也是view.transform的默认值。 为了简单起见。我就以Tap导航条手势触发调整大小 讲以下代码添加进第一段代码的末尾:

    UITapGestureRecognizer *tapGestureReconizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(shrinkNavBar)];
    tapGestureReconizer.numberOfTapsRequired = 1;
    tapGestureReconizer.numberOfTouchesRequired = 1;
    [contentView addGestureRecognizer:tapGestureReconizer];

全透明导航条

只需要3行代码:

    [self.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
    [self.navigationBar setShadowImage:[UIImage new]];
    [self.navigationBar setTranslucent:YES];

comments powered by Disqus