iOS - 如何在 Swift 中创建没有第三方框架的自定义动画横幅

iOS - How to create custom animated banner without third party framework in Swift

我需要创建一个自定义下拉横幅,它会从顶部掉落,然后在几秒钟内上升。 对于自定义横幅 UIView,我指的是这个问题,这是一个完美的例子,这就是我想要的,因为我的横幅也是动态的,这将根据文本调整高度。

但不确定如何制作此动画。我已经为动画编写了代码并且它工作得很好但不确定这个动画如何与我上面提到的自定义视图一起工作。

@IBAction func buttonClicked(_ sender: Any) {
    bannerView()
}

func bannerView() {
    let container = UIView()
    container.backgroundColor = UIColor.black
    container.frame = CGRect(x: 0, y: -200, width: self.view.frame.width, height: 200)
    UIApplication.shared.windows[0].addSubview(container)
    DispatchQueue.main.async {
        UIView.animate(withDuration: 0.4, delay: 0.0, options: .curveLinear, animations: {
            container.frame = CGRect(x:0, y: 0, width: self.view.frame.size.width, height: 200)
            
        }) { (finished) in
            UIView.animate(withDuration: 0.4,delay: 2.0, options: .curveLinear, animations: {
                container.frame = CGRect(x:0, y: -200, width: self.view.frame.size.width, height: 200)
            })
        }
    }
}
@IBAction func buttonClicked(_ sender: Any) {
   var stringText = "Lorem ipsum dolor sit amet,"
    bannerNotification(text: stringText)
}


func bannerNotification(text: String) {
    let container = UIView()
    let image = UIImageView()
    let label = UILabel()
    container.frame = CGRect(x: 0, y:-100, width: self.view.frame.size.width, height: 100)
    container.backgroundColor = .blue
    image.frame = CGRect(x: 15, y: 60, width: 30, height: 30)
    image.image = UIImage(named: "passport")
    label.frame = CGRect(x: image.bounds.maxX + 35, y: 40, width: container.frame.size.width - 100, height: 50)
    label.numberOfLines = 0
    label.font = UIFont(name:"Helvetica Neue", size: 15)
    label.text = text
    container.addSubview(image)
    container.addSubview(label)
    UIApplication.shared.windows[0].addSubview(container)
    DispatchQueue.main.async {
        UIView.animate(withDuration: 0.4, delay: 0.0, options: .curveLinear, animations: {
            container.frame = CGRect(x:0, y: 0, width: self.view.frame.size.width, height: 100)
            
        }) { (finished) in
            UIView.animate(withDuration: 0.4,delay: 2.0, options: .curveLinear, animations: {
                container.frame = CGRect(x:0, y: -100, width: self.view.frame.size.width, height: 100)
            })
        }
    }
}

试试这个,希望对你有用。

我不喜欢将子视图添加到 windows 而不是添加到视图层次结构...但是,如果这确实是您想要做的,请尝试一下(查看代码中的注释).

@IBAction func buttonClicked(_ sender: Any) {
    bannerNotification(text: "Banner Test with lots of text to wrap onto multiple lines. We're using explict frames and calculating the height of the (potentially multiline) label.")
}

func bannerNotification(text: String){

    // create a "container" view
    let container = UIView()
    
    // create a label
    let label = UILabel()
    
    // add label to container
    container.addSubview(label)
    
    // color / font / text properties as desired
    container.backgroundColor = UIColor(red: 0.0, green: 0.5, blue: 1.0, alpha: 1.0)
    label.backgroundColor = .yellow
    label.numberOfLines = 0
    label.font = UIFont(name:"Helvetica Neue", size: 16.0)
    label.text = text
    
    // padding on left/right of label
    let hPadding: CGFloat = 16.0
    
    // padding on top of label - account for status bar?
    let vTopPadding: CGFloat = 32.0
    
    // padding on bottom of label
    let vBotPadding: CGFloat = 16.0

    let width = UIScreen.main.bounds.width
    
    // get reference to window 0
    let w = UIApplication.shared.windows[0]
    
    // add container to window
    w.addSubview(container)
    
    // calculate label height
    let labelSize = label.systemLayoutSizeFitting(CGSize(width: width - (hPadding * 2.0),
                                                  height: UIView.layoutFittingCompressedSize.height))
    
    // rect for container view - start with .zero
    var containerRect = CGRect.zero
    // set its size to screen width x calculated label height + top/bottom padding
    containerRect.size = CGSize(width: width, height: labelSize.height + vTopPadding + vBotPadding)
    // set container view's frame
    container.frame = containerRect
    
    // rect for label - container rect inset by padding values
    let labelRect = containerRect.inset(by: UIEdgeInsets(top: vTopPadding, left: hPadding, bottom: vBotPadding, right: hPadding))
    // set the label's frame
    label.frame = labelRect

    // position container view off-the-top of the screen
    container.frame.origin.y = -container.frame.size.height
    
    DispatchQueue.main.async {
        UIView.animate(withDuration: 0.4, delay: 0.0, options: .curveLinear, animations: {
            container.frame.origin.y = 0
        }) { (finished) in
            UIView.animate(withDuration: 0.4,delay: 2.0, options: .curveLinear, animations: {
                container.frame.origin.y = -container.frame.size.height
            })
        }
    }
    
}