refactor: 重构 EPMomentViewController,替换 UITableView 为 EPMomentListView
主要变更: 1. 移除 UITableView,改为使用 EPMomentListView 以简化数据展示和交互。 2. 添加顶部固定文案 UILabel,提升用户体验。 3. 通过 EPMomentAPIHelper 统一管理 Moments 列表 API 请求,优化数据加载逻辑。 4. 更新 UI 约束,确保布局适配不同屏幕。 此重构旨在提升代码可维护性和用户界面的一致性。
This commit is contained in:
@@ -1,374 +0,0 @@
|
||||
//
|
||||
// EPTabBarController.swift
|
||||
// YuMi
|
||||
//
|
||||
// Created by AI on 2025-10-09.
|
||||
// Copyright © 2025 YuMi. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SnapKit
|
||||
|
||||
/// EP 系列 TabBar 控制器
|
||||
/// 悬浮设计 + 液态玻璃效果,只包含 Moment 和 Mine 两个 Tab
|
||||
@objc class EPTabBarController: UITabBarController {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
/// 全局事件管理器
|
||||
private var globalEventManager: GlobalEventManager?
|
||||
|
||||
/// 是否已登录
|
||||
private var isLoggedIn: Bool = false
|
||||
|
||||
/// 自定义悬浮 TabBar 容器
|
||||
private var customTabBarView: UIView!
|
||||
|
||||
/// 毛玻璃背景视图
|
||||
private var tabBarBackgroundView: UIVisualEffectView!
|
||||
|
||||
/// Tab 按钮数组
|
||||
private var tabButtons: [UIButton] = []
|
||||
|
||||
// MARK: - Lifecycle
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
// 测试域名配置
|
||||
#if DEBUG
|
||||
APIConfig.testEncryption()
|
||||
#endif
|
||||
|
||||
// 隐藏原生 TabBar
|
||||
self.tabBar.isHidden = true
|
||||
|
||||
// 设置 delegate 以完全控制切换行为
|
||||
self.delegate = self
|
||||
|
||||
setupCustomFloatingTabBar()
|
||||
setupGlobalManagers()
|
||||
setupInitialViewControllers()
|
||||
|
||||
NSLog("[EPTabBarController] 悬浮 TabBar 初始化完成")
|
||||
}
|
||||
|
||||
deinit {
|
||||
globalEventManager?.removeAllDelegates()
|
||||
NSLog("[EPTabBarController] 已释放")
|
||||
}
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
/// 设置自定义悬浮 TabBar
|
||||
private func setupCustomFloatingTabBar() {
|
||||
// 创建悬浮容器
|
||||
customTabBarView = UIView()
|
||||
customTabBarView.translatesAutoresizingMaskIntoConstraints = false
|
||||
customTabBarView.backgroundColor = .clear
|
||||
view.addSubview(customTabBarView)
|
||||
|
||||
// 液态玻璃/毛玻璃效果
|
||||
let effect: UIVisualEffect
|
||||
if #available(iOS 26.0, *) {
|
||||
// iOS 26+ 使用液态玻璃(Material)
|
||||
effect = UIGlassEffect()
|
||||
} else {
|
||||
// iOS 13-17 使用毛玻璃
|
||||
effect = UIBlurEffect(style: .systemMaterial)
|
||||
}
|
||||
|
||||
tabBarBackgroundView = UIVisualEffectView(effect: effect)
|
||||
tabBarBackgroundView.translatesAutoresizingMaskIntoConstraints = false
|
||||
tabBarBackgroundView.layer.cornerRadius = 28
|
||||
tabBarBackgroundView.layer.masksToBounds = true
|
||||
|
||||
// 添加边框
|
||||
tabBarBackgroundView.layer.borderWidth = 0.5
|
||||
tabBarBackgroundView.layer.borderColor = UIColor.white.withAlphaComponent(0.2).cgColor
|
||||
|
||||
customTabBarView.addSubview(tabBarBackgroundView)
|
||||
|
||||
// 简化的布局约束(类似 Masonry 风格)
|
||||
customTabBarView.snp.makeConstraints { make in
|
||||
make.leading.equalTo(view).offset(16)
|
||||
make.trailing.equalTo(view).offset(-16)
|
||||
make.bottom.equalTo(view.safeAreaLayoutGuide).offset(-12)
|
||||
make.height.equalTo(64)
|
||||
}
|
||||
|
||||
tabBarBackgroundView.snp.makeConstraints { make in
|
||||
make.edges.equalTo(customTabBarView)
|
||||
}
|
||||
|
||||
// 添加 Tab 按钮
|
||||
setupTabButtons()
|
||||
|
||||
NSLog("[EPTabBarController] 悬浮 TabBar 设置完成")
|
||||
}
|
||||
|
||||
/// 设置 Tab 按钮
|
||||
private func setupTabButtons() {
|
||||
let momentButton = createTabButton(
|
||||
normalImage: "tab_moment_off",
|
||||
selectedImage: "tab_moment_on",
|
||||
tag: 0
|
||||
)
|
||||
|
||||
let mineButton = createTabButton(
|
||||
normalImage: "tab_mine_off",
|
||||
selectedImage: "tab_mine_on",
|
||||
tag: 1
|
||||
)
|
||||
|
||||
tabButtons = [momentButton, mineButton]
|
||||
|
||||
let stackView = UIStackView(arrangedSubviews: tabButtons)
|
||||
stackView.axis = .horizontal
|
||||
stackView.distribution = .fillEqually
|
||||
stackView.spacing = 20
|
||||
stackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
tabBarBackgroundView.contentView.addSubview(stackView)
|
||||
|
||||
stackView.snp.makeConstraints { make in
|
||||
make.top.equalTo(tabBarBackgroundView).offset(8)
|
||||
make.leading.equalTo(tabBarBackgroundView).offset(20)
|
||||
make.trailing.equalTo(tabBarBackgroundView).offset(-20)
|
||||
make.bottom.equalTo(tabBarBackgroundView).offset(-8)
|
||||
}
|
||||
|
||||
// 默认选中第一个
|
||||
updateTabButtonStates(selectedIndex: 0)
|
||||
}
|
||||
|
||||
/// 创建 Tab 按钮
|
||||
private func createTabButton(normalImage: String, selectedImage: String, tag: Int) -> UIButton {
|
||||
let button = UIButton(type: .custom)
|
||||
button.tag = tag
|
||||
button.adjustsImageWhenHighlighted = false // 禁用高亮效果,避免闪烁
|
||||
|
||||
// 尝试设置自定义图片,如果不存在则使用 SF Symbols
|
||||
if let normalImg = UIImage(named: normalImage), let selectedImg = UIImage(named: selectedImage) {
|
||||
// 正确设置:分别为 normal 和 selected 状态设置图片
|
||||
button.setImage(normalImg, for: .normal)
|
||||
button.setImage(selectedImg, for: .selected)
|
||||
} else {
|
||||
// 使用 SF Symbols 作为备用
|
||||
let fallbackIcons = ["sparkles", "person.circle"]
|
||||
let iconName = fallbackIcons[tag]
|
||||
let imageConfig = UIImage.SymbolConfiguration(pointSize: 24, weight: .medium)
|
||||
let normalIcon = UIImage(systemName: iconName, withConfiguration: imageConfig)
|
||||
|
||||
button.setImage(normalIcon, for: .normal)
|
||||
button.setImage(normalIcon, for: .selected)
|
||||
button.tintColor = .white.withAlphaComponent(0.6)
|
||||
}
|
||||
|
||||
// 图片渲染模式
|
||||
button.imageView?.contentMode = .scaleAspectFit
|
||||
|
||||
// 移除标题
|
||||
button.setTitle(nil, for: .normal)
|
||||
button.setTitle(nil, for: .selected)
|
||||
|
||||
// 设置图片大小约束
|
||||
button.imageView?.snp.makeConstraints { make in
|
||||
make.size.equalTo(28)
|
||||
}
|
||||
|
||||
button.addTarget(self, action: #selector(tabButtonTapped(_:)), for: .touchUpInside)
|
||||
return button
|
||||
}
|
||||
|
||||
/// Tab 按钮点击事件
|
||||
@objc private func tabButtonTapped(_ sender: UIButton) {
|
||||
let newIndex = sender.tag
|
||||
|
||||
// 如果点击的是当前已选中的 tab,不做任何操作
|
||||
if newIndex == selectedIndex {
|
||||
return
|
||||
}
|
||||
|
||||
// 先更新按钮状态
|
||||
updateTabButtonStates(selectedIndex: newIndex)
|
||||
|
||||
// 禁用 UITabBarController 的默认切换动画,避免闪烁
|
||||
UIView.performWithoutAnimation {
|
||||
selectedIndex = newIndex
|
||||
}
|
||||
|
||||
let tabNames = ["动态", "我的"]
|
||||
NSLog("[EPTabBarController] 选中 Tab: \(tabNames[newIndex])")
|
||||
}
|
||||
|
||||
/// 更新 Tab 按钮状态
|
||||
private func updateTabButtonStates(selectedIndex: Int) {
|
||||
// 禁用按钮交互,避免快速点击
|
||||
tabButtons.forEach { $0.isUserInteractionEnabled = false }
|
||||
|
||||
for (index, button) in tabButtons.enumerated() {
|
||||
let isSelected = (index == selectedIndex)
|
||||
|
||||
// 直接设置 isSelected 属性即可,图片会自动切换
|
||||
button.isSelected = isSelected
|
||||
|
||||
// SF Symbols 的情况需要手动更新 tintColor
|
||||
if button.currentImage?.isSymbolImage == true {
|
||||
button.tintColor = isSelected ? .white : .white.withAlphaComponent(0.6)
|
||||
}
|
||||
|
||||
// 选中状态缩放动画
|
||||
UIView.animate(withDuration: 0.2, delay: 0, options: [.curveEaseOut], animations: {
|
||||
button.transform = isSelected ? CGAffineTransform(scaleX: 1.1, y: 1.1) : .identity
|
||||
})
|
||||
}
|
||||
|
||||
// 延迟恢复按钮交互
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) {
|
||||
self.tabButtons.forEach { $0.isUserInteractionEnabled = true }
|
||||
}
|
||||
}
|
||||
|
||||
/// 设置全局管理器
|
||||
private func setupGlobalManagers() {
|
||||
globalEventManager = GlobalEventManager.shared()
|
||||
globalEventManager?.setupSDKDelegates()
|
||||
|
||||
// TODO: v0.2 版本暂时禁用房间最小化视图(无房间功能)
|
||||
// 后续版本可通过 Build Configuration 或版本号判断是否启用
|
||||
/*
|
||||
if let containerView = view {
|
||||
globalEventManager?.setupRoomMiniView(on: containerView)
|
||||
}
|
||||
*/
|
||||
|
||||
// 注册社交分享回调
|
||||
globalEventManager?.registerSocialShareCallback()
|
||||
|
||||
NSLog("[EPTabBarController] 全局管理器设置完成(v0.2 - 无 MiniRoom)")
|
||||
}
|
||||
|
||||
/// 设置初始 ViewController(未登录状态)
|
||||
private func setupInitialViewControllers() {
|
||||
// TODO: 暂时使用空白页面占位
|
||||
let blankVC1 = UIViewController()
|
||||
blankVC1.view.backgroundColor = .white
|
||||
blankVC1.tabBarItem = createTabBarItem(
|
||||
title: "动态",
|
||||
normalImage: "tab_moment_normal",
|
||||
selectedImage: "tab_moment_selected"
|
||||
)
|
||||
|
||||
let blankVC2 = UIViewController()
|
||||
blankVC2.view.backgroundColor = .white
|
||||
blankVC2.tabBarItem = createTabBarItem(
|
||||
title: "我的",
|
||||
normalImage: "tab_mine_normal",
|
||||
selectedImage: "tab_mine_selected"
|
||||
)
|
||||
|
||||
viewControllers = [blankVC1, blankVC2]
|
||||
selectedIndex = 0
|
||||
|
||||
NSLog("[EPTabBarController] 初始 ViewControllers 设置完成")
|
||||
}
|
||||
|
||||
/// 创建 TabBarItem
|
||||
/// - Parameters:
|
||||
/// - title: 标题
|
||||
/// - normalImage: 未选中图标名称
|
||||
/// - selectedImage: 选中图标名称
|
||||
/// - Returns: UITabBarItem
|
||||
private func createTabBarItem(title: String, normalImage: String, selectedImage: String) -> UITabBarItem {
|
||||
let item = UITabBarItem(
|
||||
title: title,
|
||||
image: UIImage(named: normalImage)?.withRenderingMode(.alwaysOriginal),
|
||||
selectedImage: UIImage(named: selectedImage)?.withRenderingMode(.alwaysOriginal)
|
||||
)
|
||||
return item
|
||||
}
|
||||
|
||||
// MARK: - Public Methods
|
||||
|
||||
/// 登录成功后刷新 TabBar
|
||||
/// - Parameter isLogin: 是否已登录
|
||||
func refreshTabBar(isLogin: Bool) {
|
||||
isLoggedIn = isLogin
|
||||
|
||||
if isLogin {
|
||||
setupLoggedInViewControllers()
|
||||
} else {
|
||||
setupInitialViewControllers()
|
||||
}
|
||||
|
||||
NSLog("[EPTabBarController] TabBar 已刷新,登录状态: \(isLogin)")
|
||||
}
|
||||
|
||||
/// 设置登录后的 ViewControllers
|
||||
private func setupLoggedInViewControllers() {
|
||||
// 只在 viewControllers 为空或不是正确类型时才创建
|
||||
if viewControllers?.count != 2 ||
|
||||
!(viewControllers?[0] is EPMomentViewController) ||
|
||||
!(viewControllers?[1] is EPMineViewController) {
|
||||
|
||||
// 创建真实的 ViewController(OC 类)
|
||||
let momentVC = EPMomentViewController()
|
||||
momentVC.tabBarItem = createTabBarItem(
|
||||
title: "动态",
|
||||
normalImage: "tab_moment_normal",
|
||||
selectedImage: "tab_moment_selected"
|
||||
)
|
||||
|
||||
let mineVC = EPMineViewController()
|
||||
mineVC.tabBarItem = createTabBarItem(
|
||||
title: "我的",
|
||||
normalImage: "tab_mine_normal",
|
||||
selectedImage: "tab_mine_selected"
|
||||
)
|
||||
|
||||
viewControllers = [momentVC, mineVC]
|
||||
NSLog("[EPTabBarController] 登录后 ViewControllers 创建完成 - Moment & Mine")
|
||||
}
|
||||
|
||||
selectedIndex = 0
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - UITabBarControllerDelegate
|
||||
|
||||
extension EPTabBarController: UITabBarControllerDelegate {
|
||||
|
||||
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
|
||||
NSLog("[EPTabBarController] 选中 Tab: \(item.title ?? "Unknown")")
|
||||
}
|
||||
|
||||
/// 禁用系统默认的切换动画
|
||||
func tabBarController(_ tabBarController: UITabBarController,
|
||||
animationControllerForTransitionFrom fromVC: UIViewController,
|
||||
to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
|
||||
// 返回 nil 表示不使用动画
|
||||
return nil
|
||||
}
|
||||
|
||||
/// 完全控制是否允许切换
|
||||
func tabBarController(_ tabBarController: UITabBarController,
|
||||
shouldSelect viewController: UIViewController) -> Bool {
|
||||
// 允许切换,但通过返回 nil 的 animationController 来禁用动画
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - OC Compatibility
|
||||
|
||||
extension EPTabBarController {
|
||||
|
||||
/// OC 兼容:创建实例的工厂方法
|
||||
@objc static func create() -> EPTabBarController {
|
||||
return EPTabBarController()
|
||||
}
|
||||
|
||||
/// OC 兼容:刷新 TabBar 方法
|
||||
@objc func refreshTabBarWithIsLogin(_ isLogin: Bool) {
|
||||
refreshTabBar(isLogin: isLogin)
|
||||
}
|
||||
}
|
@@ -17,8 +17,7 @@
|
||||
/// @param pageSize 一页的个数
|
||||
/// @param types 类型 0,2
|
||||
+ (void)momentsRecommendList:(HttpRequestHelperCompletion)completion page:(NSString *)page pageSize:(NSString *)pageSize types:(NSString *)types {
|
||||
NSString * fang = [NSString stringFromBase64String:@"ZHluYW1pYy9zcXVhcmUvcmVjb21tZW5kRHluYW1pY3M="];///dynamic/square/recommendDynamics
|
||||
[self makeRequest:fang method:HttpRequestHelperMethodGET completion:completion, __FUNCTION__, page, pageSize, types, nil];
|
||||
[self makeRequest:@"dynamic/square/recommendDynamics" method:HttpRequestHelperMethodGET completion:completion, __FUNCTION__, page, pageSize, types, nil];
|
||||
}
|
||||
|
||||
/// 朋友圈动态最新列表
|
||||
@@ -27,8 +26,7 @@
|
||||
/// @param pageSize 一页的个数
|
||||
/// @param types 类型 0,2
|
||||
+ (void)momentsLatestList:(HttpRequestHelperCompletion)completion dynamicId:(NSString *)dynamicId pageSize:(NSString *)pageSize types:(NSString *)types {
|
||||
NSString * fang = [NSString stringFromBase64String:@"ZHluYW1pYy9zcXVhcmUvbGF0ZXN0RHluYW1pY3M="];///dynamic/square/latestDynamics
|
||||
[self makeRequest:fang method:HttpRequestHelperMethodGET completion:completion, __FUNCTION__, dynamicId, pageSize, types, nil];
|
||||
[self makeRequest:@"dynamic/square/latestDynamics" method:HttpRequestHelperMethodGET completion:completion, __FUNCTION__, dynamicId, pageSize, types, nil];
|
||||
}
|
||||
|
||||
/// 朋友圈动态关注列表
|
||||
|
Reference in New Issue
Block a user