iOS开发中视图的下拉放大和上拉模糊的效果实现
把"秘密"的cell效果整体视图都放到scrollview中,基本是和secret app 一模一样的效果了.
代码如下:(模糊效果的类就不写了,大家可以搜"uiimage+imageeffects",还要导入accelerate.framework)
1.mtsecretappeffect.h
#import <foundation/foundation.h>
@interface mtsecretappeffect : nsobject
/**
* 创建整体的scrollview,把headscrollview和tableview全部加载在上面,靠它来上下滑动,其余的滑动全部禁止
*
* @return mainscrollview
*/
- (uiscrollview *)createmainscrollview;
/**
* 创建headscrollview
*
* @return headscrollview
*/
- (uiscrollview *)createheadscrollview;
/**
* 创建头部的模糊view
*
* @param scrollview headscrollview
*
* @return blurimageview
*/
- (uiimageview *)createblurimageviewofview:(uiscrollview *)scrollview;
/**
* 在- (void)scrollviewdidscroll:(uiscrollview *)scrollview 中调用的方法
*
* @param scrollview
* @param mainscrollview
* @param tableview
* @param headscrollview
* @param blurimageview
*/
- (void)scrolldidscrollview:(uiscrollview *)scrollview withmainscrollview:(uiscrollview *)mainscrollview withtableview:(uitableview *)tableview withheadscrollview:(uiscrollview *)headscrollview withblurimageview:(uiimageview *)blurimageview;
@end
2.mtsecretappeffect.m
#import "mtsecretappeffect.h"
#import "uiimage+imageeffects.h"
#import <quartzcore/quartzcore.h>
#define header_height 200.0f
#define header_init_frame cgrectmake(0, 0, 320, header_height)
const cgfloat kbarheight = 50.0f;
const cgfloat kbackgroundparallexfactor = 0.5f;
const cgfloat kblurfadeinfactor = 0.015f;
@implementation mtsecretappeffect
// 欠缺:调用者设置代理
- (uiscrollview *)createmainscrollview{
// 和self.view同大小的底部scrollview
uiscrollview *mainscrollview = [[uiscrollview alloc] initwithframe:[uiapplication sharedapplication].keywindow.frame];
mainscrollview.bounces = yes;
mainscrollview.alwaysbouncevertical = yes;
mainscrollview.contentsize = cgsizezero;
mainscrollview.showsverticalscrollindicator = yes;
mainscrollview.scrollindicatorinsets = uiedgeinsetsmake(50.0f, 0, 0, 0);
return mainscrollview;
}
- (uiscrollview *)createheadscrollview{
uiscrollview *headscrollview = [[uiscrollview alloc] initwithframe:header_init_frame];
headscrollview.scrollenabled = no;
headscrollview.contentsize = cgsizemake(320, 1000);
return headscrollview;
}
- (uiimageview *)createblurimageviewofview:(uiscrollview *)scrollview{
uigraphicsbeginimagecontextwithoptions(scrollview.bounds.size, scrollview.opaque, 0.0);
[scrollview.layer renderincontext:uigraphicsgetcurrentcontext()];
uiimage *img = uigraphicsgetimagefromcurrentimagecontext();
uigraphicsendimagecontext();
uiimageview *blurimageview = [[uiimageview alloc] initwithframe:cgrectmake(0, 0, 320, header_height)];
blurimageview.image = [img applyblurwithradius:12 tintcolor:[uicolor colorwithwhite:0.8 alpha:0.4] saturationdeltafactor:1.8 maskimage:nil];
blurimageview.autoresizingmask = uiviewautoresizingflexiblewidth | uiviewautoresizingflexibleheight;
blurimageview.alpha = 0;
blurimageview.backgroundcolor = [uicolor clearcolor];
return blurimageview;
}
- (void)scrolldidscrollview:(uiscrollview *)scrollview withmainscrollview:(uiscrollview *)mainscrollview withtableview:(uitableview *)tableview withheadscrollview:(uiscrollview *)headscrollview withblurimageview:(uiimageview *)blurimageview{
cgfloat y = 0.0f;
cgrect rect = header_init_frame;
if (scrollview.contentoffset.y < 0.0f) {
// 下拉变大效果
y = fabs(min(0.0f, mainscrollview.contentoffset.y));
headscrollview.frame = cgrectmake(cgrectgetminx(rect) - y / 2.0f, cgrectgetminy(rect) - y, cgrectgetwidth(rect) + y, cgrectgetheight(rect) + y);
}
else {
y = mainscrollview.contentoffset.y;
blurimageview.alpha = min(1 , y * kblurfadeinfactor);
cgfloat backgroundscrollviewlimit = headscrollview.frame.size.height - kbarheight;
if (y > backgroundscrollviewlimit) {
headscrollview.frame = (cgrect) {.origin = {0, y - headscrollview.frame.size.height + kbarheight}, .size = {320, header_height}};
tableview.frame = (cgrect){.origin = {0, cgrectgetminy(headscrollview.frame) + cgrectgetheight(headscrollview.frame)}, .size = tableview.frame.size };
tableview.contentoffset = cgpointmake (0, y - backgroundscrollviewlimit);
cgfloat contentoffsety = -backgroundscrollviewlimit * kbackgroundparallexfactor;
[headscrollview setcontentoffset:(cgpoint){0,contentoffsety} animated:no];
}
else {
headscrollview.frame = rect;
tableview.frame = (cgrect){.origin = {0, cgrectgetminy(rect) + cgrectgetheight(rect)}, .size = tableview.frame.size };
[tableview setcontentoffset:(cgpoint){0,0} animated:no];
[headscrollview setcontentoffset:cgpointmake(0, -y * kbackgroundparallexfactor)animated:no];
}
}
}
@end
3.main.m
#import "rootviewcontroller.h"
#import "commentcell.h"
#import "mtsecretappeffect.h"
#define header_height 200.0f
@interface rootviewcontroller () <uiscrollviewdelegate, uitableviewdatasource, uitableviewdelegate>
@property (nonatomic,strong) mtsecretappeffect *secreteffect; // secretapp 效果对象
@property (nonatomic,strong) uiscrollview *mainscrollview; // 与view相同大小的scrollview
@property (nonatomic,strong) uiscrollview *headscrollview; //
@property (nonatomic,strong) uiimageview *blurimageview; //
@property (nonatomic,strong) uitableview *tableview; //
@end
@implementation rootviewcontroller
- (void)viewdidload
{
[super viewdidload];
// 0.创建secretapp effect 效果对象
self.secreteffect = [[mtsecretappeffect alloc] init];
// 1.主底部scrollview
self.mainscrollview = [self.secreteffect createmainscrollview];
self.mainscrollview.delegate = self;
self.view = self.mainscrollview;
// 2.head背景view
self.headscrollview = [self.secreteffect createheadscrollview];
// 3.背景图片视图
uiimageview *imageview = [[uiimageview alloc] initwithframe:cgrectmake(0, 0, 320, header_height)];
imageview.image = [uiimage imagenamed:@"secret.png"];
imageview.autoresizingmask = uiviewautoresizingflexiblewidth | uiviewautoresizingflexibleheight;
[self.headscrollview addsubview:imageview];
// 4.模糊视图
_blurimageview = [self.secreteffect createblurimageviewofview:self.headscrollview];
[self.headscrollview addsubview:_blurimageview];
// 5.tableview
self.tableview = [[uitableview alloc] initwithframe:cgrectmake(0, header_height, cgrectgetwidth(self.view.frame), cgrectgetheight(self.view.frame) - 50 ) style:uitableviewstyleplain];
self.tableview.scrollenabled = no;
self.tableview.delegate = self;
self.tableview.datasource = self;
self.tableview.tablefooterview = [[uiview alloc] initwithframe:cgrectzero];
self.tableview.separatorcolor = [uicolor clearcolor];
// 6.添加视图
[self.view addsubview:self.headscrollview];
[self.view addsubview:self.tableview];
// 7.设置一下
self.mainscrollview.contentsize = cgsizemake(320, self.tableview.contentsize.height + cgrectgetheight(self.headscrollview.frame));
}
- (void)scrollviewdidscroll:(uiscrollview *)scrollview {
// 8.调用方法
[self.secreteffect scrolldidscrollview:scrollview withmainscrollview:self.mainscrollview withtableview:self.tableview withheadscrollview:self.headscrollview withblurimageview:self.blurimageview];
}
#pragma mark - 隐藏状态栏
- (bool)prefersstatusbarhidden {
return yes;
}
#pragma mark - uitableview datasource
- (nsinteger)numberofsectionsintableview:(uitableview *)tableview {
return 1;
}
- (nsinteger)tableview:(uitableview *)tableview numberofrowsinsection:(nsinteger)section {
return 20;
}
- (cgfloat)tableview:(uitableview *)tableview heightforrowatindexpath:(nsindexpath *)indexpath {
return 40;
}
- (uitableviewcell *)tableview:(uitableview *)tableview cellforrowatindexpath:(nsindexpath *)indexpath {
commentcell *cell = [tableview dequeuereusablecellwithidentifier:[nsstring stringwithformat:@"cell %ld", indexpath.row]];
if (!cell) {
cell = [[commentcell alloc]initwithstyle:uitableviewcellstyledefault reuseidentifier:[nsstring stringwithformat:@"cell %ld", indexpath.row]];
}
cell.textlabel.text = [nsstring stringwithformat:@"section = %ld row = %ld",indexpath.section,indexpath.row];
return cell;
}
- (void)didreceivememorywarning
{
[super didreceivememorywarning];
// dispose of any resources that can be recreated.
}
@end
效果图:
pppppppppppppppppppppp1
它主要效果:下拉头部视图放大,上拉视图模糊而且到一定位置固定不动,其他cell可以继续上移.
封装的主要效果类:mtheadeffect.m(.h文件省略,很简单的)
#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;
voidvoid *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
voidvoid *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);
}
}