大家应该都看到过iOS7解锁屏幕的滑动模糊渐变效果,好了,现在可以把手纸收起来了,今天黄老师就给大家讲一下如何在Android平台上
实现类似的滑动模糊渐变效果,其实方式远比你想像的简单。
目标效果展示:
第一部分:几个前提
说到模糊效果,我们先要了解几个前提
1、原图,指需要被模糊的一张位图
2、模糊,通常是采用指将一个位图的每个像素RGB值都取周围像素的RGB值的平均值,这样就可以产生模糊效果,一般通过高斯函数来实现,
至于Java中的实现方式黄老师就不给大家细讲了,我也不是搞图形算法的,在这方面了解的不比大家多,百度一下能找到一堆高斯模糊转换的实现。
3、模糊半径,指每个像素点周围模糊的半径,半径越大,模糊程度约高,模糊效果越明显,同时,模糊计算耗费时间越长。
4、模糊处理非常费时,一半在100ms~5000ms内,就黄老师我本人找的网上的算法实测,一般android通过java实现的高斯模糊算法转换一张手机
屏幕分辨率为480x800的位图需要2s左右,所以如果要在滑动的过程中实时不断重新计算模糊效果会非常差,所以如果要实现iOS7那样的滑动动态模糊
渐变效果,用这样的方式是不可行的,实际上iOS也不是这么做的,因为iOS的硬件也没达到能实时计算的程度。
那么究竟应该如何去实现模糊渐变呢,其实非常简单,我们接着讲。
第二部分:动态模糊渐变的合理实现方式
其实,我的方式非常简单,首先你需要明确一个最大的模糊效果的模糊半径值,我们给它取个名字叫maxRadius,然后使用maxRadius和原图传入高斯模糊算法
中计算出最大模糊效果的位图maxBlurBitmap。
然后,在ui组件中,假设我的原图是用一个ImageView显示在界面上的,然后你所需要做的是,再创建一个ImageView置于原图ImageView之上,然后将图片源
设置为maxBlurBitmap,如下图:
接着,我们只需要简单的调整maxBlurBitmap的透明度,即可实现模糊渐变效果了,是否很简单呢?
第三部分,提供一个最简单的Java高斯模糊实现,我网上找来的,方便偷懒不愿自己找的同学
001.
1
/**
002.
2 * 位图处理类
003.
3 * @author HalfmanG2
004.
4 */
005.
5
public
class
BitmapUtil {
006.
6
007.
7
/**
008.
8 * 创建一个虚化的位图
009.
9 * @param sentBitmap 原位图
010.
10 * @param radius 虚化半径
011.
11 * @return 虚化后的位图
012.
12 */
013.
13
public
static
Bitmap createBlurBitmap(Bitmap sentBitmap,
int
radius) {
014.
14
Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(),
true
);
015.
15
if
(radius <
1
) {
016.
16
return
(
null
);
017.
17
}
018.
18
int
w = bitmap.getWidth();
019.
19
int
h = bitmap.getHeight();
020.
20
int
[] pix =
new
int
[w * h];
021.
21
bitmap.getPixels(pix,
0
, w,
0
,
0
, w, h);
022.
22
int
wm = w -
1
;
023.
23
int
hm = h -
1
;
024.
24
int
wh = w * h;
025.
25
int
div = radius + radius +
1
;
026.
26
int
r[] =
new
int
[wh];
027.
27
int
g[] =
new
int
[wh];
028.
28
int
b[] =
new
int
[wh];
029.
29
int
rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
030.
30
int
vmin[] =
new
int
[Math.max(w, h)];
031.
31
int
divsum = (div +
1
) >>
1
;
032.
32
divsum *= divsum;
033.
33
int
dv[] =
new
int
[
256
* divsum];
034.
34
for
(i =
0
; i <
256
* divsum; i++) {
035.
35
dv[i] = (i / divsum);
036.
36
}
037.
37
yw = yi =
0
;
038.
38
int
[][] stack =
new
int
[div][
3
];
039.
39
int
stackpointer;
040.
40
int
stackstart;
041.
41
int
[] sir;
042.
42
int
rbs;
043.
43
int
r1 = radius +
1
;
044.
44
int
routsum, goutsum, boutsum;
045.
45
int
rinsum, ginsum, binsum;
046.
46
for
(y =
0
; y < h; y++) {
047.
47
rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum =
0
;
048.
48
for
(i = -radius; i <= radius; i++) {
049.
49
p = pix[yi + Math.min(wm, Math.max(i,
0
))];
050.
50
sir = stack[i + radius];
051.
51
sir[
0
] = (p &
0xff0000
) >>
16
;
052.
52
sir[
1
] = (p &
0x00ff00
) >>
8
;
053.
53
sir[
2
] = (p &
0x0000ff
);
054.
54
rbs = r1 - Math.abs(i);
055.
55
rsum += sir[
0
] * rbs;
056.
56
gsum += sir[
1
] * rbs;
057.
57
bsum += sir[
2
] * rbs;
058.
58
if
(i >
0
) {
059.
59
rinsum += sir[
0
];
060.
60
ginsum += sir[
1
];
061.
61
binsum += sir[
2
];
062.
62
}
else
{
063.
63
routsum += sir[
0
];
064.
64
goutsum += sir[
1
];
065.
65
boutsum += sir[
2
];
066.
66
}
067.
67
}
068.
68
stackpointer = radius;
069.
69
for
(x =
0
; x < w; x++) {
070.
70
r[yi] = dv[rsum];
071.
71
g[yi] = dv[gsum];
072.
72
b[yi] = dv[bsum];
073.
73
rsum -= routsum;
074.
74
gsum -= goutsum;
075.
75
bsum -= boutsum;
076.
76
stackstart = stackpointer - radius + div;
077.
77
sir = stack[stackstart % div];
078.
78
routsum -= sir[
0
];
079.
79
goutsum -= sir[
1
];
080.
80
boutsum -= sir[
2
];
081.
81
if
(y ==
0
) {
082.
82
vmin[x] = Math.min(x + radius +
1
, wm);
083.
83
}
084.
84
p = pix[yw + vmin[x]];
085.
85
sir[
0
] = (p &
0xff0000
) >>
16
;
086.
86
sir[
1
] = (p &
0x00ff00
) >>
8
;
087.
87
sir[
2
] = (p &
0x0000ff
);
088.
88
rinsum += sir[
0
];
089.
89
ginsum += sir[
1
];
090.
90
binsum += sir[
2
];
091.
91
rsum += rinsum;
092.
92
gsum += ginsum;
093.
93
bsum += binsum;
094.
94
stackpointer = (stackpointer +
1
) % div;
095.
95
sir = stack[(stackpointer) % div];
096.
96
routsum += sir[
0
];
097.
97
goutsum += sir[
1
];
098.
98
boutsum += sir[
2
];
099.
99
rinsum -= sir[
0
];
100.
100
ginsum -= sir[
1
];
101.
101
binsum -= sir[
2
];
102.
102
yi++;
103.
103
}
104.
104
yw += w;
105.
105
}
106.
106
for
(x =
0
; x < w; x++) {
107.
107
rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum =
0
;
108.
108
yp = -radius * w;
109.
109
for
(i = -radius; i <= radius; i++) {
110.
110
yi = Math.max(
0
, yp) + x;
111.
111
sir = stack[i + radius];
112.
112
sir[
0
] = r[yi];
113.
113
sir[
1
] = g[yi];
114.
114
sir[
2
] = b[yi];
115.
115
rbs = r1 - Math.abs(i);
116.
116
rsum += r[yi] * rbs;
117.
117
gsum += g[yi] * rbs;
118.
118
bsum += b[yi] * rbs;
119.
119
if
(i >
0
) {
120.
120
rinsum += sir[
0
];
121.
121
ginsum += sir[
1
];
122.
122
binsum += sir[
2
];
123.
123
}
else
{
124.
124
routsum += sir[
0
];
125.
125
goutsum += sir[
1
];
126.
126
boutsum += sir[
2
];
127.
127
}
128.
128
if
(i < hm) {
129.
129
yp += w;
130.
130
}
131.
131
}
132.
132
yi = x;
133.
133
stackpointer = radius;
134.
134
for
(y =
0
; y < h; y++) {
135.
135
pix[yi] = (
0xff000000
& pix[yi] ) | ( dv[rsum] <<
16
) | ( dv[gsum] <<
8
) | dv[bsum];
136.
136
rsum -= routsum;
137.
137
gsum -= goutsum;
138.
138
bsum -= boutsum;
139.
139
stackstart = stackpointer - radius + div;
140.
140
sir = stack[stackstart % div];
141.
141
routsum -= sir[
0
];
142.
142
goutsum -= sir[
1
];
143.
143
boutsum -= sir[
2
];
144.
144
if
(x ==
0
) {
145.
145
vmin[y] = Math.min(y + r1, hm) * w;
146.
146
}
147.
147
p = x + vmin[y];
148.
148
sir[
0
] = r[p];
149.
149
sir[
1
] = g[p];
150.
150
sir[
2
] = b[p];
151.
151
rinsum += sir[
0
];
152.
152
ginsum += sir[
1
];
153.
153
binsum += sir[
2
];
154.
154
rsum += rinsum;
155.
155
gsum += ginsum;
156.
156
bsum += binsum;
157.
157
stackpointer = (stackpointer +
1
) % div;
158.
158
sir = stack[stackpointer];
159.
159
routsum += sir[
0
];
160.
160
goutsum += sir[
1
];
161.
161
boutsum += sir[
2
];
162.
162
rinsum -= sir[
0
];
163.
163
ginsum -= sir[
1
];
164.
164
binsum -= sir[
2
];
165.
165
yi += w;
166.
166
}
167.
167
}
168.
168
bitmap.setPixels(pix,
0
, w,
0
,
0
, w, h);
169.
169
return
(bitmap);
170.
170
}
171.
171
}