高仿美团<二>

作者: 土鳖不土 | 来源:发表于2015-08-30 17:59 被阅读4350次

    亲爱的粉友们我又回来了。

    继上一次高仿美团主界面之后我说我会持续更新的,还说重要的事情说三遍。由于最近项目比较紧就很比较难挤出时间去coding;
    不话痨了:上次就想给大家分享一个项目的最初搭建但是,由于太匆忙就没上,今天补上 哈哈!先分析一下项目的目录结构吧:
    其他的文件夹就不多说了,主要的类都在Class里面按照功能模块建一个文件夹,最好建一个工具类,和分类这样业务更加分明。其中工具类把整个项目都用到的功能抽取出来。比如说快速加载XIB,plist,网络等等。


    屏幕快照 2015-08-30 15.55.25.png

    接下来在每个功能模块的文件夹里面放MVC。

    屏幕快照 2015-08-30 16.01.12.png

    这些都只是个人习惯,个人觉得比较爽比较舒服,没有好坏之分。
    有图有真相:

    主界面-首页 上门 商家 我的 更多 运行效果

    接下来我按一个功能模块一个模块讲解整个项目

    首页

    首先先声明下本项目中的下啦刷新用的是MJRefresh,还有的第三方框架有MJExtension,AFN,SDWebImage(顺便个MJ打个广告)
    #pragma mark - 设置下啦刷新
    -(void)setRefreshIntableView{
    [self.firstTableView addGifHeaderWithRefreshingTarget:self refreshingAction:@selector(refreshData)];`

    //设置普通状态的动画图片
    NSMutableArray *idleImages = [NSMutableArray array];
    for (NSUInteger i = 1; i<=60; ++i) {
        UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:@"dropdown_anim__000%zd",i]];
        [idleImages addObject:image];
    }
    [self.firstTableView.gifHeader setImages:idleImages forState:MJRefreshHeaderStateIdle];
    
    //设置即将刷新状态的动画图片
    NSMutableArray *refreshingImages = [NSMutableArray array];
    for (NSInteger i = 1; i<=3; i++) {
        UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:@"dropdown_loading_0%zd",i]];
        [refreshingImages addObject:image];
    }
    [self.firstTableView.gifHeader setImages:refreshingImages forState:MJRefreshHeaderStatePulling];
    
    //设置正在刷新是的动画图片
    [self.firstTableView.gifHeader setImages:refreshingImages forState:MJRefreshHeaderStateRefreshing];
    
    //马上进入刷新状态
    [self.firstTableView.gifHeader beginRefreshing];
    

    }
    解释如上代码注释,已经非常清楚了,就是给当前的tableView, [self.firstTableView addGifHeaderWithRefreshingTarget:self refreshingAction:@selector(refreshData)];
    然后将所需要的动画图放在一个数组里面。然后设置三种状态的刷新。
    说白了首页就是一个tableView。这个tableView分为5个section.
    每个section里面的cell进行自定义。就是这么简单粗暴。

    再说下怎么封装tableViewCell,为什么我们要封装他呢?为什么要封装他,原因通俗一点就是,cell是个视图,视图怎么创建cell自己最清楚。没必要让控制器知道。
    送大家我之前说我的一句话:

    控制器知道的越少越好,否则你将死的很惨!!!。

    举个例子:
    1.创建自定义的tableViewCell要不要XIB随你(我这个例子用XIB)。

    #import <UIKit/UIKit.h>
    @class JFHotQueueModel;
    @interface JFHotQueueCell : UITableViewCell
    @property (weak, nonatomic) IBOutlet UIImageView *hotQueueImageView;
    @property (weak, nonatomic) IBOutlet UILabel *mianLabel;
    @property (weak, nonatomic) IBOutlet UILabel *subtitleLabel;
    //提供一个模型的set方法
    @property (nonatomic, strong)JFHotQueueModel *hotQueueModel;
    //提供一个类方法传一个tableView快速创建一个cell
    + (instancetype)cellWithTableView:(UITableView *)tableView;
    

    这个地方再送你一句话:tableView,collectionView,地图标注等都可以这个干,(举一返三,这是一个能力)几百万个项目,每个项目N种做法,难到我们都要敲一遍?(SB才这个干)起初我们可以模仿,在模仿中总结。一步一个脚印。我去扯的优点远了.

    tableViewcell.m里面的实现

    + (instancetype)cellWithTableView:(UITableView *)tableView
    {
        static NSString *ID = @"hotqueue";
        JFHotQueueCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
        if (cell == nil) {
            // 从xib中加载cell
            cell = [[[NSBundle mainBundle] loadNibNamed:@"JFHotQueueCell" owner:nil options:nil] lastObject];
        }
        return cell;
    }
    #重写model的set方法,给XIB里面的控件赋值
    -(void)setHotQueueModel:(JFHotQueueModel *)hotQueueModel{
        _hotQueueModel = hotQueueModel;
        NSURL *urlStr = [NSURL URLWithString:hotQueueModel.imageUrl];
        [self.hotQueueImageView sd_setImageWithURL:urlStr  placeholderImage:nil];
        self.mianLabel.text = hotQueueModel.title;
        self.subtitleLabel.text = hotQueueModel.comment;
    }
    

    好了第二个界面:

    上门

    这个界面主要讲下,这么封装图片轮播器

    cell上的轮播器

    毫无疑问这个轮播器在cell上面。
    只要将cell创建好后将封装好的轮播器加在上面就完事了
    自定义轮播器的视图
    .h文件

    @interface JFImageScrollView : UIView
    @property (nonatomic, strong)UIScrollView *scrollView;
    @property (nonatomic, strong)UIPageControl *pageControl;
    @property (nonatomic, strong)NSArray *imgArray;
    -(void)setImageArray:(NSArray *)imageArray;
    /**
     *  创建一个ScrollView
     *
     *  @param frame      供外界提供一个frame
     *  @param imageArray 供外界提供一个图片数组
     *
     *  @return 返回一个自定义的ScrollView
     */
    -(JFImageScrollView * )initWithFrame:(CGRect)frame imageArray:(NSArray *)imageArray;
    

    .m文件

    @interface JFImageScrollView ()<UIScrollViewDelegate>{
        NSTimer *_timer;
        int _pageNumber;
    }
    @end
    @implementation JFImageScrollView
    -(JFImageScrollView * )initWithFrame:(CGRect)frame imageArray:(NSArray *)imageArray{
        self = [super initWithFrame:frame];
        if (self) {
            self.scrollView = [[UIScrollView alloc]initWithFrame:frame];
            self.scrollView.contentSize = CGSizeMake(4 * SCREENWIDTH, frame.size.height);
            self.scrollView.pagingEnabled = YES;
            self.scrollView.delegate = self;
            self.scrollView.showsHorizontalScrollIndicator = NO;
            //添加图片
            for(int i = 0 ; i < 10; i++){
                UIImageView *imageView = [[UIImageView alloc] init];
                imageView.frame = CGRectMake(i*SCREENWIDTH, 0, SCREENWIDTH, frame.size.height);
                imageView.tag = i+10;
               // UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(OnTapImage:)];
                //[imageView addGestureRecognizer:tap];
                imageView.userInteractionEnabled = YES;
                [self.scrollView addSubview:imageView];
            }
            [self addSubview:self.scrollView];
            
            //
            self.pageControl = [[UIPageControl alloc] initWithFrame:CGRectMake(SCREENWIDTH/2-40, frame.size.height-40, 80, 30)];
            self.pageControl.currentPage = 0;
            self.pageControl.numberOfPages = 6;
            [self addSubview:self.pageControl];
            
            [self addTimer];
    
            
        }
        return self;
    
    }
    
    -(void)setImageArray:(NSArray *)imageArray{
        _pageNumber = (int)imageArray.count;
        self.scrollView.contentSize = CGSizeMake(imageArray.count * SCREENWIDTH, self.frame.size.height);
        self.pageControl.numberOfPages = imageArray.count;
        //添加图片
        for(int i = 0 ; i < imageArray.count; i++){
            UIImageView *imageView = (UIImageView *)[self.scrollView viewWithTag:i+10];
            imageView.backgroundColor = [UIColor redColor];
    
            NSString *imageName =[NSString stringWithFormat:@"%@",imageArray[i]];
            NSLog(@"%@",imageName);
            [imageView sd_setImageWithURL:[NSURL URLWithString:imageName] placeholderImage:[UIImage imageNamed:@"bg_customReview_image_default"]];        
        }
    }
    //添加计时器
    -(void)addTimer{
        _timer = [NSTimer scheduledTimerWithTimeInterval:3 target:self selector:@selector(netxPage) userInfo:nil repeats:YES];
        [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
    }
    //移除计时器
    -(void)removeTimer{
        [_timer invalidate];
        _timer = nil;
    }
    //计时器每一秒的响应方法
    -(void)netxPage{
        int page = (int)self.pageControl.currentPage;
        if (page == _pageNumber-1) {
            page = 0;
        }else{
            page++;
        }
        //滚动scrollview
        CGFloat x = page * self.scrollView.frame.size.width;
        self.scrollView.contentOffset = CGPointMake(x, 0);
    }
    
    #pragma mark - UIScrollViewDelegate
    //滑动时scrollView代理方法,计算出当前滑动到哪里。加上视图宽度的一半,再整除滚动视图宽度,算出第几页。
    -(void)scrollViewDidScroll:(UIScrollView *)scrollView{
        CGFloat scrollViewW = scrollView.frame.size.width;
        CGFloat x = scrollView.contentOffset.x;
        int page = (x + scrollViewW/2)/scrollViewW;
        self.pageControl.currentPage = page;
    }
    //开始拖动时,就关闭计时器,因为这个时候用户在交互。
    -(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
        [self removeTimer];
    }
    //结束拖动的时候就立马再加上计时器
    -(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
        [self addTimer];
    }
    
    /**
     *  移除定时器
     */
    -(void)dealloc{
        [self removeTimer];
    }
    

    接下来:就是创建八个视图给每个视图加手势,之前已经说过了,就不赘述。


    八个视图

    商家

    分类

    这个界面主要讲下这个自定义视图怎么自定义的
    如图所示很明显就是两个tableVew.
    上代码:
    .h

    @protocol JFMerchantFilterViewDelegate <NSObject>
    
    @optional
    -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath withId:(NSNumber *)ID ;
    
    @end
    @interface JFMerchantFilterView : UIView
    /**
     *  全部分类的tableView
     */
    @property(nonatomic, strong) UITableView *tableViewOfGroup;
    /**
     *  每组详情的tableView
     */
    @property(nonatomic, strong) UITableView *tableViewOfDetail;
    @property (nonatomic, weak) id <JFMerchantFilterViewDelegate> delegate;
    

    .m
    既然是两个tableView那么就提供两个数据源,两个下标,用来识别那个tableView被点击了哪一行。

    @interface JFMerchantFilterView ()<UITableViewDataSource, UITableViewDelegate>
    {
        NSMutableArray *_bigGroupArray;//左边分组tableview的数据源
        NSMutableArray *_smallGroupArray;//右边分组tableview的数据源
        NSInteger _bigSelectedIndex;
        NSInteger _smallSelectedIndex;
    }
    @end
    @implementation JFMerchantFilterView
    /*
    // Only override drawRect: if you perform custom drawing.
    // An empty implementation adversely affects performance during animation.
    - (void)drawRect:(CGRect)rect {
        // Drawing code
    }
    */
    -(instancetype)initWithFrame:(CGRect)frame{
        self =[super initWithFrame:frame];
        if (self) {
            _bigGroupArray = [[NSMutableArray alloc] init];
            _smallGroupArray = [[NSMutableArray alloc] init];
            [self initViews];
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                [self getCateListData];
            });
        }
        return self;
    }
    
    -(void)initViews{
        for (int i = 0 ; i < 2; i ++) {
            
            UITableView *tableView = [[UITableView alloc] initWithFrame:CGRectMake(i *TableViewW/2,  0, TableViewW/2, TableViewH) style:UITableViewStylePlain];
            tableView.tag = 10 + i ;
            tableView.delegate = self;
            tableView.dataSource = self;
            if (i == 0 ) {
                self.tableViewOfGroup =tableView;
                self.tableViewOfGroup.backgroundColor = [UIColor whiteColor];
    
            }else{
                self.tableViewOfDetail =tableView;
                self.tableViewOfDetail.backgroundColor = RGB(242, 242, 242);
    
            }
            tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
            [self addSubview:tableView];
    
        }
    
    }
    
    -(void)getCateListData{
        NSString *urlStr = [[GetUrlString sharedManager]urlWithCateListStr];
        [NetWork sendGetUrl:urlStr withParams:nil success:^(id responseBody) {
            JFLog(@"%@", responseBody);
            NSMutableArray *dataArray = [responseBody objectForKey:@"data"];
            for (int i = 0; i < dataArray.count; i++) {
                JFMerchantCataGroupModel *cateModel = [JFMerchantCataGroupModel objectWithKeyValues:dataArray[i]];
                [_bigGroupArray addObject:cateModel];
            }
            [self.tableViewOfGroup reloadData];
        } failure:^(NSError *error) {
            
        }];
    }
    
    #pragma mark - UITableViewDataSource
    -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
        if (tableView.tag == 10) {
            return _bigGroupArray.count;
        }else{
            if (_bigGroupArray.count == 0) {
                return 0;
            }
            JFMerchantCataGroupModel *subclassCateM = (JFMerchantCataGroupModel *)_bigGroupArray[_bigSelectedIndex];
            if (subclassCateM.list == nil) {
                return 0;
            }else{
                return subclassCateM.list.count;
            }
        }
    }
    
    -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
        return 42;
    }
    
    -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
        if (tableView.tag == 10) {
            JFKindFilterCell *cell = [JFKindFilterCell cellWithTableView:tableView];
            cell.merchantCataGroupModel = _bigGroupArray[indexPath.row];
            return cell;
        }else{
             JFMerchantCataGroupModel *cateModel = (JFMerchantCataGroupModel *)_bigGroupArray[_bigSelectedIndex];
            JFKindSubclassFilterCell *cell = [JFKindSubclassFilterCell cellWithTableView:tableView indexPath:indexPath model:cateModel];
            return cell;
        }
        
    }
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
        if (tableView.tag == 10) {
            _bigSelectedIndex = indexPath.row;
            JFMerchantCataGroupModel *cataModel =  _bigGroupArray[_bigSelectedIndex];
            [self.tableViewOfDetail reloadData];
            if (cataModel.list == nil) {
                [self.tableViewOfDetail reloadData];
                [self.delegate tableView:tableView didSelectRowAtIndexPath:indexPath withId:cataModel.id];
            }else{
                [self.tableViewOfDetail reloadData];
            }
        }else{
            _smallSelectedIndex = indexPath.row;
            JFMerchantCataGroupModel *cataModel =  _bigGroupArray[_bigSelectedIndex];
            NSDictionary *dict =  cataModel.list[_smallSelectedIndex];
            NSNumber *ID = [dict objectForKey:@"id"];
    //        NSString *name = [dic objectForKey:@"name"];
            [self.delegate tableView:tableView didSelectRowAtIndexPath:indexPath withId:ID ];
            
        }
    }
    

    我的和更多

    最后两个界面都是比较简单的就不多说了。
    如果不懂的话可以直接简信,或者直接评论,我会一一解答。
    有好的建议我会非常感谢。
    完整的项目源码会在 会下一次放在github上。(这次就不放了哦,下一次会是一个比较完整的JF团购 呈现给大家)

    希望你可以继续关注我。

    最后重申一下本项目持续更新中。。。

    2015 - 08 - 30

    相关文章

      网友评论

      本文标题:高仿美团<二>

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