新闻类App顶部菜单栏封装
概述
最近有一个需求,类似今日头条顶部的菜单栏。唯一区别是需要带可移动的下划线。网上查找资料,发现解决方案大部分是用UIScrollView实现。下方VC控制用UICollectionView。这样可以解决问题,但是不完美,当标签很多的时候,这时候的UIScrollView上会有大量写死的Button,没有达到复用的目的。所以自己封装了一个空间。菜单栏使用UICollectionView,VC控制使用PageViewController。
这样做的目的是为了完全复用,支持无限扩展。因为菜单栏是collectionView,所以不怕内存爆掉。VC的控制使用PageViewController,好处是滑动的时候可以懒加载,只有用户浏览的时候才会实例化并缓存起来。网上的其他方案都是一次性把所有VC都实例化,然后使用CollectionView管理,这是不好的,因为有些VC用户可能从来不浏览,没必要实例化。
接下来就详细介绍一下。
实现难点
菜单栏需要把所选的一栏居中显示
使用ScrollView,需要手动计算,设置offset,让其被选栏居中,比较麻烦。如果使用CollectionView,CollectionView有一个方法:
open func scrollToItem(at indexPath: IndexPath, at scrollPosition: UICollectionView.ScrollPosition, animated: Bool)
只要将scrollPosition设置为.centeredHorizontally,即可实现该功能
左右滑动的时候,可以切换所选菜单,且下方横线需要跟着动
使用ScrollView的话就比较方便了,计算滑动距离和屏幕宽的比例,让下划线跟着滑即可。但是使用CollectionView的话,滑完之后会自动居中显示被选菜单。位置就会出错。解决方案就是让下划线跟着被选菜单cell的位置。
在collectionView中,滑动cell的时候其实只是offset在变,cell的frame其实是不变的,collectionView其实也是个ScrollView,cell是加在scrollView的contentView上的。在这里卡壳了好久。解决方案是,将cell的坐标转化到collectionView上,然后让下划线的中心点和cell在collectionView上中心点保持一致
if let currentCell = collectionView.cellForItem(at: IndexPath(row: currentIndex, section: 0)) {
lineView.center.x = currentCell.convert(CGPoint(x: currentCell.bounds.width / 2.0, y: 0), to: scrollView).x
}PageViewController没有ScrollView的Delegate,滑动的时候,不知道滑动的情况。
可以使用一个暗黑技巧:
for subview in pageViewController.view.subviews {
if let scrollView = subview as? UIScrollView {
scrollView.delegate = self
}
}然后再scrollViewDidScroll方法中操作
public func scrollViewDidScroll(_ scrollView: UIScrollView) {
if isForbideScroll { return} var progress:CGFloat = 0
var nextIndex = 0
let screenWidth = UIScreen.main.bounds.width
let count = items.count //判断是左移还是右移
if UIScreen.main.bounds.width > scrollView.contentOffset.x{ //右移动
nextIndex = currentIndex - 1
if nextIndex < 0 {
nextIndex = 0
}
//计算progress
progress = (screenWidth - scrollView.contentOffset.x)/screenWidth
}
if UIScreen.main.bounds.width < scrollView.contentOffset.x{ //左移
nextIndex = currentIndex + 1
if nextIndex > count - 1 {
nextIndex = count - 1
}
progress = (scrollView.contentOffset.x - screenWidth)/screenWidth
}
if progress != 0.0 {
topBar.pageViewScroll(nextIndex: nextIndex, progress: progress)
}
}
如何使用
- 风格控制类SegmentTopBarStyle
- 数据源[SegmentItem]
- 自定义VC必须实现ChildViewControllerProtocol协议,协议中初始化方法可以按需修改,增加参数。初始化方法修改后记得在ScrollPageView中修改自定义VC的初始化。
- ScrollPageView中使用了SegmentTopBarView,所以你也可以单独使用SegmentTopBarView
override func viewDidLoad() {
super.viewDidLoad() //风格控制
let style = SegmentTopBarStyle()
style.bottomLineColor = UIColor.red
style.showExtraButton = false //datasource
let items = dataSource() //ScrollPageView
let subiView = ScrollPageView(frame: view.bounds,
items: items,
style: style,
parentVC: self,
customClassType: ChildViewController.self)
view.addSubview(subiView)
} func dataSource() -> [SegmentItem] {
// 讲数据转化为SegmentItem的数组
var arr = [SegmentItem]()
for i in 0...10 {
let item = SegmentItem(title: "title\(i)", cid: "\(i)")
arr.append(item)
}
return arr
}
源码
demo基于swift4.0。代码不多,稍微阅读下就能看懂。你也许会有更多的个性化的定制,可以在这个结构上随意改,拿走不谢
demo: https://github.com/wangdachui/Segment
新闻类App顶部菜单栏封装的更多相关文章
- 新闻类App使用的组件
UI SlidingMenu:com.jeremyfeinstein.slidingmenu:滑动菜单 ActionBarSherlock:com.actionbarsherlock:Action B ...
- iOS开发之资讯类App常用分类控件的封装与实现(CollectionView+Swift3.0+)
今天博客中,我们就来实现一下一些常用资讯类App中常用的分类选择的控件的封装.本篇博客中没有使用到什么新的技术点,如果非得说用到了什么新的技术点的话,那么勉强的说,用到了一些iOS9以后UIColle ...
- 分享一下怎么开发一款图片视频类App,秒拍和prisma
第一步,分解短视频App的功能 我们在秒拍官网看到如此描述: [视频拍摄及导入]支持直接拍摄及导入手机本地的视频 [照片电影]照片专属特效,轻松创作照片电影 [MV特效]10余款全新MV特效,让普通视 ...
- iOS开发之常用资讯类App的分类展示与编辑的完整案例实现(Swift版)
上篇博客我们聊了<资讯类App常用分类控件的封装与实现(CollectionView+Swift3.0)>,今天的这篇博客就在上篇博客的基础上做些东西.做一个完整的资讯类App中的分类展示 ...
- GNE: 4行代码实现新闻类网站通用爬虫
GNE(GeneralNewsExtractor)是一个通用新闻网站正文抽取模块,输入一篇新闻网页的 HTML, 输出正文内容.标题.作者.发布时间.正文中的图片地址和正文所在的标签源代码.GNE在提 ...
- 三分之一的程序猿之社交类app踩过的那些坑
三分之一的程序猿之社交类app踩过的那些坑 万众创新,全民创业.哪怕去年陌生人社交不管融资与否都倒闭了不知道多少家,但是依然有很多陌生人社交应用层出不穷的冒出来.各种脑洞大开,让人拍案叫起. 下面我们 ...
- 为什么那么多人想开发一元夺宝类app?
别拿你的无知和愚蠢,来证明主观的判断! 国人对一切事物具有怀疑的本性是好的, 但是若不建立于科学的分析方法, 那就是愚昧! 身边有朋友玩夺宝投入较多,产出较少,于是向我求助.想从数据分析的角度知道到底 ...
- 2016年上半年金融类App成绩单,手机银行优势尽显! (转自Analysys易观(ID:enfodesk))
2016已悄然时过大半,金融各领域经过了开年大战,二季度末尾的6月更是几家欢喜几家愁,其中频繁出现的黑马更是足够让人惊喜.我们基于易观千帆6月移动应用大数据,筛选了百款金融类App为您揭晓TOP100 ...
- 移动互联网实战--资源类APP的数据存储处理和优化
前言: 对于资源类的APP, 其音频/图形占据了APP本身很大的比例. 如何存储和管理这些资源文件, 成了一个颇具挑战性的难点. 移动端的碎片化, 高中低端手机的并存, 需要开发者不光是具备基础的存储 ...
随机推荐
- RHEL7下用本地光盘或镜像iso文件做yum源
应用场境:Redhat 系统想要直接在线通过yum的条件时需要注册,一般用户都是非注册的,这个时候如果要想通过yum安装新软件,我们可以通过将安装盘或者镜像iso文件设置为yum源的方式来进行. 测试 ...
- 对于Spring中注入对象失败的问题
1.今天进行了一段代码,经过检查发现config配置文件没问题,注入注解也编写正确,但是RedisTemplate就是会抛出空指针异常. 进过一系列检查发现,其在用户使用该类的时候采用的是new方式创 ...
- [luoguU48834][count]
题目链接 思路 这个题可以考虑用全部情况减去不合法的情况,来求解.首先需要知道n个点所组成的图总共有\(C(_n^2)\)种,然后用f[n]表示n个点的图联通的方案数. 然后钦定1在联通图里面,考虑不 ...
- JDK和CGLIB动态代理区别
背景:虽然自己了解这两种代理的区别,但是面试时候还是答的很模糊,需要好好总结. 前言JDK动态代理实现原理(jdk8):https://blog.csdn.net/yhl_jxy/article/de ...
- Java 多线程篇
先举个例子 计算机的核心是CPU,它承担了计算机所有计算任务,可以把它理解为像一个工厂,时刻在运行. 假定工厂有一个电力系统,工厂有很多车间,一次只能供给一个车间使用,也就是说一个车间开工的时候,其他 ...
- JS事件(一)事件流&事件处理程序
1.事件流描述的是从页面接收事件的顺序 IE和Netscape提出了几乎完全相反的事件流概念 IE:事件冒泡(由内而外) Netscape:事件捕获(由外向内) DOM2级事件规定事件流包括三个阶段: ...
- django系列 1 :python+django环境搭建 +mac提示找不到manage.py命令
1.安装python3 2.设置python3的环境变量 3.进入命令行模式,输入 pip install django 1.10.3 4.验证是否安装完成 pip show django 5.dja ...
- 微信小程序:import导入公共文件方式
wxss: @import "../common/ali_icon.wxss"; wxml: 公共文件(位置:../common/head.wxml)如下---- <temp ...
- tomcat插件使用
1.pom.xml添加插件 <build> <plugins> <!-- tomcat7插件 --> <!-- 注意:目前来说,maven中央仓库还没有tom ...
- oracle中查看所有表和字段以及表注释字段注释
获取表:select table_name from user_tables; //当前用户拥有的表 select table_name from all_tables; //所有用户的表 selec ...