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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 09:07:55