·您现在的位置: 云翼网络 >> 文章中心 >> 网站建设 >> app软件开发 >> IOS开发 >> iOS-TwitterCover小效果

iOS-TwitterCover小效果

作者:佚名      IOS开发编辑:admin      更新时间:2022-07-23

For What?

Twitter客户端在个人Tab有这样的一个效果:

         

向下拖动ScrollView(TableView)时,ScrollView上方的图片会随着手指的拖动而放大并且变模糊。松开手指之后,图片随着ScrollView的回复原来位置而恢复原样,如上图。

 

What I Do?

So,我们可以怎么实现一个类似的效果呢?

下面是我刚写的一个Demo截图,非常简单,而且也是用了网上开源的毛玻璃代码。

      

 

咱来个高端的工具,看看,这里面是怎么的一个架构?!

通过树状的视图效果,我们可以看出,背景图片backgroundImageView(放大,毛玻璃效果)是一个UIImageView的子类,TableView会占据真个Window的bounds。其中TableView的tableHeaderView正好覆盖在backgroundImageView的上方,并且背景是透明色,才能看到下层backgroundImageView的变化情况。

 

依赖开源代码

毛玻璃图片开源代码:https://github.com/CoCrash/DKLiveBlur

 1 //
 2 //  DKLiveBlurView.h
 3 //  LiveBlur
 4 //
 5 //  Created by Dmitry Klimkin on 16/6/13.
 6 //  Copyright (c) 2013 Dmitry Klimkin. All rights reserved.
 7 //
 8 
 9 #import <UIKit/UIKit.h>
