Swift 3中全设备TableView翻转动画及底部弹出收起实现求助
嘿,这个需求我之前做过类似的,给你一套完整的实现方案,保证适配所有设备,而且动画流畅~
核心思路
咱们要实现的效果拆解下来就是三个关键点:
- TableView固定占屏幕70%高度,适配所有设备
- 从底部平滑弹出/收起的动画
- 点击屏幕任意位置(TableView外)触发收起
下面直接上代码和细节说明:
1. 基础配置与UI搭建
首先在你的ViewController里定义所需的控件和变量,用Swift 3的语法来写:
import UIKit class TableViewPopupVC: UIViewController, UITableViewDataSource, UITableViewDelegate { // 核心控件 private let popupTableView = UITableView() private let backgroundMask = UIView() // 适配参数:TableView占屏幕70%高度 private let tableViewHeightRatio: CGFloat = 0.7 private let screenBounds = UIScreen.main.bounds // 用于AutoLayout的底部约束(推荐用AutoLayout适配旋转) private var tableViewBottomConstraint: NSLayoutConstraint! override func viewDidLoad() { super.viewDidLoad() setupBackgroundMask() setupPopupTableView() setupTriggerButton() // 可以加个按钮测试弹出 } }
2. 背景遮罩与点击收起逻辑
背景遮罩不仅能让视觉效果更突出,还能用来监听“点击屏幕任意位置”的操作:
extension TableViewPopupVC { private func setupBackgroundMask() { backgroundMask.frame = screenBounds backgroundMask.backgroundColor = UIColor.black.withAlphaComponent(0.5) backgroundMask.isHidden = true // 添加点击手势,触发收起动画 let tapGesture = UITapGestureRecognizer(target: self, action: #selector(hidePopupTableView)) backgroundMask.addGestureRecognizer(tapGesture) view.addSubview(backgroundMask) view.sendSubview(toBack: backgroundMask) // 把遮罩放在TableView下面 } }
3. TableView布局与适配
这里用AutoLayout来做适配,不管设备尺寸还是屏幕旋转,都能自动调整:
extension TableViewPopupVC { private func setupPopupTableView() { popupTableView.translatesAutoresizingMaskIntoConstraints = false popupTableView.backgroundColor = .white popupTableView.register(UITableViewCell.self, forCellReuseIdentifier: "DefaultCell") popupTableView.dataSource = self popupTableView.delegate = self view.addSubview(popupTableView) // 设置约束:左右贴边,高度为屏幕70%,初始在屏幕底部外 NSLayoutConstraint.activate([ popupTableView.leadingAnchor.constraint(equalTo: view.leadingAnchor), popupTableView.trailingAnchor.constraint(equalTo: view.trailingAnchor), popupTableView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: tableViewHeightRatio) ]) // 单独保存底部约束,方便动画修改 tableViewBottomConstraint = popupTableView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: screenBounds.height) tableViewBottomConstraint.isActive = true } // TableView数据源实现(随便写点测试数据) func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 20 } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "DefaultCell", for: indexPath) cell.textLabel?.text = "测试行 \(indexPath.row + 1)" return cell } }
4. 弹出/收起动画实现
用UIView的动画块来实现平滑的位移效果,Swift 3里的语法是UIView.animate(withDuration:animations:completion:):
extension TableViewPopupVC { // 弹出TableView @objc func showPopupTableView() { backgroundMask.isHidden = false // 修改底部约束,让TableView滑上来 tableViewBottomConstraint.constant = 0 UIView.animate(withDuration: 0.3) { self.view.layoutIfNeeded() } } // 收起TableView @objc func hidePopupTableView() { tableViewBottomConstraint.constant = screenBounds.height UIView.animate(withDuration: 0.3, animations: { self.view.layoutIfNeeded() }) { _ in self.backgroundMask.isHidden = true } } // 加个测试按钮,方便触发弹出 private func setupTriggerButton() { let showButton = UIButton(type: .system) showButton.setTitle("弹出TableView", for: .normal) showButton.addTarget(self, action: #selector(showPopupTableView), for: .touchUpInside) showButton.frame = CGRect(x: 40, y: 100, width: screenBounds.width - 80, height: 44) view.addSubview(showButton) } }
关键适配说明
- 用
UIScreen.main.bounds获取屏幕尺寸,结合比例tableViewHeightRatio设置高度,不管是iPhone还是iPad,各种尺寸都能适配 - 用AutoLayout约束而不是固定frame,支持屏幕旋转时自动调整布局
- 背景遮罩覆盖整个屏幕,点击任意非TableView区域都会触发收起,完美满足“点击屏幕任意位置收起”的需求
如果你的项目里用的是frame布局(不推荐,但也能实现),可以把布局代码改成:
// setupPopupTableView里用frame的写法 let tableViewHeight = screenBounds.height * tableViewHeightRatio popupTableView.frame = CGRect(x: 0, y: screenBounds.height, width: screenBounds.width, height: tableViewHeight) view.addSubview(popupTableView) // 弹出动画 @objc func showPopupTableView() { backgroundMask.isHidden = false UIView.animate(withDuration: 0.3) { self.popupTableView.frame.origin.y = self.screenBounds.height - self.popupTableView.frame.height } } // 收起动画 @objc func hidePopupTableView() { UIView.animate(withDuration: 0.3, animations: { self.popupTableView.frame.origin.y = self.screenBounds.height }) { _ in self.backgroundMask.isHidden = true } }
这样也能实现效果,但AutoLayout的适配性更好,推荐用第一种方案。
内容的提问来源于stack exchange,提问作者User
相关产品推荐
相关产品推荐

