美文网首页iOS开源&高仿项目精选iOS工作系列iOS
iOS高仿城觅项目(开发思路和代码)

iOS高仿城觅项目(开发思路和代码)

作者: Top_熊 | 来源:发表于2015-07-19 01:49 被阅读39774次

    前言

    很早前就想和大家分享一些真正项目的开发思路和流程,一直没能鼓起勇气写,毕竟这不是一件轻松的事情,一个月前,公司的项目上线,鼓起勇气利用每天的休息时间写了这个半成品的项目,基本的UI与逻辑都打通了,剩下的细节需要时间修改,由于下周工作有新需求需要开发,可能很长一段时间没精力来写了,本想把所有的功能都实现,并且修改掉发现的bug后再给大家学习的,由于工作的情况,可能会延缓2个月左右的日子(后续我会把功能陆续实现),代码我传到github上了,相信读者会发现很多的不足之处,希望大家可以自行尝试修改一些bug和实现剩余的部分功能,说实话一直是每天晚上8点写到凌晨3点左右,因为有些朋友不希望看见过多的三方库,所以基本非常耗时的需求我都尽力自己封装的,当然我写的有很多不足之处,希望大家可以指出不足之处,共同进步,由于时间比较匆忙,我的code一次review都没,望大家包涵,项目使用OC写的,算是对OC的一个纪念吧。等忙完这段时间,我会再用swift来写一个新的项目分享给大家,喜欢的朋友可以继续关注我的博客,我会第一时间将新项目到博客上

    这篇博客是配合代码来写的,大部分的图片都是我自己扣下来的,数据也是我直接写的假数据,在代码中基本每一步我都有详细的注释,唠叨的有点多,下面就先展示下我仿的这个项目吧,有兴趣的朋友可以下一下原版的app参照一下(写的过程中app更新了一点新功能)

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

    抽屉抽屉
    首页部分效果首页部分效果
    首页效果首页效果
    部分效果部分效果
    发现发现 消息消息 搜索搜索 设置设置 模糊效果模糊效果 代码注释展示代码注释展示 代码注释展示代码注释展示

    还有很多细节就不一一展示了,大家将代码运行下自己查看即可

    由于内容比较多,我就按功能模块来介绍给大家了

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

    • 这里值得注意的是根据苹果推荐的使用方法是,当一个控制器的View是另一控制器view的子控件,那么这个控制器也最好也是另一个控制器的子控制器例如:
    UIViewController *testVC = [UIViewController new];
    [self.view addSubview:testVC.view];
    [self addChildViewController:testVC];
    
    • 这里左边的view实际上相当于自己定义一个和系统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做形变动画完成的transformX轴的位移以及整体的缩放效果,这里由于每个导航控制器的功能一样,这里抽取了共同的特点封装了一个基类导航控制器,基类拥有点击左边的按钮完成变形和恢复的功能

    • 拖动手势是给主控制器添加一个UIPanGestureRecognizer手势(称为pan),当pan开始拖拽时,计算拖动的距离来按比例执行动画,根据手势的状态(pan.status ==UIGestureRecognizerStateEnded)停止时拖动的距离计算出该停留在哪里的位置,需要注意的是这里得记录下当前导航控制器是处于哪种状态,给导航控制器自定义个属性isScale来记录,这里判断很多,具体实现我在代码中每一步都有注释,参照代码即可

    首页

    • 首页就是一个tableView就可以搞定,tableView的headView颜色和数据服务器会给返回,给每个headView添加一个点击手势,点击push到下一个控制器,这里需要注意tableViewdelegate中headView的复用headView的复用使用方法和cell差不多,也是系统自带缓存池子,和cell一样注册一下根据identifier来拿取即可,导航条的颜色会和前一个headView的颜色一样,这里由于我之前设置了导航控制器的主题
    [UINavigationBar appearanceWhenContainedIn:self, nil]
    
    • 所以不可以直接设置导航条的颜色了 ,然后我尝试了设置navigationBar的背景色,设置navigationBar的setTintColor:
      设置navigationBar.layer的背景色 以及根据颜色画出navigationBar的背景图片4种办法都无法达到原生的效果
      最后采用将navigationBar隐藏,自己放一个View了充当了导航条来解决这个问题(需要注意当切换控制器是对导航条隐藏属性的设置)
    - (void)viewWillAppear:(BOOL)animated
    {
        [super viewWillAppear:animated];
        //隐藏系统的导航条,由于需要自定义的动画,自定义一个view来代替导航条
        [self.navigationController setNavigationBarHidden:YES animated:YES];
    }
    

    发现

    • 这个页面是一个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,便可以拿到cell的模型push到下一个控制器,并将cell的模型赋值给下一个控制器
    -(void)iconButtonClick:(UIButton *)sender
    {
        //点击button通知代理
        if ([self.delegate respondsToSelector:@selector(foundCollectionViewCell:)]) {
            [self.delegate foundCollectionViewCell:self];
            }
    }
    

    登陆

    • 登陆只用了微信登陆和新浪登陆,不涉及到注册就非常简单,好多公司都会要求要用原生的登陆,只需要去新浪和微信的官网将SDK下载下来,并且按照官方给的帮助文档操作即可,如果公司没用硬性要求的话,我一般使用友盟平台的登陆,包括崩溃统计,三方登陆,分享,用户分析等等(这里提一嘴貌似QQ原生登陆必须写在appDelegate中,别的都写在哪里都行,遇到一次这个情况,有解决办法的朋友可以告诉我)

    消息

    • 一样这里也是tabelView,这里我个人的逻辑是将所有的未读的消息存放到本地数据库,每次点击删除一条,将本地的数据删除一条,有新的消息时直接写入到数据库

    • 当点击删除全部的时候,就清空本地的数据清空,下次接受的服务器的数据在重新写入到数据库,每次点击消息页面时去数据库查看是否有未读消息,如果有未读数据,变显示编辑按钮和cell

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

    • 这里记录编辑按钮的状态,读取本地是否有未读消息数组的个数,如果有就显示编辑按钮,记录编辑按钮的状态,如果是选中状态就隐藏cell中箭头图片,显示删除按钮,并且将删除按钮的状态设为选中,这样就可以切换按钮的文字了,将本地的数据数组删除掉并且刷新tableView,这里用的是删除动画,需要注意删除的顺序

        [self.datas removeObjectAtIndex:indexPath.row];
        [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationRight];
        //加入延时调用是防止删除后过快的就刷新tableView
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [self.tableView reloadData];
        });
    
    • 底部的删除完全交给编辑按钮来控制,选中状态时出现,非选中状态时消失,点击删除全部,直接将数组中的模型全部移除,然后清空数据库里的数据,刷新tableView

    搜索

    搜索搜索
    • 这个也需要持久化存储来记录用户的操作由于数据量比较小直接用plist即可,每次页面弹出后,先从本地读取用户历史搜索的数据,用户每次删除或者新输入搜索框内容时也直接写入到本地的caches文件中

    • 设置textFiled的代理,监听用户的完成输入,判断textFiled的text是否有长度,如果有的话发送给服务器响应的请求,并且将用户数据的string保存到本地的plist中

    • 这里需要提一下关于热门按钮的布局,因为热门的文字长度不一样,但每次只有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种效果)
    • 封装一个blurView,blurView的子控件有一个collectionView做用户选择用,一个imageView做模糊背景,以及一个取消按钮,将blurView添加给控制器的view做子控件,并且默认alpha值为0, 每次点击分类,地区,或者排序时,渲染当前tableView的layer的图片,并且将渲染好的图片赋值给blurView中的imageView,给imageView添加模糊效果,在配合改变blurView的alpha完成出现和消失即可

    详情页

    详情页展示详情页展示
    • 这个页面坑很多,需要注意的细节太多,也是我耗时最久的页面,诚然目前bug依旧不少

    • 这个页面的层级关系很重要,需要重点注意

    • 首先是导航条,这个咋一看好像是导航条有个渐隐渐现的动画,我的做法是在顶部放了一个高度为64的view,根据tableView的偏移量计算出view的透明度,但是透明度只是1或者0,顶部的scrollView里面装的imageView,根据服务器返回的图片地址个数,设置他的展示内容大小,并且在整一个scrollView最上面添加一个和导航条一样颜色的view,用它来做出向上推慢慢出现绿色的效果,并且根据底部scrollview的偏移计算拉伸的大小,这里拉伸的大小我算的不是很准确,感觉需要将锚点钉在最顶端,这应就可以做到只拉伸底部

    • 然后是中间切换tableView的view(后面就叫它选择view),要实现能像headView一样,卡在导航条下面的效果,这里因为没有导航条,并且在切换tableView时候不会带走选择view,所以只能将他放到和顶部的view在同一个层级中,同样根据底部scrollView的contentOffset.y计算他的位置,当偏移量超过顶部的64时,就停留在那,不超过时就回到顶部view的下面,这里的计算我加了很多的注释,怕计算的朋友也会看的懂的,大概是这样

      -(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) {
    
                if (scrollView == self.rmdTableView) {
    
                    self.infoTableView.contentOffset = CGPointMake(0, -245 - selectViewOffsetY);
    
                } else {
    
                    self.rmdTableView.contentOffset = CGPointMake(0, -245 - selectViewOffsetY);
    
                }
            }
    
        } else {
            //说明是backgroundScrollView在滚动
    
            CGFloat selectViewOffsetY = self.selectView.frame.origin.y - ScrollHeadViewHeight;
            //让新出来的tableView的contentOffset正好卡在selectView的头上,还是有bug
            if (selectViewOffsetY != -ScrollHeadViewHeight && selectViewOffsetY <= 0) {
    
                if (self.showingTableView == self.rmdTableView) {
    
                    self.infoTableView.contentOffset = CGPointMake(0, -245 - selectViewOffsetY);
    
                } else {
    
                    self.rmdTableView.contentOffset = CGPointMake(0, -245 - selectViewOffsetY);
    
                }
            }
    
            CGFloat offsetX = self.backgroundScrollView.contentOffset.x;
            NSInteger index = offsetX / WNXAppWidth;
    
            CGFloat seleOffsetX = offsetX - self.scrollX;
            self.scrollX = offsetX;
    
            //根据scrollViewX偏移量算出顶部selectViewline的位置
            if (seleOffsetX > 0 && offsetX / WNXAppWidth >= (0.5 + index)) {
                [self.selectView lineToIndex:index + 1];
            } else if (seleOffsetX < 0 && offsetX / WNXAppWidth <= (0.5 + index)) {
                [self.selectView lineToIndex:index];
            }
        }
    }
    
    • 下面是一个scrollView上添加了3个tabelView,根据服务器返回的数据判断显示多少个,这里就只显示了俩个tableView演示一下,如果有第三个的话直接添加到底部的scrollView即可,我的代码中因为只是演示两个tableView就将两个tableView交给了一个控制器管理,如果多个tableView最好将每个tableView交给独立的一个控制器来管理,各司其职,这样逻辑会清晰很多

    这些就是这个项目的大体思路,当然还有很多很多的细节都在代码中,感觉自己有很多想要表达的但是没法说出来,所以我在代码中加的很详细的注释,第一次尝试将思路写出来,感觉有很多不足,本应该每完成一个功能就总结一下,而我是在发布的晚上回头总结的,有很多当时的思路不是很清晰了...以后我会改善的,大家有什么意见可以直接留言,我看到会一一回复的!

    注意下载完工程请直接打开 点击运行点击运行

    附上代码的下载地址

    点击下载代码

    • 希望大家可以点一下右上角star⭐️,大家的支持与鼓励是我继续分享的动力_,欢迎大家多提意见和交流

    我的微博链接

    • 我会在以后更新学习Swift的心得以及发布一些Swift的小效果,欢迎朋友继续关注

    相关文章

      网友评论

      • c38cc430525d:作者很用心,不管注释还是回答问题,下载了几个别人的aap源文件不是xcode各种报错就是框架太多,这是唯一一个能正常打开的源文件,而却还那么多注释,太感谢了
      • 83bbb35816fb:大神,希望可以加个好友,谢谢。
      • codebystone:你好,有个问题想请教你,能加个好友吗?QQ158060394
      • 笙绳省盛:不知道楼主还在不在,想问下,如果要添加用户登录操作,需要怎么办。
        Top_熊:@笙绳省盛 你需要一个后台的服务器
        笙绳省盛:是不是要在真机上有微信或者新浪的客户端,在XCODE上无法实现吧
        Top_熊:@笙绳省盛 需要发送请求于服务器进行校验
      • e70382eaab9b:你好,我项目跟你详情页有类似的地方,但我是多个tableView,用scrollView来管理,类似网易首页,我如何判断滚动做向上滑动的渐显渐隐动画和固定选择View呢,求告知。QQ815801834
        e70382eaab9b:@Freewing 详情页面,有多个tableView,每个tableView交给各自的控制器管理,在主控制器里用一个底部的scrollView管理,我想问下,怎么判断上下滑动的逻辑?楼主的代码里是两个tableView直接写在主控制器里,所以很好拿到tableView,我是分开的,只能拿到各自管理tableView的控制器,求大神们帮帮忙!! :sob:
      • 36519128314d:你公司还招人吗,想跟你一起开发项目,你太吊了
      • 金康帅:// 学习的了你 <维尼的小熊>的源码.以及一些自认为不足的地方的优化.以及view手写代码.布局适配了,6 6P.
        //16号开始学. 8 /24号下午7点08基本全部完成.没有复制粘贴.部分大段的注释是粘贴的
        //感谢楼主了. :smile: :smile:
        学到了很多东西,注释也比较用心. 有想要看手写布局的可以私信我.
      • d496bf8fb8fe:450037443大神求指教
      • b13cd3e68764:作者加个好友,向你学习。11454326
      • YHWXQ简简单单的生活:楼主,可以加个好友吗?想请教一下您,谢谢,本人QQ:1223394868
      • 0x00chen:楼主在这里问你一个问题,一个tabbar视图 首页上面有一个button点击一下直接跳到第二个tabbar的页面,下面的tabbaritem 也自动移动到第二个 怎么做啊
      • 7b6c4671d61e:向你学习,可以的话希望能加个好友向你请教问题907356745 谢谢啦😆
      • ba73a6f69e84:楼主加个好友吧,我项目有个功能跟你项目中的功能类似,想请教你一下!QQ:1581592540。
        急求!!!!!!!!!
      • 6dbbc3992d92:大兄弟 你是真的机智 啊 ,我喜欢
      • 954a32f45ce1:谢谢分享 登录的方法什么时候实现类
      • InitWithYou:您好!本人新手,我有个疑问,您的详情页面,不可以拖拽顶部图片和selectView吖。这样用户体验会很不舒服,万一我图片下面还有很长一个Lab显示介绍信息,把tableView挤出屏幕下方了怎么办呢,能有什么方法用您这种思路而且能拖拽图片么?我尝试添加拖拽手势也不行。。求指导。。
        金康帅:@ydw灬yidawu 拖拽图片比较简单,是用 scrollviewDiddrag ;scrollStopDrag这种类似的方法写的 .你去看看scrollView的代理方法 ,tableview挤出屏幕是在初始化 tableview 的时候,cgrectmake(0,64,APPWIDTH,APPHEIGHT -64) 要把导航栏减掉 减64 这样子.不知道过了那么久,你应该会了,不过我还是和你讲一下
      • mile_zzz:mark ,
      • 浅浅浅丶蓝:大神写的不错,但是搜索历史删没有的时候会出现问题,分区表头都是热门,退出再进,两个分区cell一样是热门标签. 我试了下也没解决 :joy:
        金康帅:@浅浅浅丶蓝 我改进了作者的这个地方的不妥,代码如下.主要是1:如果有历史就返回两个secction; 如果没有就只返回热门这个secttion,删除历史记录我改为了更加通用的:在table的head上再加一个button,作为删除全部的历史记录.这里直接清除文件就OK了.这样bug就基本解决了,还有不清除的可以再问我.我把有些小bug给解决了.还有手写代码了改为.. :smile:
        -(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
        //注册head的方法和cell差不多
        CNSearchHeadView *head =(CNSearchHeadView*)[tableView dequeueReusableHeaderFooterViewWithIdentifier:@"head"];
        if (head ==nil) {
        head =[CNSearchHeadView headView];
        }
        if (self.datas.count ==2) {
        if (section == 0) {
        head.headTextLabel.text =@"历史";
        [head.headClearButton addTarget:self action:@selector(historyClearClick:) forControlEvents:UIControlEventTouchUpInside];
        return head;
        }else{
        head.headTextLabel.text =@"热门";
        head.headClearButton.hidden =YES;
        return head;
        }

        }else{
        head.headTextLabel.text =@"热门";
        head.headClearButton.hidden =YES;
        return head;

        }
        }

        -(void)historyClearClick:(UIButton *)sender{
        [_hisDatas removeAllObjects];
        [self.hisDatas writeToFile:CNSearchHistoryPath atomically:YES];
        [self.tableView reloadData];

        }
      • 59a63886e799:楼主,加个好友吧,我是新手,有好多地方没看明白,希望楼主能够指点我,谢谢。我QQ377933961
      • 9ee8e46c6101:感谢楼主分享,非常有用,之前一直做安卓开发,最近公司要求做ios ,莫大帮助,感谢,感谢
      • 简笑笑:@维尼的小熊 您好我发现,消息模块setModel方法中的messageLabel在[self layoutIfNeeded]前后高度发生了变化,想问是怎么做到的这是我的qq979310021希望您能给我解答下
        金康帅:@简笑笑 self layoutIfNeeded 1.在创建的模型中写入了这个label的高 的属性,然后在view中加入这个模型作为属性,然后才setModel 就是把模型model 设置成了view的属性property .然后服务器返回数据时,就会把行高的值传入模型中,layoutifneeded是系统的方法,当有frame值 改变时,就重新布局.
      • AIlls:可以加QQ吗。。像你学习。。大神。。。409978617
      • 逸小枫:大神,真的,我有一颗极具想进步的心,方便加下QQ 以后能好好交流一下么 277735871 跪谢 本人是培训出来的现在在一家公司实习
      • 在没老之前:楼主好人!不过希望楼主可以写一个两个tableView的交互的demo。我刚刚工作没多久,有这么一个需求。左侧的tableView显示年份,点击年份,展开月份,然后点击对应的月份,右边的tableView展示对应的数据 :grin:
      • ChangeBegin:楼主,类似首页详情界面的布局,有些问题想问一下,你的qq多少?我的1291640687,谢谢
      • helloDolin:赞赞赞👍
      • 海泉:赞
      • 942babc7fadf:啊 大神 我下了你的代码 想参考下你的思路 可是代码下载下来直接报错clang: error: linker command failed with exit code 1 (use -v to see invocation) clang: error: linker command failed with exit code 1 (use -v to see invocation) 这是怎么回事啊

      • _令_狐_冲_:真心不错~~ :+1:
      • N1n9:楼主好棒.我最近在学习swift. 有很多不懂的地方. 看了你的smallDay收获很多.希望你加一下我QQ605865863.有问题可以帮忙指导一下. :relaxed:
      • FlyingPenguin:iPad 系列还没有正常兼容 都有黑边 以iPad pro为甚。
      • 阿龙欧巴:看着爱鲜蜂那个,觉得目前要不还是先把你这个看完,毕竟是OC的,因为swift目前还不是很了解,学习ing!谢谢分享!!
        Top_熊:@阿龙欧巴 哪个是你啊..加的人实在太多了 我没法辨别出来哪个是...
        阿龙欧巴:@维尼的小熊 鸡冻万分啊!我看到你微博说下一个是一个游戏,期待ing!(PS:你好像木有加我QQ,我申请了😭,不要抛弃小白)
        Top_熊:@阿龙欧巴 恩 慢慢看吧 等你都看完了 我估计新的也来了~
      • 谢朝森:您好:我在编译的时候出现如下的错误:
        ld:library not found for -lpods -MJExtension
        clang: error: linker command failed with exit code 1 (use -v to see invocation)
        我在网上查找了些方法,但是没有用,希望大神能够帮忙解决下。
      • f880df0a921d:你的qq是多少呀???
      • 9dd4bf77b2ae:厉害 能加我q吗 我也想请教 654774214
      • e82908282270:ld: library not found for -lPods-MJExtension
        clang: error: linker command failed with exit code 1 (use -v to see invocation)
      • b226fe1c3711:哥们,写的非常不错。我遇到一个问题,想请教一下你。我qq295014159.多谢。
      • 0超人bu会飞0:小熊同学 搜索界面,当把搜索历史都删除后,会出现两个“热门”标题哦
      • 寓言命理风水占测师:你好 大神 项目急需参考,,能给一份可以运行的版本吗????谢拉 315970520@qq.com,
      • bacb89cb92b6:你好 对你的项目非常感兴趣 能成为好友吗 希望以后的相互交流 807480635 望成为好友 楼主最棒
      • d170d6e3cec6:我的qq 1262258751,看了你的文章后有好多问题,想向你请教,楼主加个好友吧 :grin:
      • fdfcbc8ab62f:楼主 楼主加个好友吧 刚刚学习ios 半年 603334504
      • 蜗壳美如画:大神你好,能加我QQ吗: 397866153,验证信息 随便写 , 或者你开个群吧, 你的项目框架我很喜欢啊,想和你多多交流
      • 李白不读书: 扣扣635835286 大神求大腿
      • 子斌:楼主,麻烦问下,GiF图片是怎么制造哒?
      • 随风__陈坪__:加个好友 17528063 我是ios开发
      • chatwyn: :smile: 大神我要向你学习 ,求多指点
      • 壹点微尘:写的不错 学习了
      • Hosealee:楼主写的很好 正准备入swift 谢谢楼主的详细介绍
      • 轩辕小羽:好文!有用!已打赏! :smiley:
        Top_熊:@轩辕小羽 3q 推荐你看看我写的爱鲜蜂,那个写的比较认真😅
      • 0b795899cd51:ui实现思路写的很详细 但是我最近在研究业务逻辑和数据持久层或者需不需要这些层 因为要给我们学习小组的项目搭建一个框架 使得组里同学能好分工 一个人负责ui 一个人负责内部逻辑 一个人开发特色的功能 请问您有没有类似的设计思路
      • 444bb6bb4f18:看着思路比较清晰,下载下来借鉴敲一个。
        :+1:
      • 69c81508658f:最近在做一个漫画的项目,希望和大神做个朋友
      • 选一个昵称也被使用了:写的挺好的,那么多东西都自己做了
      • Liusr:太感谢了,最近也在模仿这个app.有好多地方不知道怎么写,向您学习啦! :pray:
      • 747b09fa0709:441991224 楼主求加~
      • 我就叫土豆:博主,你好,能加个QQ吗?228243482
      • 48e030ceaec7:lz你个逗比,左按钮的事件命名是right,右按钮的事件是left,你是左撇子吗
      • e5858e4415c1:问下楼主,你的项目里UI是怎么写的,不是用StoryBoard拉控件吗,还是直接代码实现的?
      • 844ef49a4da7:835932621楼主看到回我。谢谢!
      • eaab518c46fc:谢谢分享。
      • 鱼鱼鱼四只鱼:楼主还真是耐心,没有一点点架子,以后多多交流学习
      • 苹果酸的:学长好6
      • 与世倾听X游定终生:超赞的分享,感谢😊
      • d51c03969594:哇塞 大神啊 这么迟才看见是我的损失,加个好友哈1342505786 :pray: 谢谢
      • qbk1989:加个好友呗,qq:121342920 还想请教你一些其他的问题
      • SPIREJ:小熊你好,请问你写这个文章的时候,项目展示是怎么做的?还有图片你怎么控制的显示大小? :cry:
        SPIREJ:请问一下在贴代码的时候中间的*号会消失,如何解决?比如:MLNavigationController *mlNav = [[MLNavigationController alloc] initWithRootViewController:threeVC];中间的8号贴出来会消失。
        SPIREJ:@维尼的小熊 谢谢,我试试 :blush:
        Top_熊:@SPIRE丶J 用的licecap这个软件截取gif图片
      • 夜殇丶夜逝:你好 谢谢你的分享 看完你的项目我学到很多东西. 方便加一下好友吗 以后可能要多叨扰你了
        夜殇丶夜逝:QQ:874600238
      • f95e75e8f2cd:楼主加下好友,我在看你的项目,最近在写项目,看你的右写东西没有看懂想向你请教下可以么Q185988077
      • ddaff34313ab:很给力,谢谢了
      • 0294b96fe4db:楼主 急需此项目swift版,公司要swift开发 万分感谢
      • 言十年:模仿的两个项目,不错呢!怎么找原的模仿对象呢?这都不是主流的app呢
        言十年:@维尼的小熊 挺好的
        Top_熊:@言十年 appstore呀
      • 383bcce0c238:有空请教下,可以嘛?q:1538627809
      • 383bcce0c238:新手,不想坑公司,所以想代码规范点,希望大牛多指点下
      • iOS小虫下米:QQ 453141759 很仔细看了楼主的分享,希望能一起探讨 :pray:
      • 程旭媛:城觅客户端里 搜索-特色标签里点击箭头可以向下显示更多,然后再次点击就可以缩回去,请问这种效果如何实现呢?程序里有个显示更多评论信息需要这样子的效果 望博主指教 多谢!
      • 070c7851dd88:你的代码中,我仿佛看到了李明杰的身影。
      • EagleOne:我查阅相关博客,手势仿射变换那里比例这样写是不是更好 CGFloat scaleXY = 1 - moveX / maxMoveX * (1 - zoomScale);
        //根据手势移动距离缩放的比例
        CGAffineTransform transform = CGAffineTransformMakeScale(scaleXY, scaleXY);
        //后面两个参数是根据手势移动的距离delatX;
        self.showViewController.navigationController.view.transform = CGAffineTransformTranslate(transform, moveX*scaleXY, 0);
      • smalldu:楼主叼叼的
      • EagleOne:博主,请问一下仿射变换那里是怎么算比例的吗,能不能介绍的详细点,新手谢谢了
      • runningJoey:果断加好友,我的QQ:24302437,加一下,谢谢!!
      • Scott_Mr:我想请问一下你用百度地图的时候,怎么做到点击某个标注的时候将那个点击的标注显示在最前面呢?
        Scott_Mr:@维尼的小熊 我的需求是这样子的,先从后台获取一些经纬度,然后我点击某个标注,得把标注移动到地图中心,并且又再一次请求数据,然后在根据返回的经纬度去写标注,所以我怀疑是重新添加标注引起不显示点击的那个标注在最上面
        Top_熊:@Scott_Mr 我用的高德地图,自带效果就可以,如果没有自带效果的话,可以点击后,拿到当前点击的标记,讲他插入到父控件的最上面也可以解决的
      • 8c6d96ef3f76:报MAMapkit file not found 该怎么解决呢 大神
      • 9913e661dff4:多谢分享!
      • 817fa77a6cc7:小熊哥 你说的swift项目啥时候能发布呢 公司要换swift来写新项目了 我研究了一周多了 总是遇到各种问题 网上也查不到 :disappointed_relieved: 求大腿
        817fa77a6cc7:@维尼的小熊 期待 :pray:
        Top_熊:@大保健不 大概九月中旬吧,已经在写了,这个项目功能我基本都会做的,会第一时间发布的
      • Sheepy:非常感谢分享~最近半年我也在学Swift,希望有空能跟楼主交流哈,加楼主qq了,等待通过~
      • 燕语呢喃嗅花香:楼主大赞!! :+1: :+1: :+1: 特意注册账号来支持一下,希望楼主加个好友,QQ1191486202
      • zhcoder:cell滑动卡顿比较明显!
      • 91阿生:大神呀! 我想做个你项目中 详情页控制器 中得效果 我看了下你项目中写的 看的头晕了 不知道整体控件的构思 凌乱!! 求指导呀! 谢谢哈!!
      • 497517efcf36:楼主 我下你的程序下来 编译报错 能帮我解决下吗
      • _wzz:无意见到此贴,对楼主深表敬意!!请接受我的膝盖,特地注册了个号来膜拜一下!
      • shiningsky67:QQ 1146518547 希望共同学习 iOS开发
      • codeGlider:好良心·啊·,谢谢分享!
      • iStig:打赏完成,博主算比较有心的,没用第三方一个一个手动实现
        Top_熊:@iStig 😃谢谢
        iStig:@iStig 关键一点是作法都比较朴实,方便新手练习和理解
      • 小小黑枣:我也想加大神的qq,我的qq714981451

      本文标题:iOS高仿城觅项目(开发思路和代码)

      本文链接:https://www.haomeiwen.com/subject/pvdpqttx.html