iOS - 滤镜的初步实现

图片.png

一、相关属性声明(有可能有遗漏的,自行添加)

    /// 滤镜相关
    @property (nonatomic,strong)GPUImageView * gpuView;//预览视频内容
    @property (nonatomic,strong)GPUImageMovie * gpuMovie;//接管视频数据
    @property (nonatomic,strong)UIScrollView * EditView;//滤镜选择视图
    @property (nonatomic,strong)NSArray * GPUImgArr;//存放滤镜数组
    @property (nonatomic,strong)GPUImageOutput<GPUImageInput> * pixellateFilter;//视频滤镜
    @property (nonatomic,strong)GPUImageMovieWriter * movieWriter;//视频处理输出
    
    @property (nonatomic,copy)NSString * fileSavePath;//视频合成后存储路径
    
    @property (nonatomic,assign)NSTimer * timer;//设置计时器,因为重复合成同一个滤镜时间会很长超时后重新创建
    @property (nonatomic,assign)int timeNum;//记时时间
    @property (nonatomic,strong)UIView * hudView;//加载框
    
    @property (nonatomic , assign) NSInteger index;// 记录选择滤镜下标

** 二、相关方法实现**

- (void)viewDidLoad {
    [super viewDidLoad];

    self.view.backgroundColor = HEXCOLOR(0x333333);
    
    self.index = 0;
    
    [self createPreviewView];
    
    // 封面视图
    self.firstIma = [MSUCameraPhotoVc getImageAtSomeFrame:self.videoUrl videoTime:1];
}

#pragma mark - 创建视图
// 视频播放视图
- (void)createPreviewView{
    self.gpuView = [[GPUImageView alloc]initWithFrame:CGRectMake(0, 0, WIDTH, HEIGHT-150)];
    
    CGSize videoSize = [MSUCameraPhotoVc getVideoSizeWithURL:_videoUrl];
    if (videoSize.width < videoSize.height || [self.statusStr isEqualToString:@"竖屏"]) {
        //设置展示页面的旋转
        [_gpuView setInputRotation:kGPUImageRotateRight atIndex:0];
        _gpuView.fillMode = kGPUImageFillModePreserveAspectRatioAndFill;
    }

    [self.view addSubview:_gpuView];
    
    self.gpuMovie = [[GPUImageMovie alloc]initWithURL:self.videoUrl];
    _gpuMovie.shouldRepeat = YES;//循环
    _gpuMovie.playAtActualSpeed = YES;
    [_gpuMovie addTarget:_gpuView];
    [_gpuMovie startProcessing];

    [self createFilterView];

}

