Android模糊图像教程(2)
前面我们介绍了使用RenderScript使另一个视图范围内的图片部分模糊。但是实际上,我们并没有深入地调用这个方法来研究图像模糊行为。原因是我们需要在性能方面进行仔细考虑,这篇文章我们会进行更进一步地的探索。
调用这个方法最直白的方法是父布局的onDraw()
。有经验的开发者读到这里可能会开始摇头,我们应该保持onDraw
方法的实现尽可能有效。以前的文章中的代码包括创建对象、位图操作和切换到renderScript
上下文。其中,OnDraw
会降低帧速率。你可以不相信我的做法,但是可以通过测量并证明它是有效的。在后面的系列中,我们就会这样做。
如果布局是静态的(即我们的布局不包含任何动画),在布局时就不会改变待模糊的位置和范围。只有在布局改变时执行该操作才有意义,但前提是布局的所有视图大小和位置根据布局变化测量和计算过。这里有一个非常实用的技巧,可以注册一个OnGlobalLayoutListener
监听函数。当布局发生改变的时候会调用onGlobalLayout()
方法。当我们收到布局已经改变的通知时,注册的OnPreDrawListener
监听函数的onPreDraw()
方法会被调用每当执行onDraw
方法。我们要做的第一件事情就是取消注册onPreDraw()
方法,这样只有在布局改变的时候才会被调用,而不是每次onDraw
方法触发时都调用。下面可以执行模糊方法,从这个方法的返回值很重要,使用它可以让我们放弃onDraw
操作,重复之前的布局。这对在回调函数中修改布局非常有帮助,但是这里不需要这么做。所以返回true,继续绘制。
我们的Activity
代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
public class MainActivity extends Activity { private ImageView mImage; private TextView mText; private OnPreDrawListener mPreDrawListener = new OnPreDrawListener() { @Override public boolean onPreDraw() { ViewTreeObserver observer = mText.getViewTreeObserver(); if (observer != null ) { observer.removeOnPreDrawListener( this ); } Drawable drawable = mImage.getDrawable(); if (drawable != null && drawable instanceof BitmapDrawable) { Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap(); if (bitmap != null ) { blur(bitmap, mText, 25 ); } } return true ; } }; private OnGlobalLayoutListener mLayoutListener = new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { ViewTreeObserver observer = mText.getViewTreeObserver(); if (observer != null ) { observer.addOnPreDrawListener( mPreDrawListener); } } }; /** * Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.main); mImage = (ImageView) findViewById(R.id.image); mText = (TextView)findViewById(R.id.text); if (mImage != null && mText != null ) { ViewTreeObserver observer = mText.getViewTreeObserver(); if (observer != null ) { observer.addOnGlobalLayoutListener( mLayoutListener); } } } private void blur(Bitmap bkg, View view, float radius) { . . . } } |
在父布局覆盖onDraw
方法的优点是,可以在布局层次上任意附加OnPreDrawListener
方法。因此需要自定义一个布局,这个布局是标准布局的子类,这样就可以覆盖onDraw
方法。使用predrawlistener
意味着可以非常容易在任意布局中添加。
最后,模糊图片实现如下:
在下一篇文章中,我会更深入地回答为什么要避免在onDraw
中执行模糊操作,并且还会介绍有用的性能测量工具。
这篇文章的代码在这里。