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

CustomTabbarViewController:创建并管理带动态圆形高亮的自定义Tab Bar界面

自定义TabBar控制器(CustomTabbarViewController)

CustomTabbarViewController 是UITabBarController的自定义子类,专为iOS应用打造定制化且视觉美观的Tab Bar界面。它负责管理多个与Tab项绑定的视图控制器的展示,同时支持Tab Bar外观与行为的定制。

核心特性

  • 自定义Tab Bar外观:可定制背景色、色调(tint color)和圆角半径。
  • 动态圆形高亮指示器:选中Tab项时,圆形指示器会动画移动到对应位置,为用户提供清晰的视觉反馈,提升交互体验。
  • 自适应布局:Tab Bar会自动调整布局,适配设备方向变化和安全区域内边距,确保在不同设备、不同方向下都能呈现一致美观的效果。

完整实现代码

import UIKit

class TabbarViewController: UITabBarController {
    
    var circle: UIView?
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        guard let selectedItem = tabBar.selectedItem, let index = tabBar.items?.firstIndex(of: selectedItem) else { return }
        let frame = frameForTabAtIndex(index: index)
        circle?.center.x = frame.origin.x + frame.width/2
        circle?.center.y = frame.origin.y + frame.height/2
        circle?.alpha = 1
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.navigationController?.setNavigationBarHidden(true, animated: false)
        
        self.setupTabBarUI()
        guard let itemCount = tabBar.items?.count else { return }
        let numberOfItems = CGFloat(itemCount)
        let tabBarItemSize = CGSize(width: (tabBar.frame.width / numberOfItems) - 20, height: tabBar.frame.height)
        circle = UIView(frame: CGRect(x: 0, y: 0, width: tabBarItemSize.height, height: tabBarItemSize.height))
        circle?.backgroundColor = #colorLiteral(red: 0.2770082951, green: 0.5475645661, blue: 0, alpha: 0.28)
        circle?.layer.cornerRadius = circle!.frame.width/2
        circle?.alpha = 0
        tabBar.addSubview(circle!)
        tabBar.sendSubviewToBack(circle!)
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        self.setupCustomTabBarFrame()
    }
    
}

extension TabbarViewController {
    // MARK: 私有方法
    
    private func setupCustomTabBarFrame() {
        let height = self.view.safeAreaInsets.bottom + 64
        
        var tabFrame = self.tabBar.frame
        tabFrame.size.height = height
        tabFrame.origin.y = self.view.frame.size.height - height
        
        self.tabBar.frame = tabFrame
        self.tabBar.setNeedsLayout()
        self.tabBar.layoutIfNeeded()
    }
    
    private func setupTabBarUI() {
        // 设置颜色和圆角
        self.tabBar.layer.cornerRadius = 22
        self.tabBar.layer.masksToBounds = true
        self.tabBar.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
        self.tabBar.backgroundColor = UIColor(red: 245/255, green: 246/255, blue: 247/255, alpha: 1)
        self.tabBar.tintColor = #colorLiteral(red: 0.4670000076, green: 0.6430000067, blue: 0.3919999897, alpha: 1)
        //            self.tabBar.unselectedItemTintColor = UIColor.green
        
        // 移除底部分割线
        if #available(iOS 13.0, *) {
            let appearance = self.tabBar.standardAppearance
            appearance.shadowImage = nil
            appearance.shadowColor = nil
            self.tabBar.standardAppearance = appearance
        } else {
            self.tabBar.shadowImage = UIImage()
            self.tabBar.backgroundImage = UIImage()
        }
    }
    
    func frameForTabAtIndex(index: Int) -> CGRect {
        var frames = tabBar.subviews.compactMap { (view:UIView) -> CGRect? in
            if let controlView = view as? UIControl {
                for item in controlView.subviews {
                    if let imageView = item as? UIImageView {
                        return imageView.superview!.convert(imageView.frame, to: tabBar)
                    }
                }
                return controlView.frame
            }
            return nil
        }
        frames.sort { $0.origin.x < $1.origin.x }
        guard frames.count > index else {
            return frames.last ?? CGRect.zero
        }
        return frames[index]
    }
    
    override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
        guard let index = tabBar.items?.firstIndex(of: item) else { return }
        let frame = frameForTabAtIndex(index: index)
        self.circle?.center.x = frame.origin.x + frame.width/2
        self.circle?.center.y = frame.origin.y + frame.height/2
    }
}

效果示例

示例图片

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 21:24:50