10 
11 #define kDKBlurredBackgroundDefaultLevel 0.9f
12 #define kDKBlurredBackgroundDefaultGlassLevel 0.2f
13 #define kDKBlurredBackgroundDefaultGlassColor [UIColor whiteColor]
14 
15 @interface DKLiveBlurView : UIImageView
16 
17 @PRoperty (nonatomic, strong) UIImage *originalImage;
18 @property (nonatomic, weak) UIScrollView *scrollView;
19 @property (nonatomic, assign) float initialBlurLevel;
20 @property (nonatomic, assign) float initialGlassLevel;
21 @property (nonatomic, assign) BOOL isGlassEffectOn;
22 @property (nonatomic, strong) UIColor *glassColor;
23 
24 - (void)setBlurLevel:(float)blurLevel;
25 
26 @end
DKLiveBlurView.h
  1 //
  2 //  DKLiveBlurView.m
  3 //  LiveBlur
  4 //
  5 //  Created by Dmitry Klimkin on 16/6/13.
  6 //  Copyright (c) 2013 Dmitry Klimkin. All rights reserved.
  7 //
  8 
  9 #import "DKLiveBlurView.h"
 10 #import <Accelerate/Accelerate.h>
 11 
 12 @interface DKLiveBlurView ()
 13 
 14 @property (nonatomic, strong) UIImageView *backgroundImageView;
 15 @property (nonatomic, strong) UIView *backgroundGlassView;
 16 
 17 @end
 18 
 19 @implementation DKLiveBlurView
 20 
 21 @synthesize originalImage = _originalImage;
 22 @synthesize backgroundImageView = _backgroundImageView;
 23 @synthesize scrollView = _scrollView;
 24 @synthesize initialBlurLevel = _initialBlurLevel;
 25 @synthesize backgroundGlassView = _backgroundGlassView;
 26 @synthesize initialGlassLevel = _initialGlassLevel;
 27 @synthesize isGlassEffectOn = _isGlassEffectOn;
 28 @synthesize glassColor = _glassColor;
 29 
 30 - (id)initWithFrame:(CGRect)frame {
 31     self = [super initWithFrame:frame];
 32     if (self) {
 33         // Initialization code
 34         
 35         _initialBlurLevel = kDKBlurredBackgroundDefaultLevel;
 36         _initialGlassLevel = kDKBlurredBackgroundDefaultGlassLevel;
 37         _glassColor = kDKBlurredBackgroundDefaultGlassColor;
 38 
 39         _backgroundImageView = [[UIImageView alloc] initWithFrame: self.bounds];
 40         
 41         _backgroundImageView.alpha = 0.0;
 42         _backgroundImageView.contentMode = UIViewContentModeScaleToFill;
 43         _backgroundImageView.backgroundColor = [UIColor clearColor];
 44         
 45         _backgroundImageView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
 46 
 47         [self addSubview: _backgroundImageView];
 48         
 49         _backgroundGlassView = [[UIView alloc] initWithFrame: self.bounds];
 50         
 51         _backgroundGlassView.alpha = 0.0;
 52         _backgroundGlassView.backgroundColor = kDKBlurredBackgroundDefaultGlassColor;
 53         
 54         _backgroundGlassView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
 55                 
 56         [self addSubview: _backgroundGlassView];
 57     }
 58     return self;
 59 }
 60 
 61 - (void)setGlassColor:(UIColor *)glassColor {
 62     _glassColor = glassColor;
 63     _backgroundGlassView.backgroundColor = glassColor;
 64 }
 65 
 66 - (void)setScrollView:(UIScrollView *)scrollView {
 67     [_scrollView removeObserver: self forKeyPath: @"contentOffset"];
 68     
 69     _scrollView = scrollView;
 70     
 71     [_scrollView addObserver: self forKeyPath: @"contentOffset" options: 0 context: nil];
 72 }
 73 
 74 - (UIImage *)blurryImage:(UIImage *)image withBlurLevel:(CGFloat)blur {
 75     if ((blur < 0.0f) || (blur > 1.0f)) {
 76         blur = 0.5f;
 77     }
 78     
 79     int boxSize = (int)(blur * 100);
 80     boxSize -= (boxSize % 2) + 1;
 81     
 82     CGImageRef img = image.CGImage;
 83     
 84     vImage_Buffer inBuffer, outBuffer;
 85     vImage_Error error;
 86     void *pixelBuffer;
 87     
 88     CGDataProviderRef inProvider = CGImageGetDataProvider(img);
 89     CFDataRef inBitmapData = CGDataProviderCopyData(inProvider);
 90     
 91     inBuffer.width = CGImageGetWidth(img);
 92     inBuffer.height = CGImageGetHeight(img);
 93     inBuffer.rowBytes = CGImageGetBytesPerRow(img);
 94     inBuffer.data = (void*)CFDataGetBytePtr(inBitmapData);
 95     
 96     pixelBuffer = malloc(CGImageGetBytesPerRow(img) * CGImageGetHeight(img));
 97         
 98     outBuffer.data = pixelBuffer;
 99     outBuffer.width = CGImageGetWidth(img);
100     outBuffer.height = CGImageGetHeight(img);
101     outBuffer.rowBytes = CGImageGetBytesPerRow(img);
102     
103     error = vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer, NULL,
104                                        0, 0, boxSize, boxSize, NULL,
105                                        kvImageEdgeExtend);
106     
107     
108     if (error) {
109         NSLog(@"error from convolution %ld", error);
110     }
111     
112     CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
113     CGContextRef ctx = CGBitmapContextCreate(
114                                              outBuffer.data,
115                                              outBuffer.width,
116                                              outBuffer.height,
117                                              8,
118                                              outBuffer.rowBytes,
119                                              colorSpace,
120                                              CGImageGetBitmapInfo(image.CGImage));
121     
122     CGImageRef imageRef = CGBitmapContextCreateImage (ctx);
123     UIImage *returnImage = [UIImage imageWithCGImage:imageRef];
124     
125     //clean up
126     CGContextRelease(ctx);
127     CGColorSpaceRelease(colorSpace);
128     
129     free(pixelBuffer);
130     CFRelease(inBitmapData);
131     
132     CGColorSpaceRelease(colorSpace);
133     CGImageRelease(imageRef);
134     
135     return returnImage;
136 }
137 
138 - (void)setOriginalImage:(UIImage *)originalImage {
139     _originalImage = originalImage;
140     
141     self.image = originalImage;
142     
143     dispatch_queue_t queue = dispatch_queue_create("Blur queue", NULL);
144     
145     dispatch_async(queue, ^ {
146         
147         UIImage *blurredImage = [self blurryImage: self.originalImage withBlurLevel: self.initialBlurLevel];
148         
149         dispatch_async(dispatch_get_main_queue(), ^{
150             
151             self.backgroundImageView.alpha = 0.0;
152             self.backgroundImageView.image = blurredImage;
153         });
154     });
155     
156     dispatch_release(queue);
157 }
158 
159 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
160                         change:(NSDictionary *)change context:(void *)context {
161     
162     // closer to zero, less blur applied
163     [self setBlurLevel:(self.scrollView.contentInset.top - self.scrollView.contentOffset.y) / (3* CGRectGetHeight(self.bounds) / 5)];
164 }
165 
166 - (void)setBlurLevel:(float)blurLevel {
167     self.backgroundImageView.alpha = blurLevel;
168     
169     if (self.isGlassEffectOn) {
170         self.backgroundGlassView.alpha = MAX(0.0, MIN(self.backgroundImageView.alpha - self.initialGlassLevel, self.initialGlassLevel));
171     }
172 }
173 
174 @end
DKLiveBlurView.m

