源码

首页 » 归档 » 源码 » Swift开源项目-模仿今日头条-ios学习从入门到精通尽在姬长信

Swift开源项目-模仿今日头条-ios学习从入门到精通尽在姬长信

分享最热门的ios资讯

说明

首先声明,今日头条是我经常用的 app 之一,模仿今日头条也是因为感兴趣,代码仅用于学习交流。

项目中有的地方代码写的不是很简洁,究竟自己能力有限,对 Swift 使用不是很熟练,还请各位朋友不喜勿喷。下面有项目的完整源码,喜欢的朋友可以下载下来,如果您感觉我写的代码对您有所资助,还请在 github 给个 star,非常感谢您的支持!~

Github 地址

CodaData 地址

环境设置

  • 项目环境

    • Xcode 7.3.1(低于这个版本会报错)

    • Swift 2.2

    • iOS 8.0 +

  • 使用cocoaPods管理第三方库,如果电脑没有安装 cocoapods,请先安装 cocoapods。安装方式可参考:最面目目样版 CocoaPods 的安装流程

  • 项目中使用到的第三方库

    • SnapKit: 结构

    • Kingfisher: 缓存图片

    • SVProgressHUD:提示框

    • FDFullscreenPopGesture:侧滑

    • Alamofire :网络请求

    • SwiftyJSON:解析 json

    • MJRefresh: 上拉刷面目目样和下拉刷面目目样

实现的功能

1. 获取今日头条的接口

2. 完成首页的结构和数据的显示

3. 实现首页顶部导航栏转动

4. 面目目样闻详情界面简单实现

5. 点击屏蔽按钮,弹出屏蔽视图(坐标有一些问题)

6. 完成视频界面顶部导航栏转动

7. 完成视频界面结构和数据获取

8. 用户界面简单实现

9. 完成关注界面结构和数据的获取

10. 完成关注界面,添加关注功能

11. 完成搜索功能

12. 完成个人界面的结构

13. 完成设置界面的结构

14. 完成离线下载界面结构

15. 活动界面简单实现

16. 登录界面的简单实现

17. 启动界面的简单实现

数据请求

今日头条的接口文件请看:news.json

需要提前安装 postman,然后把该文件导入到 postman 进行检察,可以打开谷歌浏览器,找到扩展法式,添加面目目样的扩展,搜索 postman或者直接去这个链接下载:postman下载地址。下载完成后,直接拖入到谷歌浏览器的扩展法式界面即可。

首页

YMHomeViewController.md

1.首先,首页的状态栏的颜色是白色,所以调用了下面的要领:

override func preferredStatusBarStyle()->UIStatusBarStyle 
{    
  return.LightContent
}

但是,经过测试,上面的代码不起作用,对于 YMMineViewController.swift 上面的代码是起作用的。

唯一的区别是就是在 YMMineViewController.swift 中隐藏了导航条。所以经过查阅资料,得到下面的结论:

1.不管是调用了系统的 UINavigationController 还是使用自己继承自 UINavigationController,如果 navigationBar 没有被隐藏的话,那么导航控制器的 rootController 以及它 push 的控制器的 preferredStatusBarStyle() 要领都不会被调用。

2.如果在当前控制器手动设置了 navagationBar 的 barStyle 为 .Black 或者 .Default 或者使用下面的代码手动设置:

// 方式1
navigationController?.setNavigationBarHidden(true,animated:false)
// 方式2
navigationController?.navigationBarHidden = true

那么 preferredStatusBarStyle() 就会被正常调用了。

还有一点关于隐藏导航栏的注意点请看 YMMineViewController.swift

2.关于导航栏的 titleView

在首页首页顶部标题的时候,直接设置 titleView 的宽度为屏幕的宽,但是两边总是会留出 10 的间距,这个时候需要重写父类的 setFrame 要领,在 OC 里面可以使用下面的要领:

- (void)setFrame:(CGRect)frame{      
    CGRect newFrame = CGRectMake(0,0,SCREENW,44);    
    [super setFrame:frame];  
}

但是在 swift 中不能这样写,要使用下面的方式:

