这是一款非常完整的一个ios项目,基本实现了我们常用的一些功能了,而且界面设计个人感觉还是挺不错的,是一个不错的学习ios项目,喜欢的朋友可以参考一下吧。

项目展示,由于没有数据,所以所有的cell显示的都是我自己写的数据。

源码下载:

http://code.662p.com/view/11240.html

抽屉

首页部分效果

首页效果

部分效果

发现

消息

搜索

设置

模糊效果

代码注释展示

代码注释展示

还有很多细节就不一一展示了,大家将代码运行下自己查看即可。由于内容比较多,我就按功能模块来介绍给大家了。

首先是左边抽屉的效果以及点击按钮切换控制器

  • 实际这里相当于自己定义一个和系统UITabBarController差不多功能的控件,在最底层有一个控制器(后面称之为主控制器),将左边的按钮view添加到主控制器的view上,创建好右边有所的控制器(首页,发现,消息,设置...)并且将每个右边控制器包装一个导航控制器,将导航控制器按序添加给主控制器做子控制器,默认情况下将首页的导航控制器的view添加给主控制器的view子控件,根据左边按钮的点击事件通过代理方法.移除旧控制器view从父视图,将新的view添加到主视图的view具体代码如下,用一个临时属性之前选中的控制器

//暂时先做没有登陆的情况的点击
WNXNavigationController *newNC = self.childViewControllers[toIndex];
if (toIndex == WNXleftButtonTypeIcon) {
newNC = self.childViewControllers[fromIndex];
}
//移除旧的控制器view
WNXNavigationController *oldNC = self.childViewControllers[fromIndex];
[oldNC.view removeFromSuperview];
//添加新的控制器view
[self.view addSubview:newNC.view];
newNC.view.transform = oldNC.view.transform;
self.showViewController = newNC.childViewControllers[0];

这样就完成了切换控制器

  • 抽屉的效果是通过给控制器view做形变动画完成的,由于每个导航控制器的功能一样,这里抽取了共同的特点封装了一个基类导航控制器,点击左边的按钮完成抽屉效果
  • 拖动手势是给主控制器添加一个UIPanGestureRecognizer手势,根据拖动的距离计算出该停留在哪里的位置,这里判断很多,具体实现我在代码中每一步都有注释,参照代码即可

首页

  • 首页就是一个tableView就可以搞定,tableView的headView颜色和数据服务器会给返回,给每个headView添加一个点击手势,点击push到下一个控制器,导航条的颜色会和前一个headView的颜色一样,,这里由于我之前设置了导航控制器的主题
[UINavigationBar appearanceWhenContainedIn:self, nil]
  • 以不可以直接设置导航条的颜色了 这里我尝试了设置navigationBar的背景色,设置navigationBar的setTintColor:

设置navigationBar.layer的背景色 以及根据颜色画出navigationBar的背景图片4种办法都无法达到原生的效果

最后采用将navigationBar隐藏,自己放一个View了冒充导航条来解决这个问题

发现

  • 这个页面是一个UICollectionView,里面有两组数据,每一组都一个一个headView,需要注意的就是cell的点击事件,这里注意了下官方的做法是不论点击了cell的哪个位置,都会使cell内部的button进入高亮状态,这里需要用到事件的响应链,在cell的内部拦截整个cell的点击事件都交给按钮来做,具体代码如下

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
/* 拦截事件响应者,不论触发了cell中的哪个控件都交给iconButton来响应 */
// 1.判断当前控件能否接收事件
if (self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= 0.01) return nil;
// 2. 判断点在不在当前控件
if ([self pointInside:point withEvent:event] == NO) return nil;
return self.iconButton;
}

但 这里需要注意这样拦截cell的点击事件,在collectionView的cell被点击触发didDeselectItemAtIndexPath: 就不会被触发了,我的解决方法是在点击button时通过代理方法传给collectionView,外部在通过知道点击了那个cell,push到下一 个控制器,并将cell的model赋值给下一个控制器

登陆(登陆只用了微信和新浪登陆,不涉及到注册就非常简单,这些只需去官网下来登陆和分享的sdk集成进来即可,我一般使用友盟平台,包括崩溃统计,三方登陆,分享,用户分析等等)

消息

  • 一样这里也是tabelView,这里我个人的逻辑是将所有的消息归档到本地,每次点击删除一条,将本地的数据删除一条,重新归档

当点击删除全部的时候,就清空本地的归档数据,下次接受的服务器的数据在重新写入

