iOS 抖音导航栏首页一键分两列功能的实现
要实现 iOS 抖音首页导航栏的“一键分两列”功能(通常指将单列内容切换为双列瀑布流布局),需结合自定义导航栏控件与布局动态切换逻辑。以下是关键实现步骤和技术要点,基于 iOS 原生开发框架(Swift/Objective-C):
一、核心功能需求分析
- 导航栏按钮触发
在导航栏右侧添加功能按钮(如“分列”图标),点击后切换内容布局(单列 ↔ 双列)。 - 内容布局动态切换
内容区域(如UICollectionView
)需支持单列与双列布局的无缝切换。 - 状态持久化
用户退出后再进入时,需保留上次的布局状态。
二、实现步骤与代码示例
1. 自定义导航栏按钮
- 在
viewDidLoad
中添加导航栏按钮,并绑定点击事件:// Swift 示例 let layoutButton = UIBarButtonItem(image: UIImage(named: "grid_icon"), style: .plain, target: self, action: #selector(toggleLayout)) navigationItem.rightBarButtonItem = layoutButton
2. 动态切换集合视图布局
- 使用
UICollectionViewFlowLayout
动态调整列数:private var isSingleColumn = false // 默认双列@objc func toggleLayout() {isSingleColumn.toggle()updateCollectionViewLayout() }private func updateCollectionViewLayout() {let layout = UICollectionViewFlowLayout()if isSingleColumn {layout.itemSize = CGSize(width: view.bounds.width, height: 200) // 单列宽度全屏} else {let columnWidth = (view.bounds.width - 15) / 2 // 双列,考虑间距layout.itemSize = CGSize(width: columnWidth, height: 300)}collectionView.setCollectionViewLayout(layout, animated: true) }
3. 保存布局状态
- 使用
UserDefaults
持久化用户选择:private func saveLayoutPreference() {UserDefaults.standard.set(isSingleColumn, forKey: "isSingleColumnMode") }// 在 viewDidLoad 中读取状态 override func viewDidLoad() {super.viewDidLoad()isSingleColumn = UserDefaults.standard.bool(forKey: "isSingleColumnMode")updateCollectionViewLayout() }
4. 处理导航栏适配问题
- 状态栏高度适配:全面屏(如 iPhone X 及以上)需额外处理安全区域:
if #available(iOS 11.0, *) {collectionView.contentInsetAdjustmentBehavior = .neverlet statusBarHeight = UIApplication.shared.statusBarFrame.heightcollectionView.contentInset = UIEdgeInsets(top: statusBarHeight + 44, left: 0, bottom: 0, right: 0) }
- 导航栏透明效果:若需抖音式全屏沉浸感,隐藏导航栏底部阴影线:
// Objective-C 示例(通过查找导航栏底部分割线并隐藏) - (UIImageView *)findNavBarBottomLine:(UIView *)view {if ([view isKindOfClass:UIImageView.class] && view.bounds.size.height <= 1.0) {return (UIImageView *)view;}for (UIView *subview in view.subviews) {UIImageView *imageView = [self findNavBarBottomLine:subview];if (imageView) return imageView;}return nil; }
三、技术要点与优化
-
性能优化
- 使用
invalidateLayout()
替代重新创建layout
对象,减少内存开销。 - 复用单元格(
dequeueReusableCell
)避免滚动卡顿。
- 使用
-
动效增强
- 添加布局切换的过渡动画:
UIView.animate(withDuration: 0.3) {self.collectionView.performBatchUpdates({self.collectionView.setCollectionViewLayout(newLayout, animated: true)}) }
- 添加布局切换的过渡动画:
-
多列布局的间距处理
- 通过
minimumInteritemSpacing
和minimumLineSpacing
控制双列间距:layout.minimumInteritemSpacing = 5 layout.minimumLineSpacing = 10
- 通过
-
次级导航多列支持参考
- 若需实现类似“次级导航多列展开”效果(如电商类目),可参考易营宝的多列次级导航方案:
- 开启自定义导航面板,设置多列样式。
- 通过
列数 = 次级导航数 / 行数
动态计算布局。
- 若需实现类似“次级导航多列展开”效果(如电商类目),可参考易营宝的多列次级导航方案:
四、完整流程示意图
用户点击导航栏按钮↓
触发 toggleLayout 方法↓
更新 isSingleColumn 状态↓
根据状态创建单列/双列 FlowLayout↓
执行 collectionView.setCollectionViewLayout(animated: true)↓
保存状态至 UserDefaults
注意事项
- 全面屏适配:iPhone X 及以上机型需额外处理底部
Home Bar
区域(增加safeAreaInsets.bottom
)。 - 全局样式统一:若需与其他页面导航栏样式一致,建议通过
UINavigationBar.appearance()
全局配置。 - 跨版本兼容:iOS 11 后
automaticallyAdjustsScrollViewInsets
失效,需改用contentInsetAdjustmentBehavior
。
可通过调整 UICollectionViewLayout
参数快速实现布局切换,结合状态持久化与动效优化,即可复现抖音式“一键分列”体验。
相关文章:
iOS 抖音导航栏首页一键分两列功能的实现
要实现 iOS 抖音首页导航栏的“一键分两列”功能(通常指将单列内容切换为双列瀑布流布局),需结合自定义导航栏控件与布局动态切换逻辑。以下是关键实现步骤和技术要点,基于 iOS 原生开发框架(Swift/Objective-C&#x…...
零基础入门 C 语言基础知识(含面试题):结构体、联合体、枚举、链表、环形队列、指针全解析!
🌟 零基础入门 C 语言基础知识(含面试题):结构体、联合体、枚举、链表、环形队列、指针全解析! C 语言是所有程序员通向“系统世界”的第一把钥匙。很多嵌入式开发、操作系统内核、网络通信、图形引擎,背后…...

【Linux】Ubuntu 创建应用图标的方式汇总,deb/appimage/通用方法
Ubuntu 创建应用图标的方式汇总,deb/appimage/通用方法 对于标准的 Ubuntu(使用 GNOME 桌面),desktop 后缀的桌面图标文件主要保存在以下三个路径: 当前用户的桌面目录(这是最常见的位置)。所…...
【Unity】R3 CSharp 响应式编程 - 使用篇(集合)(三)
1、ObservableList 基础 List 类型测试 using System;using System.Collections.Specialized;using ObservableCollections;using UnityEngine;namespace Aladdin.Standard.Observable.Collections.List{public class ObservableListTest : MonoBehaviour{protected readonly O…...
振动力学:弹性杆的纵向振动(固有振动和固有频率的概念)
文章1、2、3中讨论的是离散系统的振动特性,然而实际系统的惯性质量、弹性、阻尼等特性都是连续分布的,因而成为连续系统或分布参数系统。确定连续介质中无数个点的运动需要无限个广义坐标,因此也称为无限自由度系统,典型的结构例如:弦、杆、膜、环、梁、板、壳等,也称为弹…...

LangGraph--Agent工作流
Agent的工作流 下面展示了如何创建一个“计划并执行”风格的代理。 这在很大程度上借鉴了 计划和解决 论文以及Baby-AGI项目。 核心思想是先制定一个多步骤计划,然后逐项执行。完成一项特定任务后,您可以重新审视计划并根据需要进行修改。 般的计算图如…...

Spring Boot 常用注解面试题深度解析
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot 常用注解面试题深度解析一、核心…...

Linux系统的CentOS7发行版安装MySQL80
文章目录 前言Linux命令行内的”应用商店”安装CentOS的安装软件的yum命令安装MySQL1. 配置yum仓库2. 使用yum安装MySQL3. 安装完成后,启动MySQL并配置开机自启动4. 检查MySQL的运行状态 MySQL的配置1. 获取MySQL的初始密码2. 登录MySQL数据库系统3. 修改root密码4.…...

408第一季 - 数据结构 - 栈与队列
栈 闲聊 栈是一个线性表 栈的特点是后进先出 然后是一个公式 比如123要入栈,一共有5种排列组合的出栈 栈的数组实现 这里有两种情况,,一个是有下标为-1的,一个没有 代码不用看,真题不会考 栈的链式存储结构 L ->…...

【RTP】Intra-Refresh模式下的 H.264 输出,RTP打包的方式和普通 H.264 流并没有本质区别
对于 Intra-Refresh 模式下的 H.264 输出,RTP 打包 的方式和普通 H.264 流并没有本质区别:你依然是在对一帧一帧的 NAL 单元进行 RTP 分包,只不过这些 NAL 单元内部有部分宏块是 “帧内编码” 而已。下面分步骤说明: 1. 原理回顾:RFC 6184 H.264 over RTP 按照 RFC 6184 …...
nano编辑器的详细使用教程
以下是 Linux 下 nano 编辑器 的详细使用指南,涵盖安装、基础操作、高级功能、快捷键以及常见问题处理。 一、安装 nano 大多数 Linux 发行版已预装 nano。如果没有安装,可以通过以下命令安装: Debian/Ubuntu 系:sudo apt update…...

Redis实战-消息队列篇
前言: 讲讲做消息队列遇到的问题。 今日所学: 异步优化消息队列基于stream实现异步下单 1. 异步优化 1.1 需求分析 1.1.1 现有下单流程: 1.查询优惠劵 2.判断是否是秒杀时间,库存是否充足 3.实现一人一单 在这个功能中&…...

(三)Linux性能优化-CPU-CPU 使用率
CPU使用率 user(通常缩写为 us),代表用户态 CPU 时间。注意,它不包括下面的 nice 时间,但包括了 guest 时间。nice(通常缩写为 ni),代表低优先级用户态 CPU 时间,也就是进…...

佰力博科技与您探讨材料介电性能测试的影响因素
1、频率依赖性 材料的介电性能通常具有显著的频率依赖性。在低频下,偶极子的取向极化占主导,介电常数较高;而在高频下,偶极子的取向极化滞后,导致介电常数下降,同时介电损耗增加。例如,VHB4910…...

K8S认证|CKS题库+答案| 4. RBAC - RoleBinding
目录 4. RBAC - RoleBinding 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、查看SA和role 3)、编辑 role-1 权限 4)、检查role 5)、创建 role和 rolebinding 6࿰…...