/// 重写 
frameoverride var frame: CGRect 
{    
    didSet {        
        let newFrame = CGRectMake(0, 0, SCREENW, 44)        
        super.frame = newFrame    
    }
}

这样设置,运行法式,发现 titleView 在屏幕两边不在留有间距。

3.子控制器

YMHomeTopicController.swift 作为 YMHomeViewController.swift 的子控制器,显示面目目样闻数据。

YMHomeTopicController.md

该类注册了四种 cell,分别表示中间三张图片,右边一张图片,中间一张大图,中间一张视频大图,没有图片的情况。

以下是四种情况:

tableView(tableView:UITableView,cellForRowAtIndexPath indexPath:NSIndexPath)->UITableViewCell

中,凭据差别情况对要显示的 cell 进行判断,显示对应的 cell。

具体判断情况请看 Model 里的 YMNewsTopic.swift 类。

YMHomeDetailController.swift

详情有下面四种方式,为了实现简单,这里使用 `webView` 来实现。

YMPopPresentationController.md

iOS 8 以后推出的专门负责转场动画的控制器。

在 Xcode 7 以上的版本中,`UIPresentationController` 有一个 bug,见下图:

presentingViewController 会报一个野指针的错误,这是 Xcode 的 bug。

UIPresentationController 中有两个要领可以结构子视图,分别是:

// 即将结构转场子视图时调用 
public func containerViewWillLayoutSubviews()
// 结构完成转场子视图时调用
public func containerViewDidLayoutSubviews()

可以在两个要领里设置  UIPresentationController 的容器视图 containerView 和 被展现的视图 presentedView()。

YMHomeTopicCell.md

这个类主要作为四种类型 cell 的父类,主要界说了 标题、头像、昵称、评论、关闭按钮。

显示图片交给其子类各自实现。

当时考虑过使用一个类来实现四种类型的 cell,但是经过测试,由于 cell 的重用机制,始终不能到达想要的结果,所以才分别创建了四种差别的 cell,使用一个类的方式是 YMTopicTableViewCell.swift 这个类,大家可以参考一下。

由于首页的情况对照多,cell 的显示对照复杂,而且今日头条的接口也不是很规范,所以这几个类实现起来对照麻烦,而且代码写的不是很简洁,用了很多 if 判断,可能看起来不是很美观。

判断的情况与 YMNewsTopic.swift 类相同,具体请看 YMNewsTopic.swift。

我觉得使用差别 cell 的情况还对照简单理解。

如果各位朋友有什么更好的实现要领,欢迎给我留言或『Pull Request』,非常感谢您的留言和建议。

YMScrollTitleView.md

这个类和和视频顶部标题的类有些类似,对于数据和按钮点击的回调使用闭包的方式。而在视频的标题 YMVideoTitleView.swift 里使用署理来取代闭包,实现的功能是相同的,但是实现的方式差别,可以对比看一下。

对控件的结构方式还是使用的 SnapKit 来进行结构。

这个类里需要首先从服务器获取标题数据,服务器返回一个数组,凭据这个数组循环创建标题的 label,然后设置好 label 的位置以及 scrollView 的 contentSize。

标题 label 的点击通过添加手势来实现监听点击操作,titleLabelOnClick 为标题点击的要领,当点击的时候,凭据索引进行相应的偏移,调用 adjustTitleOffSetToCurrentIndex 来改变 label 的位置。

在 adjustTitleOffSetToCurrentIndex(currentIndex: Int, oldIndex: Int) 要领里,需要获取之前点击 label 的索引以及刚刚点击 label 的索引,改变形变,计算当前的偏移量。

重写 frame,来设置导航栏不再有两边的间距。请看具体代码 206 行。

YMNewsTopic.md

这个类是我觉得最麻烦的一个类了,有很多种情况,所以判断也对照多。

今日头条返回的数据中,有这四个字段,image_list ,middle_image,large_image_list,video_detail_info,在 cell 里面分别对应 YMHomeSmallCell.swift,YMHomeMiddleCell.swift,YMHomeLargeCell.swift。

