SEO什么的我已经放弃了,不过为了方便读者,还是先放张最终效果图:
项目源码在https://github.com/xloger/ImageTransform
不过我不打算对项目进行详细的讲解,毕竟网上有一堆教程了,我会把做这个项目中遇到的一些问题分享出来,所以诸位浏览小标题看看是否有需要的内容就好。
起因
熟悉我的人应该知道我不喜欢造轮子,这种网上一抓一大把的Demo写出来没有任何价值,除了证明你会写。
这段时间我在找工作,某天晚上和一位面试官沟通好了并确定次日下午3点去面试,然而第二天早上的时候他突然问我一句有没有图片滤镜相关的经验,我很实诚地告诉他我没有,不过学习一下并不困难,假如涉及到算法与性能优化的地步那可能需要多花些时间,而且网上有大把的库真有需求了我也能实现。然后他就说公司需要有图片滤镜经验的所以不合适。
哦,图片滤镜经验?好像很厉害的样子?然后我从下午3点到11点,现学现做写了这个Demo,目的仅为争口气。祝您早日找到您需要的会图片滤镜这种高级技术的人才。
ps:假如涉及到自做滤镜效果,以及算法和性能优化这方面,是需要很高深的水平的。我现在的水平只是从网上搜下现成的算法自己写实现而已,但是该公司要的也只是这种能实现常见功能的。
项目介绍
功能上实现了一个调用4.4+图片选择器选择图片,实现了自定义View的画笔功能,实现了各种滤镜效果。
选择图片功能
之前没做过相关内容,代码全是照着Android 4.4从图库选择图片,获取图片路径并裁剪写的。调用的图片选择器长这样:
文章写的挺好的,可能需要对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当图片过大会造成空白
理想情况是如图一那样,但是我之前实现的时候效果一直是如下图:
底下还有一片红色的,height大概是图片的真实高度。而这个是怎么调整scaleType都无效的(保持图片比例的情况下),最后通过设置android:adjustViewBounds=”true”解决了。
被这坑到,大概是我API真的有点不熟吧……
Android6.0的权限机制
6.0的动态权限机制大家应该都清楚吧,结果方案也不复杂。但是我没心情处理了,于是最简单的方案就是把编译的SDK版本改成23之前。
好了大概就是这些值得注意的地方了。还有感兴趣的可以直接看我的源码。