React 新项目
使用git bash 创建一个新项目 建议一开始就创建TS项目 原因在Webpack中改配置麻烦 编译方法:ts compiler 另一种 bable 最好都配置 $ create-react-app cloundmusic --template typescript 早期react项目 yarn 居多 目前npm包管理居多 目前pnpm不通用 icon 在public文件夹中…...
解决MySQL8.4报错ERROR 1524 (HY000): Plugin ‘mysql_native_password‘ is not loaded
最近使用了MySQL8.4 , 服务启动成功,但是就是无法登陆,并且报错: ERROR 1524 (HY000): Plugin mysql_native_password is not loaded 使用如下的命令也报错 mysql -u root -p -P 3306 问题分析: 在MySQL 8.0版本中,默认的认证插件从mysql_native_password变更为cachi…...

AI编程在BOSS项目的实践经验分享
前言 在人工智能技术革新浪潮的推动下,智能编程助手正以前所未有的速度重塑开发领域。这些基于AI的代码辅助工具通过智能提示生成、实时错误检测和自动化重构等功能,显著提升了软件工程的全流程效率。无论是初入行业的开发者还是资深程序员,…...
力扣-131.分割回文串
题目描述 给你一个字符串 s,请你将 s 分割成一些 子串,使每个子串都是 回文串 。返回 s 所有可能的分割方案。 class Solution {List<List<String>> res new ArrayList<>();List<String> path new ArrayList<>();void…...

数学:”度量空间”了解一下?
度量空间是现代数学中一种基本且重要的抽象空间。以下是对它的详细介绍: 定义 相关概念 常见的度量空间举例 度量空间的类型 度量空间的作用 度量空间是拓扑空间的一种特殊情况,它为拓扑空间的研究提供了具体的模型和实例。同时,度量空间在…...

jenkins脚本查看及备份
位置与备份 要完整备份 Jenkins 的所有脚本和相关配置,包括 Jenkinsfile、构建脚本(如 .sh / .bat)、Job 配置、插件、凭据等,你可以从两个层面入手: ✅ 一、完整备份 Jenkins 主目录(最全面) …...

用电脑通过网口控制keysight示波器
KEYSIGHT示波器HD304MSO性能 亮点: 体验 200 MHz 至 1 GHz 的带宽和 4 个模拟通道。与 12 位 ADC 相比,使用 14 位模数转换器 (ADC) 将垂直分辨率提高四倍。使用 10.1 英寸电容式触摸屏轻松查看和分析您的信号。捕获 50 μVRMS 本底噪声的较小信号。使用独有区域触摸在几秒…...
嵌入式面试提纲
一、TCP/IP 协议 1.1 TCP/IP 五层模型概述 链路层(Link Layer) 包括网卡驱动、以太网、Wi‑Fi、PPP 等。负责把数据帧(Frame)在相邻节点间传输。 网络层(Internet Layer) 最典型的是 IP 协议 (IPv4/IPv6)。负责 路由选路、分片与重组。 其他:ICMP(Ping、目的不可达等)…...
算法工程师认知水平要求总结
要成为一名合格的算法工程师或算法科学家,需要达到的认知水平不仅包括扎实的技术功底,更涵盖系统性思维、问题抽象能力和工程实践智慧。以下是关键维度的认知能力要求: 一、理论基础认知深度 数学根基 概率统计:深刻理解贝叶斯推断…...

《如何使用MinGW-w64编译OpenCV和opencv_contrib》
《如何使用MinGW-w64编译OpenCV和opencv_contrib》 在Windows环境下使用MinGW编译OpenCV和opencv_contrib是一个常见需求,尤其是对于那些希望使用GCC工具链而非Visual Studio的开发者。下面我将详细介绍这个过程。 准备工作 首先需要安装和准备以下工具和库: MinGW(建议使…...
数据库、数据仓库、数据中台、数据湖相关概念
文章目录 序言1数据库,数据仓库,数据中台,数据湖-概念对比释义1.1概念产生的时间顺序1.2在使用功能方面对比1.3在使用工具方面对比 2数据仓库2.1数据仓库的发展阶段2.2 数据仓库的设计2.3数据仓库常用工具,方法2.3.1分析型数据库和…...

模拟搭建私网访问外网、外网访问服务器服务的实践操作
目录 实验环境 实践要求 一、准备工作 1、准备四台虚拟机,分别标号 2、 防火墙额外添加两块网卡,自定义网络连接模式 3、 关闭虚拟机的图形管理工具 4、关闭防火墙 5、分别配置四台虚拟机的IP地址,此处举一个例子(使用的临…...
【RAG召回】BM25算法示例
rank-bm25 功能示例 本篇将通过多个示例,快速展示 rank-bm25 库的核心功能。不使用jieba。 准备工作 首先,确保您已经安装了 rank-bm25。 pip install rank-bm25接下来,我们定义一个通用的中文语料库和分词函数。这里我们使用简单的单字切…...

vue中Echarts的使用
文章目录 Echarts概述什么是EchartsEcharts的好处 Vue中Echarts的使用Echarts的安装Echarts的引入 Echarts概述 什么是Echarts Apache ECharts:一个基于 JavaScript 的开源可视化图表库。 其官网如下:https://echarts.apache.org/zh/index.html Echar…...

【C++项目】负载均衡在线OJ系统-1
文章目录 前言项目结果演示技术栈:结构与总体思路compiler编译功能-common/util.hpp 拼接编译临时文件-common/log.hpp 开放式日志-common/util.hpp 获取时间戳方法-秒级-common/util.hpp 文件是否存在-compile_server/compiler.hpp 编译功能编写(重要&a…...