iOS开发之剖析"秘密"App内容页面效果(一)
近期在玩"秘密",发现点击主界面的Cell进去后的页面效果不错,就写了个Demo来演示下.
它主要效果:下拉头部视图放大,上拉视图模糊并且到一定位置固定不动,其它Cell能够继续上移.
@封装的主要效果类:MTHeadEffect.m(.h文件省略,非常easy的)
#import "MTHeadEffect.h" #import <QuartzCore/QuartzCore.h> #import <Accelerate/Accelerate.h> // 屏幕的物理宽度 #define ScreenWidth [UIScreen mainScreen].bounds.size.width #define HeadViewH 40 CGFloat const kImageOriginHight = 200.f; @implementation MTHeadEffect + (void)viewDidScroll:(UIScrollView *)tableView withHeadView:(UIImageView *)headView withBlur:(CGFloat)blur{ NSLog(@"y = %f",tableView.contentOffset.y); if (tableView.contentOffset.y > kImageOriginHight - HeadViewH) { headView.frame = CGRectMake(0, -(kImageOriginHight - HeadViewH), ScreenWidth, kImageOriginHight); [[UIApplication sharedApplication].keyWindow addSubview:headView]; }else if ((tableView.contentOffset.y < kImageOriginHight - HeadViewH) && tableView.contentOffset.y > 0){ blur = (tableView.contentOffset.y) / 500.0 + 0.45; headView.image = [[UIImage imageNamed:@"2"] boxblurImageWithBlur:blur]; headView.frame = CGRectMake(0, 0, ScreenWidth, kImageOriginHight); [tableView addSubview:headView]; }else if (tableView.contentOffset.y <= 0){ // 放大效果---x,y坐标的增量和宽度,高度的增量保持一致 CGFloat offset = -tableView.contentOffset.y; headView.frame = CGRectMake(-offset,-offset, ScreenWidth+ offset * 2, kImageOriginHight + offset); headView.image = [[UIImage imageNamed:@"2"] boxblurImageWithBlur:0.01]; } } @end @implementation UIImage (BlurEffect) // 为高斯模糊效果封装的一个类目 -(UIImage *)boxblurImageWithBlur:(CGFloat)blur { NSData *imageData = UIImageJPEGRepresentation(self, 1); // convert to jpeg UIImage* destImage = [UIImage imageWithData:imageData]; if (blur < 0.f || blur > 1.f) { blur = 0.5f; } int boxSize = (int)(blur * 40); boxSize = boxSize - (boxSize % 2) + 1; CGImageRef img = destImage.CGImage; vImage_Buffer inBuffer, outBuffer; vImage_Error error; void *pixelBuffer; //create vImage_Buffer with data from CGImageRef CGDataProviderRef inProvider = CGImageGetDataProvider(img); CFDataRef inBitmapData = CGDataProviderCopyData(inProvider); inBuffer.width = CGImageGetWidth(img); inBuffer.height = CGImageGetHeight(img); inBuffer.rowBytes = CGImageGetBytesPerRow(img); inBuffer.data = (void*)CFDataGetBytePtr(inBitmapData); //create vImage_Buffer for output pixelBuffer = malloc(CGImageGetBytesPerRow(img) * CGImageGetHeight(img)); if(pixelBuffer == NULL) NSLog(@"No pixelbuffer"); outBuffer.data = pixelBuffer; outBuffer.width = CGImageGetWidth(img); outBuffer.height = CGImageGetHeight(img); outBuffer.rowBytes = CGImageGetBytesPerRow(img); // Create a third buffer for intermediate processing void *pixelBuffer2 = malloc(CGImageGetBytesPerRow(img) * CGImageGetHeight(img)); vImage_Buffer outBuffer2; outBuffer2.data = pixelBuffer2; outBuffer2.width = CGImageGetWidth(img); outBuffer2.height = CGImageGetHeight(img); outBuffer2.rowBytes = CGImageGetBytesPerRow(img); //perform convolution error = vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer2, NULL, 0, 0, boxSize, boxSize, NULL, kvImageEdgeExtend); if (error) { NSLog(@"error from convolution %ld", error); } error = vImageBoxConvolve_ARGB8888(&outBuffer2, &inBuffer, NULL, 0, 0, boxSize, boxSize, NULL, kvImageEdgeExtend); if (error) { NSLog(@"error from convolution %ld", error); } error = vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer, NULL, 0, 0, boxSize, boxSize, NULL, kvImageEdgeExtend); if (error) { NSLog(@"error from convolution %ld", error); } CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); CGContextRef ctx = CGBitmapContextCreate(outBuffer.data, outBuffer.width, outBuffer.height, 8, outBuffer.rowBytes, colorSpace, (CGBitmapInfo)kCGImageAlphaNoneSkipLast); CGImageRef imageRef = CGBitmapContextCreateImage (ctx); UIImage *returnImage = [UIImage imageWithCGImage:imageRef]; //clean up CGContextRelease(ctx); CGColorSpaceRelease(colorSpace); free(pixelBuffer); free(pixelBuffer2); CFRelease(inBitmapData); CGImageRelease(imageRef); return returnImage; } @end
@main.m
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. // tableView self.testTableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 320, 568) style:UITableViewStylePlain]; self.testTableView.delegate = self; self.testTableView.dataSource = self; [self.view addSubview:_testTableView]; /** * 隐藏状态栏效果 * 1.系统提供了2种动画,一种是偏移,一种是渐隐 * 2.在plist文件里将”View controller-based status bar appearance” 设置为 “No” */ [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationNone]; // headView不作为tableHeadView,而是覆盖在第一个Cell上 self.headView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 200)]; self.headView.image = [[UIImage imageNamed:@"2"] boxblurImageWithBlur:0.01]; self.headView.contentMode = UIViewContentModeScaleAspectFill; // 图片展示全高度 self.headView.clipsToBounds = YES; [self.testTableView addSubview:self.headView]; } #pragma mark - scroll delegate 头部视图效果方法 -(void)scrollViewDidScroll:(UIScrollView *)scrollView { [MTHeadEffect viewDidScroll:scrollView withHeadView:self.headView withBlur:0.01]; } - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{ return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ return 25; } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ if (indexPath.row == 0) { return 200; } return 40; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ static NSString *cellIdentf = @"cell"; UITableViewCell *cell = [tableView dequeueReusableHeaderFooterViewWithIdentifier:cellIdentf]; if (!cell) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentf]; } cell.textLabel.text = [NSString stringWithFormat:@"section = %ld row = %ld",indexPath.section,indexPath.row]; return cell; }
@效果图:额,不会制作gif动图,所以不太好演示,反正关键代码已经给出,大家能够自己去尝试.
@第三方FXBlurView做法的关键代码:
- (void)createBlurView{ self.blurView = [[FXBlurView alloc] initWithFrame:CGRectMake(0, 0, ScreenWidth, kOriginHight)]; self.blurView.tintColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:1]; self.blurView.blurRadius = 1.0; self.blurView.dynamic = YES; self.blurView.alpha = 0.0; self.blurView.contentMode = UIViewContentModeBottom; } #pragma mark - scroll delegate 头部视图效果方法 -(void)scrollViewDidScroll:(UIScrollView *)scrollView { if (scrollView.contentOffset.y > 0) { self.blurView.alpha = 1.0; self.blurView.blurRadius = scrollView.contentOffset.y / 4.0; } if (scrollView.contentOffset.y == 0) { self.blurView.alpha = 0.0; } if (scrollView.contentOffset.y < 0) { CGFloat offset = - scrollView.contentOffset.y; self.blurView.alpha = 0.0; NSArray *indexPathArray = [self.testTableView indexPathsForVisibleRows]; HMTBlurTableViewCell *blurCell = (HMTBlurTableViewCell *)[self.testTableView cellForRowAtIndexPath:[indexPathArray objectAtIndex:0]]; blurCell.blurImageView.frame = CGRectMake(-offset, -offset, ScreenWidth + offset * 2, kOriginHight + offset); } }