美文网首页
项目的编程思想以及亮点

项目的编程思想以及亮点

作者: woniu | 来源:发表于2019-04-19 15:23 被阅读0次

    今天系统的总结下项目中遇到的问题以及比较好的点,也有利于以后问题的避免和解决。
    一、GIF展示。
    使用第三方YYIamge来处理GIF的展示,原本想着使用SDWebImage来处理这个问题,但是碰了很多壁这里就不多说了,试来试去还是YYAnimatedImageView用着最方便简介,所以就直接介绍YYAnimatedImageView的使用实例了。

    1、首先在cell的.h文件中导入头文件
    #import "YYAnimatedImageView.h"
    #import "YYWebImage.h"
    2、设置ImageView.
    @property (nonatomic,retain)  YYAnimatedImageView *CellImage;
    3、在.m文件中添加处理。先初始化,然后在setUpModel方法中赋值。这里用的是典型的MVC模式。
     self.CellImage = [[YYAnimatedImageView alloc]initWithFrame:CGRectMake(0, 0, (ZHWidth-60)/3, (ZHWidth-60)/3)];
     if ([model.pkgImg rangeOfString:@"gif"].location !=NSNotFound) {
            [self.CellImage yy_setImageWithURL:url options:YYWebImageOptionProgressiveBlur |YYWebImageOptionShowNetworkActivity];
        }
        else {
            [self.CellImage yy_setImageWithURL:url options:YYWebImageOptionProgressiveBlur|YYWebImageOptionSetImageWithFadeAnimation];
        }
    

    YYImage的链接

    二、绘本翻页
    翻页的效果比较复杂,为了找到一个合适的第三方也是花费了很多时间寻找和调试,最后终于实现了功能。这里有几个注意点:
    1、mpflipviewcontroller原项目使用的是上下翻页的效果,我们需要修改一下翻页的方向。在代理中修改反转的方向类型为4

    - (MPFlipViewControllerOrientation)flipViewController:(MPFlipViewController *)flipViewController orientationForInterfaceOrientation:(UIInterfaceOrientation)orientation
    {
    //    return MPFlipViewControllerOrientationVertical;
        orientation = 4;
        if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
            return UIInterfaceOrientationIsPortrait(orientation)? MPFlipViewControllerOrientationVertical : MPFlipViewControllerOrientationHorizontal;
        else
            return MPFlipViewControllerOrientationHorizontal;
        
    }
    

    这里有一点还没与解决,我在iPhone上面可以横屏,但是在iPad上面无法横屏,还有有些奇怪。待解决......
    2、由于翻页的页面布局不同,所有我们需要设置不同的XIb界面进行加载。
    mpflipviewcontroller

    三、网络封装
    1、设置VM,封装网络请求。

    //banner 的跳转接口
    +(void)latestAudioBoosWithID:(NSNumber *)pkgID callback:(InterfaceManagerBlock)completion;
    
    //  3.19日 新的免费故事&会员专区
    +(void)queryAllAudioBookPkg:(NSString *)free pageIndex:(NSNumber *)index callback:(InterfaceManagerBlock)completion;
    
    +(void)queryAllAudioBookPkg:(NSString *)free pageIndex:(NSNumber *)index callback:(InterfaceManagerBlock)completion {
        
        NSMutableDictionary *dic = [NSMutableDictionary dictionary];
        SetObjForDic(dic, free, @"subsReqd");
        SetObjForDic(dic, @8, @"pageSize");
        SetObjForDic(dic, index, @"pageIndex");
        [InterfaceManager startRequest:API_AUDIOBOOK_queryLatestAudioBookList
                              describe:@" "
                                  body:dic
                           returnClass:[PkgListModel class]
                            completion:^(BOOL isSucceed, NSString *message, ResultModel *result)
         {
             
             if (completion) {
                 completion(isSucceed, message, result.dataList);
             }
         }];
    }
    

    2、设置InterfaceManager网络请求的管理类,封装GET、POST。

    /** 统一接口请求   Post请求*/
    + (NSURLSessionDataTask *)startRequest:(NSString *)action
                describe:(NSString *)describe
                    body:(NSDictionary *)body
             returnClass:(Class)returnClass
              completion:(InterfaceManagerBlock)completion
    {
        
        
       return [WebService startRequest:action
                            body:body
                     returnClass:returnClass
                         success:^(NSURLSessionTask *task, ResultModel *result)
         {
             [self succeedWithResult:result describe:describe callback:^(BOOL isSucceed, NSString *message, id data) {
                 completion(isSucceed,message,data);
             }];
         } failure:^(NSURLSessionTask *task, NSError *error)
         {
             LogError(@"%@", error);
              completion(NO, @"request failed", nil);
         }];
    }
    

    3、在WebService类中分别处理传递过来的数据,进行网络请求,然后返回数据。

    #pragma 发起POST请求
    + (NSURLSessionDataTask *)startRequest:(NSString *)action
                    body:(NSDictionary *)body
             returnClass:(Class)returnClass
                 success:(RequestSuccessBlock)sblock
                 failure:(RequestFailureBlock)fblock
    {
    
        NSString *url = [WebService pathUrl:action];
        AFHTTPSessionManager* manager = [WebService sessoionConfigration:[url hasPrefix:@"https://"]];
    
        return [manager POST:url
                  parameters:body
                    progress:^(NSProgress *uploadProgress){}
                     success:^(NSURLSessionTask *task, id responseObject) {
                         
            NSString *responseStr = [WebService jsonStrFromTask:task
                                                       response:responseObject
                                             responseSerializer:manager.responseSerializer];
            [WebService callbackWithResponse:responseStr
                                 returnClass:returnClass
                                        task:task
                                     success:sblock
                                     failure:fblock];
            
        } failure:^(NSURLSessionTask *task, NSError *error) {
            // 请求失败
            if (fblock) {
                fblock(task, error);
            }
        }];
        
    }
    

    4、最重要的一点就是字典转model。
    先说一下思路,在请求到数据之后,使用相应的model进行转化,将对应的参数分别转换成model,之后再将model返回,在主界面中使用。由于涉及的代码比较多,我们只截取关键的代码展示即可。

       ResultModel *result = [WebService getResultWithString:responseStr
                                                  returnClass:returnClass
                                                     andError:&err];
    

    getResultWithString:responseString方法中转化model:

    ResultModel *aRespond = [[ResultModel alloc] initWithString:aString error:nil];
            if (returnClass) {
                if([aRespond.data isKindOfClass:[NSDictionary class]]){
                    NSError *error = nil;
                    //1、json转化成类  ResultModel继承了jsonModel.
                    aRespond.data = [[returnClass alloc] initWithDictionary:(NSDictionary *)aRespond.data error:&error];
                    if (error) {
                        aRespond.resultMsg = @"Parse the JSON data failed";
                    }else{
                        return aRespond;
                    }
                }
    

    四、横竖屏展示
    1、进入页面的时候在viewWillAppear中调用如下方法强制横屏,也可以设置屏幕的旋转方向。

    - (void)viewWillAppear:(BOOL)animated{
        [super viewWillAppear:animated];
        //隐藏NavigationBar,否则横屏上面会有导航栏。
        [self.navigationController setNavigationBarHidden:YES animated:animated];
        //禁止本界面左滑返回
        self.navigationController.interactivePopGestureRecognizer.enabled = NO;
        NSNumber *orientationUnknown = [NSNumber numberWithInt:UIInterfaceOrientationUnknown];
        [[UIDevice currentDevice] setValue:orientationUnknown forKey:@"orientation"];
        NSNumber *orientationTarget = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft];
        [[UIDevice currentDevice] setValue:orientationTarget forKey:@"orientation"];
    
    }
    

    2、在离开界面的时候也要取消界面的横屏。

    - (void)viewWillDisappear:(BOOL)animated{
        [super viewWillDisappear:animated];
        //解除隐藏NavigationBar,否则横屏上面会有导航栏。
        [self.navigationController setNavigationBarHidden:NO animated:animated];
       //解除本界面左滑返回
        self.navigationController.interactivePopGestureRecognizer.enabled = YES;
    
        AppDelegate * appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
        appDelegate.allowRotation = NO;//关闭横屏仅允许竖屏
        
        //强制归正: 必须添加否则还是横屏。
        if ([[UIDevice currentDevice]   respondsToSelector:@selector(setOrientation:)]) {
            SEL selector =     NSSelectorFromString(@"setOrientation:");
            NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[UIDevice instanceMethodSignatureForSelector:selector]];
            [invocation setSelector:selector];
            [invocation setTarget:[UIDevice currentDevice]];
            int val =UIInterfaceOrientationPortrait;
            [invocation setArgument:&val atIndex:2];
            [invocation invoke];
        }
    }
    

    3、还有另外一种方式
    3.1在AppDelegate.m中设置:

    @property(nonatomic,assign) BOOL allowRotation;
    
    - (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window{
        
        if (self.allowRotation) {  
            return UIInterfaceOrientationMaskLandscapeLeft;
        }
        
        return UIInterfaceOrientationMaskPortrait;
    }
    
    

    3.2 在需要的类中设置

        AppDelegate * appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
        appDelegate.allowRotation = YES;//(以上2行代码,可以理解为打开横屏开关)
    

    离开的时候:

        AppDelegate * appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
        appDelegate.allowRotation = NO;//(以上2行代码,可以理解为打开横屏开关)
    

    五、浸入式编程(自定义透明导航栏)
    主要思想是隐藏导航栏,然后自定义一个View,然后在View上面添加各种控件并添加相应的操作。

    - (void)setupMyNav{
        float titleHeight = 0;
        float xheight = 22;
    
        self.myNaviView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, ZHWidth, titleHeight)];
        self.myNaviView.backgroundColor = [UIColor whiteColor];
        
        self.myNaviView.alpha = 0;
        
        [self.view addSubview:self.myNaviView];
        [self.view bringSubviewToFront:self.myNaviView];
        
        
        UIView *view = [[UIView alloc] init];
        view.frame = CGRectMake(10,28,261,29);
        
        
        UIView *lineView = [[UIView alloc]initWithFrame:CGRectMake(0, titleHeight-0.5, ZHWidth, 0.5)];
        lineView.backgroundColor = [UIColor grayColor];
        [self.myNaviView addSubview:lineView];
        
        
        UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
        //    button.size = CGSizeMake(50, 30);
        button.frame = CGRectMake(16, xheight, 90, 40);
        [button setImage:[UIImage imageNamed:@"left_search.png"] forState:UIControlStateNormal];
        
        // 让按钮内部的所有内容左对齐
        button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
        // 让按钮的内容往左边偏移10
        //    button.contentEdgeInsets = UIEdgeInsetsMake(0, -15, 0, 0);
        
        [button addTarget:self action:@selector(moveToSearchView) forControlEvents:UIControlEventTouchUpInside];
        [self.myNaviView addSubview:button];
        
        UILabel *titleLabel = [[UILabel alloc]initWithFrame:CGRectMake((ZHWidth-80)/2, xheight, 80, 40)];
        titleLabel.text = @"推荐";
        titleLabel.textAlignment = NSTextAlignmentCenter;
        titleLabel.font = [UIFont systemFontOfSize:20];
        [self.myNaviView addSubview:titleLabel];
        
        [self setUpRightBarItem];
    }
    

    六、用到的动画
    1、音频播放的动画。

    - (void)setUpRightBarItem{
        UIImage *image1 = [UIImage imageNamed:@"cm2_list_icn_loading1"];
        UIImage *image2 = [UIImage imageNamed:@"cm2_list_icn_loading2"];
        UIImage *image3 = [UIImage imageNamed:@"cm2_list_icn_loading3"];
        UIImage *image4 = [UIImage imageNamed:@"cm2_list_icn_loading4"];
        
        NSArray *array = @[image1,image2,image3,image4,image3,image2];
        float high = 0;
        if ([[UIScreen mainScreen] bounds].size.height >= 812.0f) {
            high = 5;
        }
        self.imageView = [[UIImageView alloc]initWithFrame:CGRectMake(ZHWidth-35, 25+high, 30, 30)];
        self.imageView.userInteractionEnabled = YES;
        //先设置一个固定的图片
        self.imageView.image =[UIImage imageNamed:@"cm2_list_icn_loading1"];
        [self.myNaviView  addSubview:self.imageView];
        
        
        // 创建装图片的数组
        self.imageView.animationImages = array; // 装图片的数组(需要做动画的图片数组)
        self.imageView.animationDuration = 1; // 动画时间
        self.imageView.animationRepeatCount = 0; // 重复次数 0 表示重复
        [self.imageView stopAnimating];
        
        
        //添加手势进行控制,用来跳转界面。
        UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(storyPlayView)];
        [self.imageView addGestureRecognizer:tap];
    }
    
    - (void)startBarAnimating{    
        [self.imageView startAnimating];
    }
    
    - (void)stopBarAnimating{
        [self.imageView stopAnimating];    
    }
    

    2、碟片旋转的动画。

    - (void)beginRotation
    {
        [self.iconImageView.layer removeAnimationForKey:@"rotation"];
        CABasicAnimation *animation = [[CABasicAnimation alloc] init];
        animation.fromValue = @(0);
        animation.toValue = @(M_PI * 2);
        //旋转的时间
        animation.duration = 30;
        //绕着Z轴旋转
        animation.keyPath = @"transform.rotation.z";
        animation.repeatCount = NSIntegerMax;
        animation.removedOnCompletion = NO;
        [self.iconImageView.layer addAnimation:animation forKey:@"rotation"];
    }
    

    3、页面反转的动画。
    3.1 立方体旋转

           AudioBookPlayViewController *vc = [AudioBookPlayViewController allocController];
                vc.model = pkgModel;
                [AudioBookPkgModel setPkg:pkgModel];
                CATransition* transition = [CATransition animation];
                transition.duration = 0.5f;
                transition.type = @"cube";
                transition.subtype = kCATransitionFromRight;
                [self.navigationController.view.layer addAnimation:transition forKey:kCATransition];
                [self.navigationController pushViewController:vc animated:YES];
    

    3.2 优秀的第三方页面翻转VCTransitionsLibrary
    丰富的动画第三方VCTransitionsLibrary

    七、自定义弹框
    这里说以下两点:
    1、在init的时候会调用layoutSubviews方法,可以在此设置UI。
    2、设置抖动动画,以及手势移除。
    初始化的时候

    
    界面下落到底部,然后再移除出父视图。
    - (void)removeView{
        [UIView animateWithDuration:0.25 animations:^{
            [self.whiteView setFrame:CGRectMake((Screen_Width-300)/2, Screen_Height, 300, 200)];
        } completion:^(BOOL finished) {
            [self.backView removeFromSuperview];
            [self removeFromSuperview];
        }];
    }
    

    八、Xib布局界面(真的很便捷,一般界面推荐使用哦)
    问题1:
    主要是主界面的布局,我们使用scrollview添加到界面中,然后在scrollview上添加各种布局,这时候你会发先会报错,说适配有问题。
    原因:这是因为scrollview没填充contentSize导致的,所以我们需要手动添加一个UIView来实现这个功能,让view填充整个界面,这时还是会报适配的错误,我们需要再选中view和scrollview,然后设置等宽登高,这样就解决了适配错误。
    问题2:
    之后在view上添加各种控件,添加完毕之后,发现无法滑动。
    原因:需要在scrollview设置滑动的方向,我们选择vertical。
    问题3:
    即使设置完成之后,我们还是无法滑动,所以我们需要手动添加代码设置,才能实现滑动。
    由于xib的延迟加载,我们需要在滞后一点才能加载,不能放到viewDidLoad中哦。

    -(void) viewDidAppear:(BOOL)animated{    
        self.scrollview.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 1024);    
        //Xib无法设置setContentSize,所以我们需要手动设置。
        [self.scrollview setContentSize:CGSizeMake(320, 1400)];    
    }
    

    九、存储、解归档
    1、存储

    [NSUserDefault setObject:@1 forKey:@"isMembership"];
     [NSUserDefault synchronize];
    

    NSUserDefault作为极为常见的一种简单存储方式,我们这类就不细说了,只要记住一点,存储必须是对象类型。
    2、解归档
    这里我们先说一下应用的场景,我们需要存储model对象,但是model不能直接存储在NSUserDefault中,必须进行归档处理,然后才能存储。
    NScoding 是一个协议,主要有下面两个方法
    -(id)initWithCoder:(NSCoder *)coder;//从coder中读取数据,保存到相应的变量中,即反序列化数据
    -(void)encodeWithCoder:(NSCoder *)coder;// 读取实例变量,并把这些数据写到coder中去。序列化数据
    NSCoder 是一个抽象类,抽象类不能被实例话,只能提供一些想让子类继承的方法。
    NSKeyedUnarchiver 从二进制流读取对象。
    NSKeyedArchiver 把对象写到二进制流中去。

    2.1、解归档必须实现coding协议,所以我们必须先在model中添加NSCoding设置。

    @interface AudioBookPkgModel : JSONModel<NSCoding>
    

    2.2、在.m文件中成对实现以下两个方法

    //告诉系统归档的属性是那些
    - (void)encodeWithCoder:(NSCoder *)aCoder{
        [aCoder encodeObject:self.pkgImg forKey:@"pkgImg"];
        [aCoder encodeObject:self.bookSubtitle forKey:@"bookSubtitle"];
    
        [aCoder encodeObject:self.pkgType forKey:@"pkgType"];
        [aCoder encodeObject:self.name forKey:@"name"];
        [aCoder encodeObject:self.nameEng forKey:@"nameEng"];
    }
    
    //告诉系统接档的属性是那些
    - (id)initWithCoder:(NSCoder *)aDecoder{
        if (self = [super init]) {
            self.pkgImg = [aDecoder decodeObjectForKey:@"pkgImg"];
            self.bookSubtitle = [aDecoder decodeObjectForKey:@"bookSubtitle"];
            self.pkgType = [aDecoder decodeObjectForKey:@"pkgType"];
            self.name = [aDecoder decodeObjectForKey:@"name"];
    
            self.nameEng = [aDecoder decodeObjectForKey:@"nameEng"];
    }
    
    

    2.3、归档存储 (archiver :压缩存储 )

       NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self.model];
        [NSUserDefault setObject:data forKey:@"oneStudent"];
        [NSUserDefault synchronize];
    

    2.4、解档

        NSData *data1 = [NSUserDefault objectForKey:@"oneStudent"];
        AudioBookPkgModel *model = [NSKeyedUnarchiver unarchiveObjectWithData:data1];
    

    十、数据的传递
    数据传递是我们开发过程中常用的功能,下面我们简要的介绍下项目用到的数据传递的方法。
    1、代理
    1.1 代理应用的场景是监控持续性的连续操作,比如TableView连续拖动的代理。

    @protocol TopicCollectionViewCell3Delegate <NSObject>
    //设置代理用于传递相应的数据
    - (void)TopBackAnswer:(NSMutableArray *)dataArr;
    @end
    
    @property (nonatomic,weak) id<TopicCollectionViewCell3Delegate> delegate;
    

    1.2 在VC中设置

    #pragma mark Top3的代理,用户判断返回的数据。 
    - (void)TopBackAnswer:(NSMutableArray *)dataArr{
        
    }
    

    2、block
    2.1 在.h中设置block,注意要用copy,思考下为什么要用copy?

    @property (copy,nonatomic) void (^moreActionBlock)(long tag , int rightIndex,CGPoint CGPointMake);
    

    2.2 在.m中,调用block传值。

    - (IBAction)buttonB:(id)sender {
        UIButton *but = sender;
        if (self.moreActionBlock) {
            CGPoint point = CGPointMake(but.frame.origin.x+85, but.frame.origin.y+18);
            self.moreActionBlock(but.tag,2,point);
        }
    }
    

    2.3 在VC中接收block的传值.

     topCell.moreActionBlock = ^(long tag, int rightIndex, CGPoint CGPointMake) {
                self.startPoint = CGPointMake;
                self.tagInfo = tag;//标记tag值。          
            };
    

    3、通知
    在A页面中:

        NSDictionary *dataDic = [NSDictionary dictionaryWithObject:@1 forKey:@"info"];
        [[NSNotificationCenter defaultCenter] postNotificationName:@"infoNotification" object:nil userInfo:dataDic];
    

    在B页面中:

    
    - (void)viewDidLoad {
        [super viewDidLoad];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receiveNotification:) name:@"infoNotification" object:nil];
    }
     
    -(void)receiveNotification:(NSNotification *)infoNotification {
        NSDictionary *dic = [infoNotification userInfo];
        NSString *str = [dic objectForKey:@"info"];
    }
    

    4、属性传递
    属性的数据传递主要用于不同界面的传值,比如A界面请求的数据model要传递到B界面,我们就需要在B界面设置全局的model,用于接收A界面的数据,B.model = AModel;就像这样。
    5、存储
    存储在上面已经介绍过了,这里就不再细说了,主要用于用户的状态存储、对象的存储等。

    十一、GCD的应用
    在推荐页面中,我们设置了五个板块,然后需要有五个请求,且这五个数据都是按照顺序加载的,由于网络请求的异步性,我们怎么才能让数据按照顺序展示呢?这里就用到GCD处理多线程的同步操作,让子线程全部完成之后,我们再统一处理数据。

    dispatch_group_enter:通知group,下面的任务马上要放到group中执行了。
    dispatch_group_leave:通知group,任务完成了,该任务要从group中移除了。
    dispatch_group_notify:所有的子线程完成网络请求之后,在此处理所有的数据。

     dispatch_group_t group = dispatch_group_create();
    
        dispatch_group_enter(group);
        dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    
            //获取全部绘本的内容
            [AudioBookVM pictureBookHeader:^(BOOL isSucceed, NSString *message, id result) {
                self.arrDic  = result;
            
                dispatch_group_leave(group);
    
            }];
    
        });
        
        
        // 19、免费故事接口
        dispatch_group_enter(group);
        dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [AudioBookVM queryAudioBookPkgByFreeConditionCallback:^(BOOL isSucceed, NSString *message, id result) {
                NSDictionary *dic = result;        
                dispatch_group_leave(group);
            }];
        });
        
        // 20、精品推荐&&最新上线  "tag":"NEWPKG,BEST",
        dispatch_group_enter(group);
        dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [AudioBookVM queryAudioBookPkgFindAllCallback:^(BOOL isSucceed, NSString *message, id result) {
                //都要转换成[DataListModel class]
                NSArray *arr = result;
                patch_group_leave(group);
            }];
        });
        
    
    
        dispatch_group_notify(group, dispatch_get_main_queue(), ^{
                [self.allCollection reloadData];
          
        });
    
    

    十一、TableView或者CollectionView下拉顶部图片放大

    一开始我的思路还固定在区头放大,但事实并非如此,我们只需要开辟滚动区间,在区间里面放上图片,然后再处理滚动即可,代码如下:
    1、首先初始化tableView,然后用contentInset增加表的滚动区域,再设置UIImageView放到表上。

     self.tableView = [[UITableView alloc] initWithFrame:[UIScreen mainScreen].bounds style:UITableViewStylePlain];
        [self.view addSubview:_tableView];
        _tableView.delegate = self;
        _tableView.dataSource = self;
        //上左下右  设置向上偏移  tableview向下偏移了200个单位   contentInset:增加_tableView的滚动区域
        _tableView.contentInset = UIEdgeInsetsMake(200,0, 0, 0);
        
        _tableView.showsHorizontalScrollIndicator = NO;
        _tableView.showsVerticalScrollIndicator = NO;
    
        _topImageView = [[UIImageView alloc] init];
        _topImageView.frame = CGRectMake(0, -200, [UIScreen mainScreen].bounds.size.width, 200);
        _topImageView.contentMode = UIViewContentModeScaleAspectFill;
        _topImageView.image = [UIImage imageNamed:@"APP icon.png"];
        _topImageView.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleWidth;
        _topImageView.clipsToBounds = YES;
        _topImageView.tag = 101;
        [_tableView addSubview:_topImageView];
    

    2、代理监控表的滑动,改变Frame。

    -(void)scrollViewDidScroll:(UIScrollView *)scrollView
    {
        CGPoint point = scrollView.contentOffset;
        if (point.y < -200) {
            CGRect rect = [self.tableView viewWithTag:101].frame;
            rect.origin.y = point.y;
            rect.size.height = -point.y;
            [self.tableView viewWithTag:101].frame = rect;
        }
    }
    

    十一、编程思想MVC&MVVM

    相关文章

      网友评论

          本文标题:项目的编程思想以及亮点

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