因为是模拟的数据,为了保障每次进来都有数据,就没有实现归档解档的操作,所以每次删除后重新进入会再次有数据

  • 这里记录编辑按钮的状态,读取本地是否有未读消息数组的个数,如果有就显示编辑按钮,记录编辑按钮的状态,如果是选中状态就隐藏>图片,显示删除按钮,点击删除按钮就将本地的数据数组删除掉并且刷新tableView,这里用的是删除动画,需要注意删除的顺序

[self.datas removeObjectAtIndex:indexPath.row];
[self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationRight];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});

  • 底部的删除全部按钮完全交给编辑按钮来控制.


搜索

搜索

  • 这个也需要持久化存储功能,每次页面弹出后,先从本地读取用户历史搜索的数据,用户每次删除或者新输入收缩内容时也直接写入到本地的caches文件中
  • 这里需要提一下关于热门按钮的布局,因为热门的文字长度不一样,但每次只有4个按钮,在xib中先将按钮的位置约束好,不过宽度的约束需要俩个,一个是>= 和<= 然后根据服务器返回的实际长度在设置按钮title时,计算出每个按钮的真实宽度,根据真实宽度算出间距是多少,重新布局一次按钮的位置

(void)setHotDatas:(NSMutableArray *)hotDatas
{
_hotDatas = hotDatas;
//判断是长度是否是4,开发中可以这样写 应该服务器返回几条数据就赋值多少,而不是固定的写死数据,
//万一服务器返回的数据有错误,会造成用户直接闪退的,有
//时在某些不是很重要的东西无法确定返回的是否正确,建议用
//@try @catch来处理,
//即便返回的数据有误,也可以让用户继续别的操作,
//而不会在无关紧要的小细节上造成闪退
if (hotDatas.count == 4) {
[self.hotButton1 setTitle:hotDatas[1] forState:UIControlStateNormal];
[self.hotButton2 setTitle:hotDatas[0] forState:UIControlStateNormal];
[self.hotButton3 setTitle:hotDatas[2] forState:UIControlStateNormal];
[self.hotButton4 setTitle:hotDatas[3] forState:UIControlStateNormal];
}
[self layoutIfNeeded];
//算出间距
CGFloat margin = (WNXAppWidth - 40 -
self.hotButton1.bounds.size.width -
self.hotButton2.bounds.size.width -
self.hotButton3.bounds.size.width -
self.hotButton3.bounds.size.width) / 3;
//更新约束
[self.hotButton2 updateConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.hotButton1.right).offset(margin);
}];
[self.hotButton3 updateConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.hotButton2.right).offset(margin);
}];
[self.hotButton4 updateConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.hotButton3.right).offset(margin);
}];
}

模糊效果

模糊效果

  • 这里由于图片的质量被压缩的太厉害,实际的效果还不错,这个功能是iOS8新开放的接口,有俩个图片特效可以使用,一个是模糊blur,一个是颜色叠加(类似于PS中图片叠加的效果,不过就3种效果)

详情页

详情页展示

  • 这个页面挺坑的,需要注意的细节太多,也是我耗时最久的页面,诚然目前bug依旧不少
  • 这个页面的层级关系很重要,需要重点注意
  • 首先是导航条,这个咋一看好像是导航条有个渐隐渐现的动画,我的做法是在顶部放了一个高度为64的view,根据tableView的偏移量计算出view的透明度,但是透明度只是1或者0,顶部的scrollView里面装的imageView,根据服务器返回的图片地址个数,设置他的展示内容大小,并且在整一个scrollView最上面添加一个和导航条一样颜色的view,用它来做出向上推出现绿色的效果,并且根据底部scrollview的偏移计算拉伸的大小,我这里拉伸的大小不是很准确,感觉需要将锚点钉在最顶端。
  • 然后是中间切换tableView的view(后面就叫它选择view),要实现能像headView一样,卡在导航条下面的效果,这里因为没有导航条,并且在切换tableView时候不会带走选择view,所以只能将他放到和顶部的view在同一个层级中,同样根据底部scrollView的contentOffset.y计算他的位置,当偏移量超过顶部的64时,就停留在那,不超过时就回到顶部view的下面,这里的计算我加了很多的注释,怕计算的朋友也会看的懂的,大概是这样
  • 下面是一个scrollView上添加了3个tabelView,根据服务器返回的数据判断显示多少个,这里就指显示了俩个,并且第二个页面还没有来得及做

