欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

iOS开发中视图的下拉放大和上拉模糊的效果实现

程序员文章站 2022-04-12 10:49:50
把"秘密"的cell效果整体视图都放到scrollview中,基本是和secret app 一模一样的效果了. 代码如下:(模糊效果的类就不写了,大家可以搜"uiimag...

把"秘密"的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); 
 
    }