在Ynote的改进中涉及到一个图片放大的功能,原来自己开发的图片缩放移动功能没有那么好的用户体验,于是应用网上的开源项目GestureImage。
第一部分参考了http://www.cnblogs.com/joylee/p/Android-GestureImageView.html;
第二部分为第一部分使用时为避免MMO问题,同时缩放图片是图片质量不会太失真而所添加的内容。
如果某项目对图片质量要求很高请参考 《图片无限放大,不模糊,图片移动,仿微信图片放大 》,或许可以将这两篇文章结合起来写一个用户体验很高的图片相关功能
Android 开发过程中,交互效果是一个非常繁琐的过程,甚至比Web开发过程中JS特效更加复杂。通过多年的发展,常用的交互方式已经发展相当成熟,而且有很多非常好的插件。为了避免重复造轮子,一些常用的特效,我们可以直接拿来就用的,节省我们开发时间。留时间去开发更具有自身特色的东西。这里介绍一些常用的Android插件,而且都是些使用起来很简单的插件。
开篇第一个――GestureImageView
简介:单图浏览插件,支持图片多点缩放,支持图片拖动,开放单击和双击事件,点击事件与触摸事件不冲突(自己写过类似程序的都懂,触摸和点击容易冲突,处理起来有点复杂)
主页:https://github.com/jasonpolites/gesture-imageview
使用方法:
1、Github下载代码
example为示例,教你如何使用,实际使用过程中没有任何关系。
main为插件源码,需要放入自己的项目中。
2、基础配置
main项目可以生成jar包引用或者作为另外一个项目引用,但个人更喜欢直接引用代码,方便后续修改,也便于规范命名。
所以,大家可以直接将Main文件中的src的内容放入自己的项目中。
因为没有涉及的Layout,所以是不会报错的。
3、使用
新建一个Layout页面
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:gesture-image="http://schemas.polites.com/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center" > <com.polites.android.GestureImageView android:id="@+id/dmImageView" android:layout_width="fill_parent" android:layout_height="wrap_content" gesture-image:min-scale="0.1" gesture-image:max-scale="10.0" gesture-image:strict="false" /> </LinearLayout>
注意:LinearLayout中的 xmlns:gesture-image="http://schemas.polites.com/android" ,不添加会报错的。粗心大意很难发现。
gesture-image:min-scale 缩放最小值 gesture-image:max-scale 缩放最大值 gesture-image:strict 是否精确
使用方式和 ImageView 的使用方式是一样的,可以自己尝试其他属性。
GestureImageView使用和配置是非常简单的。入手非常容易,作为这个博主的推荐的第一个插件。下篇为大家推荐一个瀑布流插件。
第二部分:
在使用BitmapFactory.decodeFile(path)时遇到像素大的会产生内存溢出mmo问题
android系统中有这么一个变量BitmapFactory.Options可以安某比例获取到合适的图片。于是上网搜索牛人的帖子组合成下面的代码解决oom问题,同时图片质量又不会太差。
原理就是动态计算某
图片Options的值,这样就能将图片质量与MMO兼顾了
public Bitmap myScaleBitmap(String path){ BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(path, options); if (options.mCancel || options.outWidth == -1 || options.outHeight == -1) { return null; } options.inSampleSize = computeSampleSize(options, 600, (int) (1 * 1024 * 1024)); options.inJustDecodeBounds = false; options.inDither = false; options.inPreferredConfig = Bitmap.Config.ARGB_8888; Bitmap bitmap = BitmapFactory.decodeFile(path, options); return bitmap; } public static int computeSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) { int initialSize = computeInitialSampleSize(options, minSideLength, maxNumOfPixels); int roundedSize; if (initialSize <= 8) { roundedSize = 1; while (roundedSize < initialSize) { roundedSize <<= 1; } } else { roundedSize = (initialSize + 7) / 8 * 8; } return roundedSize; } private static int computeInitialSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) { double w = options.outWidth; double h = options.outHeight; int lowerBound = (maxNumOfPixels == -1) ? 1 : (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels)); int upperBound = (minSideLength == -1) ? 128 : (int) Math.min(Math.floor(w / minSideLength), Math.floor(h / minSideLength)); if (upperBound < lowerBound) { // return the larger one when there is no overlapping zone. return lowerBound; } if ((maxNumOfPixels == -1) && (minSideLength == -1)) { return 1; } else if (minSideLength == -1) { return lowerBound; } else { return upperBound; } }