- (void)createFilterView{
    UIButton *closeBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    closeBtn.frame = CGRectMake(14, 20, 20, 29);
//    closeBtn.backgroundColor = [UIColor whiteColor];
    [closeBtn setImage:[MSUPathTools showImageWithContentOfFileByName:@"record-close"] forState:UIControlStateNormal];
    closeBtn.adjustsImageWhenHighlighted = NO;
    [closeBtn addTarget:self action:@selector(closeBtnClick:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:closeBtn];
    
    UIButton *seleBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    seleBtn.frame = CGRectMake(0, HEIGHT-150, 80, 150);
    seleBtn.backgroundColor = [UIColor whiteColor];
    [seleBtn setImage:[MSUPathTools showImageWithContentOfFileByName:@"WechatIMG896"] forState:UIControlStateNormal];
    seleBtn.adjustsImageWhenHighlighted = NO;
    [seleBtn addTarget:self action:@selector(saveBtnClick:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:seleBtn];
    
    self.EditView = [[UIScrollView alloc]initWithFrame:CGRectMake(80, HEIGHT-150, WIDTH, 150)];
    _EditView.backgroundColor = [UIColor whiteColor];
    _EditView.showsVerticalScrollIndicator = NO;
    _EditView.showsHorizontalScrollIndicator = NO;
    AVURLAsset * myAsset = [AVURLAsset assetWithURL:_videoUrl];
    
    //初始化AVAssetImageGenerator
    AVAssetImageGenerator * imageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:myAsset];
    imageGenerator.appliesPreferredTrackTransform = YES;
    
    UIImage *inputImage = [[UIImage alloc]init];
    
    // First image
    //创建第一张预览图
    CGImageRef halfWayImage = [imageGenerator copyCGImageAtTime:kCMTimeZero actualTime:nil error:nil];
    if (halfWayImage != NULL) {
        inputImage = [[UIImage alloc] initWithCGImage:halfWayImage];
    }

    self.GPUImgArr = [self CreateGPUArr];
    
    for (int i = 0; i<_GPUImgArr.count; i++) {
        UIButton * effectImg = [UIButton buttonWithType:UIButtonTypeCustom];
        effectImg.frame = CGRectMake(16+i*(75+16), 22.5, 75 ,75);
        [effectImg setImage:inputImage forState:UIControlStateNormal];
        
        if (i>0) {
            
            GPUImageOutput<GPUImageInput> * disFilter = (GPUImageOutput<GPUImageInput> *)[_GPUImgArr[i] objectForKey:@"filter"];
            
            //设置要渲染的区域
            [disFilter useNextFrameForImageCapture];
            //获取数据源
            GPUImagePicture *stillImageSource = [[GPUImagePicture alloc]initWithImage:inputImage];
            //添加上滤镜
            [stillImageSource addTarget:disFilter];
            //开始渲染
            [stillImageSource processImage];
            //获取渲染后的图片
            UIImage *newImage = [disFilter imageFromCurrentFramebuffer];
            
            
            [effectImg setImage:newImage forState:UIControlStateNormal];
            
        }
        
        effectImg.layer.cornerRadius = 10;
        effectImg.layer.masksToBounds = YES;
        effectImg.tag = 1000+i;
        
        [effectImg addTarget:self action:@selector(effectImgClick:) forControlEvents:UIControlEventTouchUpInside];
        
//        if (i == 0) {
//            effectImg.layer.borderWidth = 2;
//            effectImg.layer.borderColor = HEXCOLOR(0xf49818).CGColor;
//        }
        
        UILabel * effectName = [[UILabel alloc]initWithFrame:CGRectMake(effectImg.frame.origin.x, CGRectGetMaxY(effectImg.frame)+10, effectImg.frame.size.width, 20)];
        effectName.textColor = HEXCOLOR(0x757575);
        effectName.textAlignment = NSTextAlignmentCenter;
        effectName.font = [UIFont systemFontOfSize:14];
        effectName.text = _GPUImgArr[i][@"name"];
        
        [_EditView addSubview:effectImg];
        [_EditView addSubview:effectName];
        
        _EditView.contentSize = CGSizeMake(_GPUImgArr.count*(75+16)+16+80, _EditView.frame.size.height);
    }
    
    [self.view addSubview:_EditView];
}

#pragma mark ---------------------------选择滤镜----------------------------

-(void)effectImgClick:(UIButton *)button{
    self.index++;
    
    for (int i = 0 ; i<_GPUImgArr.count ;i++) {
        UIButton *btn = [_EditView viewWithTag:1000+i];
        btn.layer.borderWidth = 0;
        btn.userInteractionEnabled = YES;
    }
    button.userInteractionEnabled = NO;
    button.layer.borderWidth = 2;
    button.layer.borderColor = HEXCOLOR(0xf49818).CGColor;
    
    
    [_gpuMovie cancelProcessing];
    [_gpuMovie removeAllTargets];
    
    _gpuMovie = [[GPUImageMovie alloc]initWithURL:_videoUrl];
    CGSize videoSize = [MSUCameraPhotoVc getVideoSizeWithURL:_videoUrl];
    if (videoSize.width < videoSize.height || [self.statusStr isEqualToString:@"竖屏"]) {
        //设置展示页面的旋转
        [_gpuView setInputRotation:kGPUImageRotateRight atIndex:0];
    }
    
    if (button.tag == 1000) {
        _pixellateFilter = (GPUImageOutput<GPUImageInput> *)[_GPUImgArr[button.tag-1000] objectForKey:@"filter"];
        [_gpuMovie addTarget:_pixellateFilter];
        [_pixellateFilter addTarget:_gpuView];
//        _pixellateFilter = nil;
//        [_gpuMovie addTarget:_gpuView];
        
    }else{
        _pixellateFilter = (GPUImageOutput<GPUImageInput> *)[_GPUImgArr[button.tag-1000] objectForKey:@"filter"];
        [_gpuMovie addTarget:_pixellateFilter];
        [_pixellateFilter addTarget:_gpuView];
    }
    
    [_gpuMovie startProcessing];
    
}

#pragma mark ------------------------滤镜数组-----------------------
-(NSArray *)CreateGPUArr{
    NSMutableArray * arr = [[NSMutableArray alloc]init];
    
    GPUImageOutput<GPUImageInput> * Filter0 = [[GPUImageFilter alloc] init];
    NSString * title0 = @"原图";
    NSDictionary * dic0 = [NSDictionary dictionaryWithObjectsAndKeys:Filter0,@"filter",title0,@"name", nil];
    [arr addObject:dic0];
    
    
    GPUImageOutput<GPUImageInput> * Filter5 = [[GPUImageGammaFilter alloc] init];
    [(GPUImageGammaFilter *)Filter5 setGamma:1.5];
    NSString * title5 = @"伽马线";
    NSDictionary * dic5 = [NSDictionary dictionaryWithObjectsAndKeys:Filter5,@"filter",title5,@"name", nil];
    [arr addObject:dic5];
    
    
    GPUImageOutput<GPUImageInput> * Filter6 = [[GPUImageColorInvertFilter alloc] init];
    NSString * title6 = @"反色";
    NSDictionary * dic6 = [NSDictionary dictionaryWithObjectsAndKeys:Filter6,@"filter",title6,@"name", nil];
    [arr addObject:dic6];
    
    GPUImageOutput<GPUImageInput> * Filter7 = [[GPUImageSepiaFilter alloc] init];
    NSString * title7 = @"褐色怀旧";
    NSDictionary * dic7 = [NSDictionary dictionaryWithObjectsAndKeys:Filter7,@"filter",title7,@"name", nil];
    [arr addObject:dic7];
    
    GPUImageOutput<GPUImageInput> * Filter8 = [[GPUImageGrayscaleFilter alloc] init];
    NSString * title8 = @"灰度";
    NSDictionary * dic8 = [NSDictionary dictionaryWithObjectsAndKeys:Filter8,@"filter",title8,@"name", nil];
    [arr addObject:dic8];
    
    GPUImageOutput<GPUImageInput> * Filter9 = [[GPUImageHistogramGenerator alloc] init];
    NSString * title9 = @"色彩直方图?";
    NSDictionary * dic9 = [NSDictionary dictionaryWithObjectsAndKeys:Filter9,@"filter",title9,@"name", nil];
    [arr addObject:dic9];
    
    
    GPUImageOutput<GPUImageInput> * Filter10 = [[GPUImageRGBFilter alloc] init];
    NSString * title10 = @"RGB";
    [(GPUImageRGBFilter *)Filter10 setRed:0.8];
    [(GPUImageRGBFilter *)Filter10 setGreen:0.3];
    [(GPUImageRGBFilter *)Filter10 setBlue:0.5];
    NSDictionary * dic10 = [NSDictionary dictionaryWithObjectsAndKeys:Filter10,@"filter",title10,@"name", nil];
    [arr addObject:dic10];
    
    GPUImageOutput<GPUImageInput> * Filter11 = [[GPUImageMonochromeFilter alloc] init];
    [(GPUImageMonochromeFilter *)Filter11 setColorRed:0.3 green:0.5 blue:0.8];
    NSString * title11 = @"单色";
    NSDictionary * dic11 = [NSDictionary dictionaryWithObjectsAndKeys:Filter11,@"filter",title11,@"name", nil];
    [arr addObject:dic11];
    
    GPUImageOutput<GPUImageInput> * Filter12 = [[GPUImageBoxBlurFilter alloc] init];
    //    [(GPUImageMonochromeFilter *)Filter11 setColorRed:0.3 green:0.5 blue:0.8];
    NSString * title12 = @"单色";
    NSDictionary * dic12 = [NSDictionary dictionaryWithObjectsAndKeys:Filter12,@"filter",title12,@"name", nil];
    [arr addObject:dic12];
    
    GPUImageOutput<GPUImageInput> * Filter13 = [[GPUImageSobelEdgeDetectionFilter alloc] init];
    //    [(GPUImageSobelEdgeDetectionFilter *)Filter13 ];
    NSString * title13 = @"漫画反色";
    NSDictionary * dic13 = [NSDictionary dictionaryWithObjectsAndKeys:Filter13,@"filter",title13,@"name", nil];
    [arr addObject:dic13];
    
    GPUImageOutput<GPUImageInput> * Filter14 = [[GPUImageXYDerivativeFilter alloc] init];
    //    [(GPUImageSobelEdgeDetectionFilter *)Filter13 ];
    NSString * title14 = @"蓝绿边缘";
    NSDictionary * dic14 = [NSDictionary dictionaryWithObjectsAndKeys:Filter14,@"filter",title14,@"name", nil];
    [arr addObject:dic14];
    
    
    GPUImageOutput<GPUImageInput> * Filter15 = [[GPUImageSketchFilter alloc] init];
    //    [(GPUImageSobelEdgeDetectionFilter *)Filter13 ];
    NSString * title15 = @"素描";
    NSDictionary * dic15 = [NSDictionary dictionaryWithObjectsAndKeys:Filter15,@"filter",title15,@"name", nil];
    [arr addObject:dic15];
    
    GPUImageOutput<GPUImageInput> * Filter16 = [[GPUImageSmoothToonFilter alloc] init];
    //    [(GPUImageSobelEdgeDetectionFilter *)Filter13 ];
    NSString * title16 = @"卡通";
    NSDictionary * dic16 = [NSDictionary dictionaryWithObjectsAndKeys:Filter16,@"filter",title16,@"name", nil];
    [arr addObject:dic16];
    
    
    GPUImageOutput<GPUImageInput> * Filter17 = [[GPUImageColorPackingFilter alloc] init];
    //    [(GPUImageSobelEdgeDetectionFilter *)Filter13 ];
    NSString * title17 = @"监控";
    NSDictionary * dic17 = [NSDictionary dictionaryWithObjectsAndKeys:Filter17,@"filter",title17,@"name", nil];
    [arr addObject:dic17];
    
    
    return arr;
}

#pragma mark -----------------------------视频存放位置------------------------
- (NSString *)fileSavePath{
    
    NSFileManager* fileManager = [NSFileManager defaultManager];
    
    NSString *pathDocuments = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
    NSString *createPath = [NSString stringWithFormat:@"%@/myVidio/333.mp4", pathDocuments];//视频存放位置
    NSString *createPath2 = [NSString stringWithFormat:@"%@/myVidio", pathDocuments];//视频存放文件夹
    //判断视频文件是否存在,存在删除
    BOOL blHave=[[NSFileManager defaultManager] fileExistsAtPath:createPath];
    if (blHave) {
        BOOL blDele= [fileManager removeItemAtPath:createPath error:nil];
        if (!blDele) {
            [fileManager removeItemAtPath:createPath error:nil];
        }
    }
    //判断视频存放文件夹是否存在,不存在创建
    BOOL blHave1=[[NSFileManager defaultManager] fileExistsAtPath:createPath2];
    if (!blHave1) {
        [fileManager createDirectoryAtPath:createPath2 withIntermediateDirectories:YES attributes:nil error:nil];
    }
    
    _fileSavePath = createPath;
    
    
    NSLog(@"视频存放地址 fileSavePath = %@",_fileSavePath);
    
    return _fileSavePath;
}

#pragma amrk - 点击事件
- (void)closeBtnClick:(UIButton *)sender{
    [self.navigationController dismissViewControllerAnimated:NO completion:^{
        [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent;
    }];
}

- (void)saveBtnClick:(UIButton *)sender{
//    [self createHudView];
    
    if (self.index == 0) {
        [MSUHUD showFileWithString:@"请选择列表中的任一滤镜"];
    } else{
        [MSUHUD showStatusWithString:@"正在合成"];

        _timeNum = 0;
        _timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timeRun) userInfo:nil repeats:YES];
        
        
        NSURL *movieURL = [NSURL fileURLWithPath:self.fileSavePath];
        NSLog(@"movieURL %@",movieURL);
        
        _movieWriter = [[GPUImageMovieWriter alloc] initWithMovieURL:movieURL size:CGSizeMake(WIDTH, HEIGHT-150)];//视频存放路径及输出视频宽高
        
        [_pixellateFilter addTarget:_movieWriter];
        
        _movieWriter.shouldPassthroughAudio = YES;
        _movieWriter.encodingLiveVideo = YES;
        
        [_gpuMovie enableSynchronizedEncodingUsingMovieWriter:_movieWriter];
        [_movieWriter startRecording];
        
        
        __weak MSUFilterController * weakSelf = self;
        
        [_movieWriter setFailureBlock:^(NSError *error) {
            NSLog(@"合成失败 173:error = %@",error.description);
            
            dispatch_async(dispatch_get_main_queue(), ^{
                [MSUHUD showFileWithString:@"合成失败,请重新合成"];
                
                weakSelf.hudView.hidden = YES;
                
                [weakSelf.pixellateFilter removeTarget:weakSelf.movieWriter];
                //            [weakSelf.dic setObject:weakSelf.pixellateFilter forKey:@"filter"];
                [weakSelf.movieWriter finishRecording];
                
                [weakSelf.timer setFireDate:[NSDate distantFuture]];
                
            });
        }];
        
        [_movieWriter setCompletionBlock:^{
            NSLog(@"视频合成结束: 188 ");
            dispatch_async(dispatch_get_main_queue(), ^{
                [MSUHUD showFileWithString:@"合成成功"];
                
                //            [[NSFileManager defaultManager] removeItemAtPath:weakSelf.fileSavePath error:nil];//取消之后就删除,以免占用手机硬盘空间
                
                weakSelf.hudView.hidden = YES;
                
                [weakSelf.pixellateFilter removeTarget:weakSelf.movieWriter];
                //            [weakSelf.dic setObject:weakSelf.pixellateFilter forKey:@"filter"];
                [weakSelf.movieWriter finishRecording];
                
                [weakSelf.timer setFireDate:[NSDate distantFuture]];
                
                [weakSelf.timer invalidate];
                weakSelf.timer = nil;
                //            weakSelf.hidesBottomBarWhenPushed = YES;
                MSUEditController *edit = [[MSUEditController alloc] init];
                edit.videoUrl = weakSelf.videoUrl;
                edit.firstIma = weakSelf.firstIma;
                edit.videoInputUrl = movieURL;
                //            edit.videoPathUrl = weakSelf.videoPathUrl;
                [weakSelf.navigationController pushViewController:edit animated:YES];
                
            });
        }];
    }
}

