ios - 如何隐藏 navigationBar -> Overlay Label 但作为图像,如 Airbnb?

标签 ios swift animation navigationbar

我做了一些实验来复制(或至少有一个类似的工作示例)airbnb 导航栏。对于那些不知道该应用程序的人,请查看以下屏幕截图:

airbnb navigationBar start :

airbnb navigationBar overlay

如您所见,导航栏最初是隐藏的,然后位于图像后面但覆盖了标题标签。我真的很喜欢导航栏平滑过渡到前面的动画。

我想用

  1. 隐藏导航栏
  2. 在 navigationBar 淡入淡出的确切位置:使 navigationBar 透明并增加 alpha
  3. 在动画结束时显示默认的导航栏

实现看起来像:https://github.com/mbecker/AirbnbCopy

import UIKit

private let kTableHeaderHeight: CGFloat = 300.0
private let kTableHeaderCutAway: CGFloat = 60.0

class MainViewController: UIViewController, UIScrollViewDelegate {

    @IBOutlet var headerView: UIView!
    @IBOutlet weak var scrollView: UIScrollView!
    @IBOutlet weak var parkHeading: UILabel!
    @IBOutlet weak var parkImage: UIImageView!
    
    var headerMaskLayer: CAShapeLayer!
    // create background images for the navigation bar
    var navBarImage = UIImage().imageWithColor(UIColor(red:0.11, green:0.64, blue:0.98, alpha:0.0))
    var gradientImage32 = UIImage().imageWithColor(UIColor(red:0.11, green:0.64, blue:0.98, alpha:0.0))
    
    let image = UIImage(named: "bg-addo")
    let overlay: UIView = UIView(frame: CGRectMake(0, 0, UIScreen.mainScreen().bounds.height, 400))
    
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        scrollView.delegate = self
        
        // Adjust view
        self.automaticallyAdjustsScrollViewInsets = false
        
        // NavigationBar
        let attrs = [
            NSForegroundColorAttributeName : UIColor.blackColor(),
            NSFontAttributeName : UIFont(name: "HelveticaNeue-Bold", size: 17)!
        ]
        self.navigationController!.navigationBar.titleTextAttributes = attrs
        self.navigationController!.navigationBar.hidden = true
        self.navigationController!.navigationBar.setBackgroundImage(navBarImage, forBarMetrics: .Default)
        self.navigationController!.navigationBar.setBackgroundImage(navBarImage, forBarMetrics: .Compact)
//        self.navigationController!.navigationBar.shadowImage = UIImage()
        self.navigationController!.navigationBar.barStyle = .Default
        
        
        // Header
        overlay.backgroundColor = UIColor(red:0.04, green:0.28, blue:0.44, alpha:0.4)
        parkImage.addSubview(overlay)
        parkImage.image = image?.imageWithAlpha(1)
        
        headerMaskLayer = CAShapeLayer()
        headerMaskLayer.fillColor = UIColor.blackColor().CGColor
        