其实可以不用开DKLiveBlur的开源Demo,他主要实现了UIImageView的一个子类DKLiveBlurView,增加了毛玻璃效果。

- setBlurLevel:方法给我们有能力去设置毛玻璃的程度,这也是我们实现类似Twitter cover效果的主要效果,毛玻璃效果随着tableview的偏移程度,逐渐改变的过程。

 

我又写了几行代码?

为了实现这个效果,我又写了几行代码?

用户在拖动scrollView(tableView)导致content offset改变的时候就会调用-scrollViewDidScroll:方法,因此我们想在用户拖动scrollview的时候,改变背景图片的大小和毛玻璃程度,则需要实现-scrollViewDidScroll:方法,并计算scrollview的content offset在Y轴下的改变值,得到图片伸缩和毛玻璃效果的比例。

除了做这个界面的布局代码,实际有用的代码就这几行:

 1 - (void)scrollViewDidScroll:(UIScrollView *)scrollView{
 2     CGPoint offset1 = scrollView.contentOffset;
 3     [backgroundView setBlurLevel:(- offset1.y/120)];
 4     
 5     CGRect baseFrame = backgroundView.frame;
 6     float visable_height = 162 - offset1.y;
 7     if (visable_height > 160) {
 8         //放大的情况
 9         baseFrame.origin.y = 0;
10         baseFrame.size.height = visable_height;
11     }else{
12         //正常情况
13         baseFrame.origin.y = (visable_height - 160)/2.0f;
14         baseFrame.size.height = 160;
15     }
16     backgroundView.frame = baseFrame;
17     
18 }

 

国内还有哪些高端大气的APP用了类似的效果?

       

看到这个界面大家是不是很熟悉?哈哈,陌陌同学的个人资料页就有类似的一个效果,不过TA平凡点,没有毛玻璃效果。或者毛玻璃有点像打马赛克一样,让陌陌同学很是不适吧。

 

曾记否,TX的手Q小企鹅也有过一个小小界面是用了类似的效果的。我相信是个大家都未曾听说过的东东:公开群···

在TA的资料页也是用了类似偏移缩放的效果。现在公开群的入口貌似被老大们屏蔽了,那就算TA已经挂掉了吧,这里我们就没办法截取效果图给大家看了。

 

SO,你看,那么多人喜欢用到这个效果,行过路过,别忘了进来看看哈。哈哈。Daisy,我写博客了···