You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于为单个视图控制器添加UIToolbar并通过标准UIKit动画控制其显隐的技术问询

关于为单个视图控制器添加UIToolbar并通过标准UIKit动画控制其显隐的技术问询

嘿,我来帮你捋捋这个问题。首先得明确一点:navigationController?.setToolbarHidden(_:animated:)这个方法只针对导航控制器自身管理的UIToolbar,所以你在单个VC里单独添加的Toolbar肯定没法直接用这个API,这就是你遇到问题的根源。

接下来分两种情况给你实用的解决方案:


一、给单独的UIToolbar实现系统风格的显隐动画

如果你只是想让这个单独的Toolbar拥有和系统导航栏Toolbar一致的显隐动画效果,完全不需要手动硬写复杂逻辑,UIKit已经给我们提供了现成的动画参数可以复用:

  1. 直接模拟系统动画参数
    系统的Toolbar显隐动画用的是特定的时长和曲线,你可以直接在UIView动画里套用这些参数:
// 隐藏Toolbar
UIView.animate(withDuration: 0.3, delay: 0, options: [.curveEaseInOut, .beginFromCurrentState], animations: {
    self.toolbar.alpha = 0
    self.toolbar.transform = CGAffineTransform(translationX: 0, y: self.toolbar.bounds.height)
}, completion: { _ in
    self.toolbar.isHidden = true
})

// 显示Toolbar
self.toolbar.isHidden = false
UIView.animate(withDuration: 0.3, delay: 0, options: [.curveEaseInOut, .beginFromCurrentState], animations: {
    self.toolbar.alpha = 1
    self.toolbar.transform = .identity
}, completion: nil)

这里的0.3秒是系统默认的栏动画时长,.curveEaseInOut是系统用的动画曲线,.beginFromCurrentState能保证动画中途被打断时也能平滑过渡,和系统行为完全一致。

  1. 利用UINavigationController的动画参数(更精准)
    如果你想完全和当前导航控制器的动画参数同步,可以直接获取导航控制器的动画配置:
let duration = navigationController?.hideShowBarDuration ?? 0.3
let curve = UIView.AnimationOptions(rawValue: UInt((navigationController?.hideShowBarAnimationCurve.rawValue)!))

// 隐藏动画示例
UIView.animate(withDuration: duration, delay: 0, options: curve.union(.beginFromCurrentState), animations: {
    self.toolbar.alpha = 0
    self.toolbar.transform = CGAffineTransform(translationX: 0, y: self.toolbar.bounds.height)
}, completion: { _ in
    self.toolbar.isHidden = true
})

这样就能保证你的Toolbar动画和系统导航栏的动画完全同节奏。


二、让普通UIView拥有类似导航栏的滚动驱动显隐效果

如果你想让一个普通UIView也能像导航栏那样,随着用户滚动UIScrollView(比如UITableView、UICollectionView)自动滑入滑出,可以通过UIScrollViewDelegate来实现:

  1. 监听滚动偏移,计算动画进度
    首先在VC里实现UIScrollViewDelegate的scrollViewDidScroll(_:)方法:
var lastContentOffset: CGFloat = 0

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    let currentOffset = scrollView.contentOffset.y
    let offsetDiff = currentOffset - lastContentOffset
    
    // 根据滚动方向计算视图的目标位置
    var targetY = customView.frame.origin.y
    if offsetDiff > 0 {
        // 向下滚动,隐藏视图
        targetY = min(view.bounds.height, targetY + offsetDiff)
    } else {
        // 向上滚动,显示视图
        targetY = max(view.bounds.height - customView.bounds.height, targetY + offsetDiff)
    }
    
    // 应用系统风格的动画
    UIView.animate(withDuration: 0.1, delay: 0, options: [.curveEaseOut, .beginFromCurrentState], animations: {
        self.customView.frame.origin.y = targetY
    }, completion: nil)
    
    lastContentOffset = currentOffset
}

这里的customView就是你要控制的普通UIView,通过监听滚动方向来调整它的Y坐标,实现滑入滑出的效果。

  1. 关于UIBarPositioningDelegate的说明
    你提到的UIBarPositioningDelegate其实主要是用来告诉UIKit你的Bar(比如UIToolbar)在屏幕上的位置(比如是否附着在顶部/底部),它并不能直接驱动动画,但如果你是用UIToolbar的话,设置它的delegate为当前VC并实现barPosition(for:)方法,可以让Toolbar的布局更贴合系统规范,比如避免被安全区域遮挡:
extension YourViewController: UIBarPositioningDelegate {
    func barPosition(for bar: UIBarPositioning) -> UIBarPosition {
        return .bottomAttached // 如果你的Toolbar在底部
    }
}

总结一下

  • 单独的UIToolbar没法用导航控制器的setToolbarHidden,但可以通过模拟系统动画参数实现一致的显隐效果
  • 普通UIView可以通过监听滚动视图的偏移来实现类似导航栏的滚动驱动动画
  • UIBarPositioningDelegate主要用于Bar的位置布局,不是动画驱动,但能优化Toolbar的系统兼容性

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 09:28:06