image_list 这是一个 数组,表示中间有三种图的情况;

middle_image 这是一个字典,表示图片在右侧的情况;

large_image_list 这是一个数组,表示中间是一张大图:

video_detail_info 这是一个字典,表示是视频,中间也用一张大图表示,这种情况和大图的情况基底细同,但是视频中间多了播放按钮。

还有最后一种情况就是没有图片的情况,比如置顶的专题,但是置顶的专题和上面在举报按钮的地方也有所区别,置顶的面目目样闻没有举报按钮,其他情况有举报按钮,需要凭据 一个字段 `label` 来进行判断。

上面五种情况出现的依赖关系,也需要进行判断,

下面说一下,具体的判断过程:

image_listmiddle_imagelarge_image_listvideo_detail_info
nilnilnilnil
nil不为 nil不为 nilnil
nil不为 nilnilnil
不为 nil不为 n

il

不为 nil不为 inil
不为 nil不为 nil
不为 nilnil
 不为 nil不为 nilnil不为 nil
不为 nil不为 nilnilnil

还有一些其他情况,比如有个数据里没有 image_list 这个字段,这种情况我没做判断,一般法式崩溃都是因为这个原因。但是实际上,我是先判断 image_list 是否有值,如果有值,则显示三张图片,如果为 nil,再判断 middle_image 的情况。

如果各位朋友有什么更好的实现要领,欢迎给我留言或『Pull Request』,非常感谢您的留言和建议。

YMPopViewAnimator.md

自界说转场动画需要集成两个署理协议,分别是 UIViewControllerTransitioningDelegate 和 UIViewControllerAnimatedTransitioning。

如果需要自界说转场动画,那么所有的操作需要自己完成,系统不再处理。

UIViewControllerTransitioningDelegate

UIViewControllerTransitioningDelegate 共有五个署理要领,这里我用到了三个署理要领,分别是:

// MARK:- UIViewControllerTransitioningDelegate    
/** 告诉系统由哪个控制器来实现署理
- parameter presented:被展现的视图    
- parameter presenting:展现的视图     
- returns: YMPopPresentationController 
iOS 8 以后推出的专门负责转场动画的控制器  */    
func presentationControllerForPresentedViewController(presented:UIViewController,presentingViewController presenting:UIViewController,sourceViewController source UIViewController) -> UIPresentationController?    /**     告诉系统谁来负责 modal 的展现动画     - parameter presented:  被展现的视图     - parameter presenting: 展现的视图     - returns: 由谁管理     */    func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning?    /**     告诉系统谁来负责 modal 的消失动画     - parameter dismissed: 消失的控制器     - returns: 由谁管理     */    func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning?

UIViewControllerAnimatedTransitioning

用到了两个署理要领:

