最近在练习一个项目,需要写一个聊天室模块;因此需要实现发表情与发gif图片的功能。刚开始用Github上的开源框架gif_drawable里的gifImageView,可是加载总是出问题;网上查了很久,试了很多方法也没解决;最后放弃了,就选用了大神郭霖写的PowerImageView那个自定义View来实现。
PwerImageView源码博客:http://blog.csdn.net/guolin_blog/article/details/11100315
在阅读了PowerImageView源码与看了相关评论后,对郭大神写的这个自定义View有了初步的了解;知道这个类还存在一些Bug,根据网友的评论和自己使用的情况进行一些总结:
1、在获取到src指定图片资源所对应的id这一块,郭霖是通过Java底层反射机制来获得,以下是方法代码:
private int getResourceId(TypedArray a, Context context, AttributeSet attrs) {
try {
Field field = TypedArray.class.getDeclaredField("mValue");
field.setAccessible(true);
TypedValue typedValueObject = (TypedValue) field.get(a);
return typedValueObject.resourceId;
} catch (Exception e) {
e.printStackTrace();
} finally {
if (a != null) {
a.recycle();
}
}
有细心的网友指出,这个为获取资源id调用反射机制来做把问题复杂化了点,且有一些网友发现这个方法会导致一些Bug出来;可以用atts里一个方法直接获取到资源id:
//使用for循环逐个取出attrs里的元素名跟src比较,如果符合,则取出对应的值(id);
for (int i = 0; i < attrs.getAttributeCount(); i++) {
if(attrs.getAttributeName(i).equals("src")) {
resourceId= attrs.getAttributeResourceValue(i, 0);
} }
两个方法我都试过了,都可以用;但第二个方法相对简单明了,因此我选择了网友提供的这个方法。
2、关于文中提到的android4.0版本以上因为默认开启了硬件加速功能会导致gif动画播放不出来,需要在注册清单中通过将hardwareAccelerated属性设置为”false“来禁用硬件加速功能;但有网友发现这种做法会导致整个应用运行效率降低,会使用一些页面加载时特别卡;建议使用另一个方法:
在构造函数中增加一行代码(红色字体代码):
public PowerImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PowerImageView);
// int resourceId = getResourceId(a, context, attrs);
for (int i = 0; i < attrs.getAttributeCount(); i++) {
if(attrs.getAttributeName(i).equals("src")) {
resourceId= attrs.getAttributeResourceValue(i, 0);
} }
if (resourceId != 0) {
// 当资源id不等于0时,就去获取该资源的流
InputStream is = getResources().openRawResource(resourceId);
// 使用Movie类对流进行解码
mMovie = Movie.decodeStream(is);
if (mMovie != null) {
// 如果返回值不等于null,就说明这是一个GIF图片,下面获取是否自动播放的属性
<span style="color:#ff0000;">this.setLayerType(View.LAYER_TYPE_SOFTWARE, null);</span>
isAutoPlay = a.getBoolean(R.styleable.PowerImageView_auto_play, false);
Bitmap bitmap = BitmapFactory.decodeStream(is);
mImageWidth = bitmap.getWidth();
mImageHeight = bitmap.getHeight();
bitmap.recycle();
if (!isAutoPlay) {
// 当不允许自动播放的时候,得到开始播放按钮的图片,并注册点击事件
mStartButton = BitmapFactory.decodeResource(getResources(),
R.drawable.start_play);
setOnClickListener(this);
}
}
}
}
3、加载了gif图片后,很多gif动画却只是加载的时候执行一次,并不会反复循环播放,但有一些图片又是可以循环播放的;源码中在onDraw方法中调用了playMovie方法后,调用了invalidate()方法;按理来说调用了invalidate方法后会重复执行onDraw方法,网上查找了相关的分享后发现,高版本的android系统可能进行了一些优化,view的invalidate方法不一定会触发onDraw方法重新执行;但问题点是,为何是固定的图片不会触发ondraw方法,而不是随机性产生的?