-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if (scrollView == self.rmdTableView || scrollView == self.infoTableView) {//说明是tableView在滚动
//记录当前展示的是那个tableView
self.showingTableView = (UITableView *)scrollView;
//记录出上一次滑动的距离,因为是在tableView的contentInset中偏移的ScrollHeadViewHeight,所以都得加回来
CGFloat offsetY = scrollView.contentOffset.y;
CGFloat seleOffsetY = offsetY - self.scrollY;
self.scrollY = offsetY;
//修改顶部的scrollHeadView位置 并且通知scrollHeadView内的控件也修改位置
CGRect headRect = self.topView.frame;
headRect.origin.y -= seleOffsetY;
self.topView.frame = headRect;
//根据偏移量算出alpha的值,渐隐,当偏移量大于-180开始计算消失的值
CGFloat startF = -180;
//初始的偏移量Y值为 顶部俩个控件的高度
CGFloat initY = SelectViewHeight + ScrollHeadViewHeight;
//缺少的那一段渐变Y值
CGFloat lackY = initY + startF;
//自定义导航条高度
CGFloat naviH = 64;
//渐隐alpha值
CGFloat alphaScaleHide = 1 - (offsetY + initY- lackY) / (initY- naviH - SelectViewHeight - lackY);
//渐现alph值
CGFloat alphaScaleShow = (offsetY + initY - lackY) / (initY - naviH - SelectViewHeight - lackY) ;
if (alphaScaleShow >= 0.98) {
//显示导航条
[UIView animateWithDuration:0.04 animations:^{
self.naviView.alpha = 1;
}];
} else {
self.naviView.alpha = 0;
}
self.topScrollView.naviView.alpha = alphaScaleShow;
self.subTitleLabel.alpha = alphaScaleHide;
self.smallImageView.alpha = alphaScaleHide;
/* 这段代码很有深意啊。。最开始是直接用偏移量算的,但是回来的时候速度比较快时偏移量会偏度很大
然后就悲剧了。换了好多方法。。最后才开窍T——T,这一段我会在blog里面详细描述我用的各种错误的方法
用了KVO监听偏移量的值,切换了selectView的父控件,切换tableview的headView。。。
*/
if (offsetY >= -(naviH + SelectViewHeight)) {
self.selectView.frame = CGRectMake(0, naviH, WNXAppWidth, SelectViewHeight);
} else {
self.selectView.frame = CGRectMake(0, CGRectGetMaxY(self.topView.frame), WNXAppWidth, SelectViewHeight);
}
CGFloat scaleTopView = 1 - (offsetY + SelectViewHeight + ScrollHeadViewHeight) / 100;
scaleTopView = scaleTopView > 1 ? scaleTopView : 1;
//算出头部的变形 这里的动画不是很准确,好的动画是一点一点试出来了 这里可能还需要配合锚点来进行动画,关于这种动画我会在以后单开一个项目配合blog来讲解的 这里这就不细调了
CGAffineTransform transform = CGAffineTransformMakeScale(scaleTopView, scaleTopView );
CGFloat ty = (scaleTopView - 1) * ScrollHeadViewHeight;
self.topView.transform = CGAffineTransformTranslate(transform, 0, -ty * 0.2);
//记录selectViewY轴的偏移量,这个是用来计算每次切换tableView,让新出来的tableView总是在头部用的,
//现在脑子有点迷糊 算不出来了。。凌晨2.57分~
CGFloat selectViewOffsetY = self.selectView.frame.origin.y - ScrollHeadViewHeight;
if (selectViewOffsetY != -ScrollHeadViewHeight && selectViewOffsetY = (0.5 + index)) {
[self.selectView lineToIndex:index + 1];
} else if (seleOffsetX < 0 && offsetX / WNXAppWidth <= (0.5 + index)) {
[self.selectView lineToIndex:index];
}
}
}

这些就是这个项目的大体思路,当然还有很多很多的细节都在代码中,第一次尝试将思路写出来,感觉有很多不足,本应该每写完一个功能就总结一下,而我是在发布的晚上回头总结的,有很多当时的思路不是很清晰了...

请直接打开WNXHuntForCity.xcworkspace

打开

而不要打开WNXHuntForCity.xcodeproj

详细说明:http://ios.662p.com/thread-2519-1-1.html

转载于:https://www.cnblogs.com/yayabei/p/4831309.html