/** 动画时长*/
func transitionDuration(transitionContext: UIViewControllerContextTransitioning?)-> NSTimeInterval     
/** 负责转场动画的效果*/    
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {        
if isPresent {            
// 展开           
let toView = transitionContext.viewForKey(UITransitionContextToViewKey)            
// 一定要将视图添加到容器上            
transitionContext.containerView()?.addSubview(toView!)            
// 锚点            
toView?.layer.anchorPoint = CGPoint(x: 1.0, y: 0.0)            
toView?.transform = CGAffineTransformMakeScale(0.0, 0.0)            
UIView.animateWithDuration(transitionDuration(transitionContext), delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0.5, options:

YMHomeShareView.swift

分享界面:

视频

YMVideoViewController.md

这个控制器主要显示顶部导航标题和帖子控制器的一个容器。

顶部导航标题请看 YMVideoTitleView.swift,帖子控制器请看 YMVideoTopicController.swift。

YMVideoTopicController.md

使用的一个 tableView 实现。集成上拉刷面目目样和下拉刷面目目样。实现起来不难。

但是视频播放麻烦一点。需要考虑 cell 的重用机制,由于今日头条返回的数据是一个网址,并不是视频的真实地址,试了一些要领,想把视频的真实地址搞出来,但是没有成功,也是我能力有限。搜易视频播放暂时写了一个地址,播放是这一个视频。

cell的图片是一个 button 的配景图片,通过 button 的点击事件,来判断此时是选中还是没有选中。当点击图片按钮或是播放按钮的时候,在这个按钮上再创建一个 playerView,来播放视频,具体类请看 `YMPlayerView.swift`。

首先提前界说一个 cell,来保存上一次点击的 cell,然后通过 YMPlayerView.swift 的回调, 首先把上一次 cell 的状态,恢复原状,然后再在当前选中的 cell 上,进行面目目样的设置,并添加一个 YMPlayerView。

说明:视频播放还是存在问题,后面有时间会优化。

关注

YMNewCareViewController.md

这个类是第三个主控制器,显示关注界面。

这个界面创建了一个 tableView,而且注册了三种差别的 cell,分别是 `YMNewCareNoLoginCell.swift`,YMNewCareTopCell.swift,以及 YMNewCareBottomCell.swift,可分别打开各自的文件,进行检察。

首先设置 UI,然后 setupRefresh() 是添加上拉和下拉刷面目目样,然后将 tableView 分成了上下两组,上边一组表示自己添加的关注内容,下边一组表示未添加的关注内容,下面一组可以上拉加载更多内容。

今日头条的接口里有一个 concern_time 字段,未添加关注之前,该值为 0,当添加某一关注内容之后,该值变为一个关注的时间,单元是秒。由于今日头条接口里返回的数据是一个数组,即已关注和未关注的内容同时包罗在一个数组中,所以可以凭据这个参数来区分是已关注还是未关注。具体要领可以参考 setupRefresh 要领里面调用的 loadNewConcernList 要领,以及 loadMoreConcernList 要领,这两个要领实现了对已关注和未关注的拆分。

接口里还有一个参数需要注意,就是 newly 这个字段,对于刚刚关注的内容或是已关注的内容并没有点击相应的 cell,跳转到下一控制器的关注内容,都会在右边显示一个 『NEW』,这个控件的显示与隐藏需要凭据 newly 的值进行判断,newly 会返回两种情况,一种是 1, 另一种是 0,即对应显示和隐藏。

上面的参数界说请看 YMConcern.swift.

在下面一组每一个 cell 上都有一个『关注』 按钮,这里我使用署理来实现按钮点击的响应事件,让 YMNewCareViewController 来接收按钮的点击。

当添加关注的时候,会有一个动画效果,这个动画效果暂时还未实现,大家可以参考今日头条的效果。参考一下,有实现的朋友,也可以联系我,也可以给我 『pull request』。

这个界面的实现还算简单,就说明到这里吧~

YMBlurImageView.md

点击关注界面的某一个 cell 之后,跳转到下移控制器的顶部视图,有一个模糊效果。

界面实现不算太难,主要是对每个控件的结构,使用 `SnapKit`。点击按钮的回调使用委托实现。

代码中注释对照详细,这里不再说明。

我的

YMMineViewController.md

隐藏导航栏的要领如下:

// 方式1
navigationController?.setNavigationBarHidden(true, animated: false)
// 方式2
navigationController?.navigationBarHidden = true

需要注意一点,隐藏导航栏的属性写到 viewDidLoad() 里不起作用。

YMSettingViewController.swift

从文件加载 cell 的数据,使用通知的方式,实现了清除缓存,以及改变字体大小,改变下载方式。

YMOfflineTableViewController.swift

我的 -> 离线 -> 离线下载

对于标题的选中与未选中,使用归档的方式,`YMHomeTopTitle` 附加一个字段来判断选中与未选中,然后存储到沙盒中,具体实现可看代码。

其他界面与代码请看项目。

用意志战胜身体的惰性!

(0)

本文由 姬長信 创作,文章地址:https://blog.isoyu.com/archives/1060.html
采用知识共享署名4.0 国际许可协议进行许可。除注明转载/出处外,均为本站原创或翻译,转载前请务必署名。最后编辑时间为:8 月 19, 2016 at 03:59 下午

关键词:

热评文章

发表回复

[必填]

我是人?

提交后请等待三秒以免造成未提交成功和重复