-(void)createHudView{
    
    if (!_hudView) {
        _hudView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, WIDTH, HEIGHT)];
        _hudView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.6];
        
        
        UIView * huV = [[UIView alloc]initWithFrame:CGRectMake(WIDTH/2-50, HEIGHT/2-50, 100, 100)];
        huV.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.6];
        
        huV.layer.cornerRadius = 5;
        huV.clipsToBounds = YES;
        
        UIActivityIndicatorView * activityView = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
        
        
        activityView.frame = CGRectMake(0, 0,huV.frame.size.width, huV.frame.size.height);
        
        [activityView startAnimating];
        
        [huV addSubview:activityView];
        
        [_hudView addSubview:huV];
        
        
        [[[UIApplication sharedApplication] keyWindow] addSubview:_hudView];
        
    }else{
        
        _hudView.hidden = NO;
        
    }
    
}

#pragma mark -----------------------计时器--------------------------
-(void)timeRun{
    
    _timeNum += 1;
    
    if (_timeNum >= 5) {
        [MSUHUD showFileWithString:@"视频处理超时,请再试一次"];
        NSLog(@"视频处理超时");
        [_timer invalidate];
        _timer = nil;
        _hudView.hidden = YES;
        [self createPreviewView];
        
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,364评论 25 707
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,579评论 18 139
  • 苹果官方文档翻译 《Objective-C语言编程》(Programming with Objective-C) ...
    fever105阅读 25,568评论 19 130
  • 早上有点灵光,记下投资标的,互选,看好机制,然后去上班,匆忙之中赶到公司,一天的忙碌后,又和室友出去吃饭,玩游戏。...
    麻花可乐阅读 212评论 0 0
  • 最近看了《猎场》这部电视剧,因为前部分无厘头的剧情,所以让从一开始追剧的室友纷纷弃剧。而我,却追上了这部剧,原因...
    南风长晴阅读 201评论 0 0