iOS高仿城觅应用客户端项目(开发思路和代码)相关推荐

  1. iOS高仿微信项目、阴影圆角渐变色效果、卡片动画、波浪动画、路由框架等源码...

    2019独角兽企业重金招聘Python工程师标准>>> iOS精选源码 iOS高仿微信完整项目源码 Khala: Swift 编写的iOS/macOS 路由框架 微信左滑删除效果的实 ...

  2. iOS高仿微信项目、阴影圆角渐变色效果、卡片动画、波浪动画、路由框架等源码

    iOS精选源码 iOS高仿微信完整项目源码 Khala: Swift 编写的iOS/macOS 路由框架 微信左滑删除效果的实现与TableViewCell的常用样式介绍 实现阴影圆角并存,渐变色背景 ...

  3. iOS高仿微信完整源码,网易爱玩APP源码等

    iOS精选源码 iOS一种弹出视图效果带动画 一个快速便捷.无侵入.可扩展的动画弹框库 高仿Elk - 旅行货币转换器 iOS内分享的界面.功能一体化解决方案 使用Olami sdk实现一个语音查询股 ...

  4. 高仿“饿了么”Vue项目(一)

    高仿"饿了么"Vue项目(一) 当我们把Vue框架的概念过了一遍之后,要进一步提升,就要看看别人是怎么使用Vue框架来做项目了. 在github上有不少好的Vue项目,我找到了其中 ...

  5. iOS 高仿爱鲜蜂APP

    //联系人:石虎  QQ: 1224614774昵称:嗡嘛呢叭咪哄 iOS高仿爱鲜蜂 前言 2016年匆匆的就过去了,又老了一岁,这一年起起伏伏,有笑声也有眼泪,感谢陪伴在我身边的人. 关于项目(代码 ...

  6. iOS高仿微信、仪表盘、图片标注图片滤镜、高斯模糊、上拉加载、下拉刷新等源码

    iOS精选源码 Swift-图片画框标注 Swift版的上拉加载, 下拉刷新控件(一句话集成, 超级易用) iOS tabbar上的提示框 Swift图片浏览器,经过一年多维护,已基本稳定 图片滤镜 ...

  7. iOS高仿微信、仪表盘、图片标注图片滤镜、高斯模糊、上拉加载、下拉刷新等源码...

    iOS精选源码 Swift-图片画框标注 Swift版的上拉加载, 下拉刷新控件(一句话集成, 超级易用) iOS tabbar上的提示框 Swift图片浏览器,经过一年多维护,已基本稳定 图片滤镜 ...

  8. 高仿喜马拉雅听Android客户端,Zhumulangma

    ### 注意:请将lib_common下manifest中喜马拉雅key替换为自己的,不然会提示访问超过限制. https://github.com/TanZhiL/Zhumulangma 本项目仅 ...

  9. android 仿网易标签切换,高仿网易云音乐客户端的Home页面切换Tabhost-IT蓝豹

    1.高仿网易云音乐客户端的Home页面切换Tabhost 高仿网易云音乐客户端的Home页面切换Tabhost,并且三角形是透明的, 实现方式,自定义AnimTabsView继承 RelativeLa ...

最新文章

  1. C++知识点杂记3——局部类、位域、volatile、链接指示、枚举、定位new
  2. Thread.sleep() SystemClock.sleep()
  3. python观察日志(part21)--ord,chr,unichr方法的联系与区别
  4. javafx ui_调用以验证JavaFX UI的响应能力
  5. HTML5简易在线画图工具
  6. full gc 次数_32. GC 是怎样工作的?
  7. 语音社交app源码中音频混音的实现步骤
  8. Windows XP 启动NetMeeting
  9. 【Vue实战】基于Vue的九宫格在线抽奖附源代码
  10. 可以测试英语发音的软件,检测英语发音的软件
  11. java中POJO、PO、BO、VO、DTO和DAO的概念
  12. html的视频字幕制作步骤,视频字幕制作软件如何制作视频滚动字幕|滚动字幕视频制作...
  13. Ubuntu下鼠标无法点击解决方案
  14. robots文件的作用
  15. 通过wifi共享使Linux设备连接网络
  16. 小米的性价比之路为何走不通了?
  17. 调查计算机对运算能力的影响,计算器对运算能力的影响的报告.docx
  18. jquery中的循环技巧
  19. easyUpload.js插件文件上传
  20. 电视卡播放软件测试初学者,教你用最简单的方法解决本地电脑共享3D高清视频卡的问题...

热门文章

  1. c++类对象 指针区别
  2. [再寄小读者之数学篇](2014-06-03 华罗庚等式)
  3. jquery 视觉特效(幻灯片效果)
  4. 不要忽视任何小问题!!!一个XML的XPath的问题.....
  5. 二、在应用中升级----网络部分
  6. oracle avg分析函数,分析函数之sum,avg
  7. java分布式 mq_分布式系统消息中间件—RabbitMQ的使用进阶篇
  8. 计算机科学速成视频35,计算机科学速成课30:万维网【视频】
  9. 以阿里云RPA为例,来告诉你到底RPA是什么?
  10. Java经典面试题整理及答案详解(五)