一个简单的Android图片滤镜实现与心得

SEO什么的我已经放弃了,不过为了方便读者,还是先放张最终效果图:

1

项目源码在https://github.com/xloger/ImageTransform

不过我不打算对项目进行详细的讲解,毕竟网上有一堆教程了,我会把做这个项目中遇到的一些问题分享出来,所以诸位浏览小标题看看是否有需要的内容就好。

起因

熟悉我的人应该知道我不喜欢造轮子,这种网上一抓一大把的Demo写出来没有任何价值,除了证明你会写。

这段时间我在找工作,某天晚上和一位面试官沟通好了并确定次日下午3点去面试,然而第二天早上的时候他突然问我一句有没有图片滤镜相关的经验,我很实诚地告诉他我没有,不过学习一下并不困难,假如涉及到算法与性能优化的地步那可能需要多花些时间,而且网上有大把的库真有需求了我也能实现。然后他就说公司需要有图片滤镜经验的所以不合适。

哦,图片滤镜经验?好像很厉害的样子?然后我从下午3点到11点,现学现做写了这个Demo,目的仅为争口气。祝您早日找到您需要的会图片滤镜这种高级技术的人才。

ps:假如涉及到自做滤镜效果,以及算法和性能优化这方面,是需要很高深的水平的。我现在的水平只是从网上搜下现成的算法自己写实现而已,但是该公司要的也只是这种能实现常见功能的。

 

项目介绍

功能上实现了一个调用4.4+图片选择器选择图片,实现了自定义View的画笔功能,实现了各种滤镜效果。

 

选择图片功能

之前没做过相关内容,代码全是照着Android 4.4从图库选择图片,获取图片路径并裁剪写的。调用的图片选择器长这样:

2

文章写的挺好的,可能需要对ContentProviders比较熟,建议不熟悉的先了解好。(不得不庆幸我博客冷啊,翻了下他文章评论,一大堆小白问题,三个因为没加SD卡权限不会的,五个不知道Uri该传啥的,这种伸手党我真不知道怎么处理好)

然后最好再对图片做下裁剪,也是发相应的Intent就好。不过我没这需求就没做。

 

画笔功能

是参照Android学习笔记进阶之在图片上涂鸦(能清屏)来的。不过原文有些问题没能很好地解决,我提几点:

资源文件不能被修改(Immutable bitmap passed to Canvas constructor)

文章是四年前的,他当时使用的是Bitmap.createBitmap()创建一个副本,现在大概是改了机制,因此你需要调用bitmap对象的copy方法来拷贝一个Bitmap。

动态设置图片

这个比较废话我在考虑我的文章要不要写的这么详细…看我项目里HandWriteView类的setImg方法就好,记得要手动重新设置Width,Height就好。

滑动事件拦截

因为我的图片比较大,所以是用了ScrollView与HorizontalScrollView滑动的,但是这就造成了滑动事件与画笔事件冲突的问题。

在阅读之前请保证你有事件传递相关的知识(可以学习郭霖的Android事件分发机制完全解析,带你从源码的角度彻底理解(上)),我本来以为我还算熟悉事件传递结果还是一脸懵逼。

我最开始的想法是根据事件传递机制,我只需要在onTouchEvent方法里return true就告诉父控件们这个事件我处理了,那应该没问题才对。结果后来发现父控件们在某些时候会直接在onInterceptTouchEvent里把该事件拦截了,所以身为子控件的我们是没有办法的。

然后搜了网上一些方法,大部分是写一个自定义ScrollView,然后那里让事件能正常传递给我们HandWriteView,略有点麻烦。然后在一个论坛里看到有人提到在子控件的onTouchEvent里直接调用getParent().requestDisallowInterceptTouchEvent(true)就好。该方法会告诉父控件不要拦截它的触摸事件,那么就能正常使用画笔了。

也许有人会疑问不是都拦截了那怎么调用子控件的onTouchEvent方法呢,应该是down事件是能正常传递的,但是move事件可能就会被拦截了,而这些拦截申明都是在一次触摸事件中生效的,所以只要你在down监听中让父控件不拦截,那么之后的move也是不会被处理的。

 

图片滤镜

该部分都是参照Android实战经验之图像处理及特效处理的集锦(总结版)实现的。不过看下来感觉作者代码风格变化比较大,似乎不全是原创,诸位不要太相信里面的代码了。

高斯模糊

使用模糊时需要注意的是性能问题,如果直接采用高斯模糊的那个算法会非常卡,所以一般是直接调用Android底层的RenderScript实现,或把一张图先缩小再放大。

 

杂七杂八的小技巧

Live Templates

输入fbc可以直接findViewById并且带类型(不需要手把手强制转换),输入gone可以直接把某个view隐藏,输入rgS可以直接获取String文件里的字符串,输入toast可以快速生成一个toast模板。

XML文件中lhw直接就是android:layout_height=”wrap_content”,lhm就是android:layout_height=”match_parent”,lww,lwm同理。

至于fori,foreach,iter这种常见的就不多说了。而且这些都是可以自己设定的。详情可参考https://zhuanlan.zhihu.com/p/22245405

ImageView当图片过大会造成空白

理想情况是如图一那样,但是我之前实现的时候效果一直是如下图:

3【我把ImageView的background设成红色了

底下还有一片红色的,height大概是图片的真实高度。而这个是怎么调整scaleType都无效的(保持图片比例的情况下),最后通过设置android:adjustViewBounds=”true”解决了。

被这坑到,大概是我API真的有点不熟吧……

Android6.0的权限机制

6.0的动态权限机制大家应该都清楚吧,结果方案也不复杂。但是我没心情处理了,于是最简单的方案就是把编译的SDK版本改成23之前。

 

好了大概就是这些值得注意的地方了。还有感兴趣的可以直接看我的源码。

发布者:xloger

在无限延伸的梦想后面 穿越冷酷无情的世界

留下评论

电子邮件地址不会被公开。 必填项已用*标注