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

Swift使用SideMenu时如何在侧边栏底部添加固定不滚动的退出按钮

实现侧边菜单固定底部Sign-out按钮的方案

现有UITableViewController的tableFooterView默认跟随列表滚动,要实现固定不滚动的底部退出按钮,可选择以下两种实现方式:


方案1:将MenuListController改为普通UIViewController(推荐)

把原本UITableViewController的结构改成普通UIViewController,内部手动添加tableView和固定在底部的sign-out按钮,从根本上避免tableView覆盖整个视图导致按钮无法固定的问题。

修改后代码:

import UIKit
import SideMenu

// 替换原有MenuListController实现
class MenuListController: UIViewController {
    var menuItems = [[String: String]]()
    // 手动添加列表视图
    private let tableView = UITableView()
    // 底部固定退出按钮
    private let signOutButton = UIButton()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupBaseUI()
        setupTableView()
        setupSignOutButton()
        
        // 原有菜单项初始化逻辑不变
        menuItems.append(["name": "隐私设置", "img": "privacy", "key" : "privacy"])
        menuItems.append(["name": "反馈问题", "img": "report_issue", "key": "report_issue"])
    }
    
    private func setupBaseUI() {
        view.backgroundColor = .white
        // 列表和按钮都添加到根视图
        [tableView, signOutButton].forEach {
            $0.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview($0)
        }
    }
    
    private func setupTableView() {
        tableView.dataSource = self
        tableView.delegate = self
        tableView.separatorStyle = .none
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
        // 列表约束:顶部到导航栏底部,底部到退出按钮顶部
        NSLayoutConstraint.activate([
            tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
            tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            tableView.bottomAnchor.constraint(equalTo: signOutButton.topAnchor, constant: -16)
        ])
    }
    
    private func setupSignOutButton() {
        signOutButton.setTitle("退出登录", for: .normal)
        let color = UIColor.init(hexString: "#1A73E9")
        signOutButton.setTitleColor(color, for: .normal)
        signOutButton.addTarget(self, action: #selector(signOutButtonTapped), for: .touchUpInside)
        // 按钮约束:固定在底部安全区
        NSLayoutConstraint.activate([
            signOutButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
            signOutButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -20),
            signOutButton.heightAnchor.constraint(equalToConstant: 40)
        ])
    }
    
    @objc func signOutButtonTapped(_ sender: AnyObject?) {
        print("触发退出登录逻辑")
    }
}

extension MenuListController: UITableViewDataSource, UITableViewDelegate {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        menuItems.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        if menuItems.indices.contains(indexPath.row) {
            let dict = menuItems[indexPath.row]
            cell.textLabel?.text = dict["name"]
            if let img = dict["img"] {
                cell.imageView?.image = UIImage(named: img)
            }
        }
        return cell
    }
}

方案2:不修改MenuListController继承关系,直接将按钮添加到侧边栏容器视图

如果你不想改动现有MenuListController的UITableViewController继承结构,可以在配置侧边菜单的时候,直接把退出按钮加到SideMenuNavigationController的根视图上,同时给tableView加底部内边距避免列表内容被按钮遮挡。

修改configureSideMenu方法代码:

func configureSideMenu() {
    let menuListVC = MenuListController()
    menu = SideMenuNavigationController(rootViewController: menuListVC)
    guard let menu = menu else { return }
    
    // 原有导航栏配置逻辑保持不变
    menu.navigationBar.setBackgroundImage(UIImage(named: "top_navbrBG"), for: .default)
    let firstFrame = CGRect(x: 20, y: 0, width: menu.navigationBar.frame.width ?? 0/2, height: menu.navigationBar.frame.height ?? 0)
    let firstLabel = UILabel(frame: firstFrame)
    firstLabel.text = "设置"
    menu.navigationBar.addSubview(firstLabel)
    SideMenuManager.default.addPanGestureToPresent(toView: self.view)
    
    let screenSize = UIScreen.main.bounds
    let screenHeight = screenSize.height + 40
    let leftBorderView = UIView(frame: CGRect(x: 1, y: -40, width: 1, height: screenHeight))
    leftBorderView.backgroundColor = UIColor.init(hexString: "#cfcfcf")
    menu.navigationBar.addSubview(leftBorderView)
    
    // 新增:添加固定底部的退出按钮
    let signOutBtn = getSignOutButton()
    signOutBtn.translatesAutoresizingMaskIntoConstraints = false
    menu.view.addSubview(signOutBtn)
    NSLayoutConstraint.activate([
        signOutBtn.leadingAnchor.constraint(equalTo: menu.view.leadingAnchor, constant: 20),
        signOutBtn.bottomAnchor.constraint(equalTo: menu.view.safeAreaLayoutGuide.bottomAnchor, constant: -20),
        signOutBtn.heightAnchor.constraint(equalToConstant: 40)
    ])
    // 给列表加底部内边距,避免滚动到最下方时内容被按钮遮挡
    menuListVC.tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 70, right: 0)
    // 注意:需要删除原有MenuListController里的`tableView.tableFooterView = getSignOutButton()`代码,避免重复添加按钮
}

内容的提问来源于stack exchange,提问作者user10469417

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 11:12:02