项目的编程思想以及亮点

2019-04-19  本文已影响0人  woniu

今天系统的总结下项目中遇到的问题以及比较好的点,也有利于以后问题的避免和解决。
一、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

上一篇下一篇

猜你喜欢

热点阅读