        headerView.layer.mask = headerMaskLayer
        updateHeaderView()
        
    }
    
    func scrollViewDidScroll(scrollView: UIScrollView) {
        
        let heightShowNavBarStart   = kTableHeaderHeight - kTableHeaderCutAway - parkHeading.frame.height - 66
        let heightShowNavBarEnd     = kTableHeaderHeight - kTableHeaderCutAway - 66
        
        
        print("scrollView.contentOffset.y   -   \(scrollView.contentOffset.y)")
        print("heightShowNavBarStart        -   \(heightShowNavBarStart)")
        print("heightShowNavBarEnd          -   \(heightShowNavBarEnd)")
        
        
        
        let base        = parkHeading.frame.height
        let counter     = heightShowNavBarEnd - scrollView.contentOffset.y
        var alpha       = counter / base
        var navigationBarHidden = false;
        
        if(scrollView.contentOffset.y >= heightShowNavBarStart && scrollView.contentOffset.y <= heightShowNavBarEnd){
            
        } else if (scrollView.contentOffset.y < heightShowNavBarStart ){
            navigationBarHidden = true
            alpha = 1
        } else if(scrollView.contentOffset.y > heightShowNavBarEnd) {
            navigationBarHidden = false
            alpha = 0
        }
        print("alpha                - \(alpha)")
        print("navigationBarHidden  - \(navigationBarHidden)")
        
        
        self.navigationController!.navigationBar.hidden = navigationBarHidden
        
        if(!navigationBarHidden && alpha == 0){
            // Show navigationBar && hide headerView parkImage
            parkImage.hidden = true
            self.navigationController!.navigationBar.setBackgroundImage(nil, forBarMetrics: .Default)
            self.navigationController!.navigationBar.setBackgroundImage(nil, forBarMetrics: .Compact)
            self.navigationController!.navigationBar.barStyle = .Default
        } else {
            parkImage.hidden = false
            parkImage.image = image?.imageWithAlpha(alpha)
            navBarImage = UIImage().imageWithColor(UIColor(red:0.96, green:0.96, blue:0.98, alpha: 1 - alpha))
            self.navigationController!.navigationBar.setBackgroundImage(navBarImage, forBarMetrics: .Default)
            self.navigationController!.navigationBar.setBackgroundImage(navBarImage, forBarMetrics: .Compact)
            overlay.backgroundColor = UIColor(red:0.04, green:0.28, blue:0.44, alpha: alpha * 0.4)
        }
        
        
    }
    
    func updateHeaderView(){
        let effectiveHeight = kTableHeaderHeight-kTableHeaderCutAway/2
        var headerRect = CGRect(x: 0, y: -effectiveHeight, width: scrollView.bounds.width, height: kTableHeaderHeight)
        if scrollView.contentOffset.y < -effectiveHeight {
            headerRect.origin.y = scrollView.contentOffset.y
            headerRect.size.height = -scrollView.contentOffset.y + kTableHeaderCutAway/2
        }
        
        headerView.frame = headerRect
        
        let path = UIBezierPath()
        path.moveToPoint(CGPoint(x: 0, y: 0))
        path.addLineToPoint(CGPoint(x: headerRect.width, y: 0))
        path.addLineToPoint(CGPoint(x: headerRect.width, y: headerRect.height))
        path.addLineToPoint(CGPoint(x: 0, y: headerRect.height-kTableHeaderCutAway))
        headerMaskLayer?.path = path.CGPath
    }
    
}

extension UIImage {
    
    func imageWithColor(colour: UIColor) -> UIImage {
        let rect = CGRectMake(0, 0, 1, 1)
        
        // Create a 1x1 pixel content
        UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
        colour.setFill()
        UIRectFill(rect)
        
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }
    
    func imageWithAlpha(alpha: CGFloat) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(size, false, scale)
        drawAtPoint(CGPointZero, blendMode: .Normal, alpha: alpha)
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage
    }
    
}

我认为动画不是很流畅,在某些时候标题图像没有设置回屏幕顶部。

有人知道如何创建这样的导航栏吗?

最佳答案

这正是您想要的,它允许您创建具有灵活高度的标题栏。通常,这种 UI 范例用于隐藏“chrome”并在用户滚动时为更多内容腾出空间。

https://github.com/bryankeller/BLKFlexibleHeightBar/

关于ios - 如何隐藏 navigationBar -> Overlay Label 但作为图像,如 Airbnb?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39163431/

相关文章:

javascript - CSS动画同时动态改变翻译

ios - Swift 动画重复次数

ios - 如何将图标添加到 Storyboard中的 iOS 静态 uitableview 单元格

ios - 无法在 UIView 中将自定义类设置为 GLKView

swift - Swift 可执行二进制文件是否需要 .swiftmodule、.swiftdoc 和 .build 文件才能运行?

swift - 读取 iOS 10 中的通知设置时出现问题

android - 在 cocos2d-x 中使用 arc4random_uniform

ios - 仅一个屏幕的横向方向模式 - iPhone

json - Swift 4 可解码 : struct from nested array

javascript - Animate React 重新排列列表项