图片加载缓存+双指拉伸图片实战

来源:互联网 发布:模拟q币充值软件 编辑:程序博客网 时间:2024/04/28 13:11

记得以前写过一篇双指拉伸图片的博客,那里基本是可以的,文章最后推出了一个问题关于Bitmap的优化。那篇博客用的是拉伸过程当中不断地创建Bitmap的老套方法,不能说是老套方法,因为那个方法放在这个应用场景下是不能用的,会照成内存泄露最终OOM。其实imageview里面有一个setImageMatrix函数,直接调用矩阵变换图片会非常容易解决这个问题。

下面这个程序会从文件中读取几十张图片(默认为23张并且有固定的名称,不过那都是小问题可以根据自己来改),然后用了缓存技术改进下性能(缓存在这里不明显,如果用在网络图片的加载而不是本地图片的加载会比较明显,这种缓存是用LRU而没有用软引用队列,因为听说现在软引用和弱引用在系统GC的时候都会被强制回收掉所以没有必要,但是究竟是不是还要查一下)。支持双指拉伸图片和单指移动图片,会记录上次的页码。

最后提一下,如果我还忘记把onTouch的返回值改为true我就剁手。。

下面是代码,写的有点乱:

package com.example.mytest;import android.annotation.SuppressLint;import android.app.Activity;import android.content.Context;import android.content.SharedPreferences;import android.content.SharedPreferences.Editor;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.BitmapFactory.Options;import android.graphics.Color;import android.graphics.Matrix;import android.graphics.Paint;import android.graphics.PointF;import android.graphics.RectF;import android.os.Bundle;import android.os.Environment;import android.support.v4.util.LruCache;import android.util.FloatMath;import android.view.MotionEvent;import android.view.View;import android.view.View.OnClickListener;import android.view.View.OnTouchListener;import android.view.WindowManager;import android.widget.Button;import android.widget.ImageView;public class MainActivity extends Activity {// 三个控件private ImageView iv;private Button pre;private Button next;// 当前页码和最大页码private int curPage = 1;final private int maxPage = 23;// 屏幕的窗口大小private int windowsWidth;private int windowsHeight;// 当前图片的大小private int picWidth = 0;private int picHeight = 0;// 图片路径private String parentPath = Environment.getExternalStorageDirectory()+ "/finger/";// 当前图片的路径private String curPath;// 缓存所需容器private LruCache<String, Bitmap> mMemoryCache;// 旧的两指距离private float oldDis = 0.0f;// 新的两指距离private float newDis = 0.0f;// 单指点击时起始位置private PointF startPoint;// 判断是否是双指private boolean touchAgain = false;// 存储图片缩放比private float scarePre = 1.0f;// 判断当前图片是否已经被移动过private boolean isTouchedAgain = false;// 辅助判断的条件,判断在同一个页面中是否是第一次移动private boolean isFirstMoved = true;// 双指触控所需组件private Paint paint;private Matrix matrix;// 最少缩放比例float minScaleR = 0.1f;// 最大缩放比例static final float MAX_SCALE = 4f;@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 获得起始页面SharedPreferences sp = getSharedPreferences("config",Context.MODE_PRIVATE);int t = sp.getInt("page", 0);if (t != 0) {curPage = t;}// 生成当前图片的路径curPath = parentPath + curPage + ".png";pre = (Button) findViewById(R.id.pre);next = (Button) findViewById(R.id.next);iv = (ImageView) findViewById(R.id.iv);// 初始化画笔和矩阵paint = new Paint();paint.setColor(Color.BLACK);matrix = new Matrix();startPoint = new PointF();// 计算缓存最大内存final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);final int cacheSize = maxMemory / 8;WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);windowsWidth = wm.getDefaultDisplay().getWidth();windowsHeight = wm.getDefaultDisplay().getHeight();mMemoryCache = new LruCache<String, Bitmap>((cacheSize)) {@SuppressLint("NewApi")@Overrideprotected int sizeOf(String key, Bitmap value) {// TODO Auto-generated method stubreturn value.getByteCount() / 1024;}};// 加载第一张图片Bitmap firstPic = creatBm(curPage);iv.setImageBitmap(firstPic);// 缓存当前和下一张图片savePage(curPage);if (curPage < maxPage) {savePage(curPage + 1);}/** * 上一张按钮的监听器 */pre.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {// TODO Auto-generated method stubif (curPage <= 1) {return;}curPage--;Bitmap bm = mMemoryCache.get(curPage + "");if (bm == null) {curPath = parentPath + curPage + ".png";bm = creatBm(curPage);}iv.setImageBitmap(bm);isTouchedAgain = false;// 缓存前一张图片if (curPage > 1) {savePage(curPage - 1);}}});/** * 下一张按钮的监听器 */next.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {// TODO Auto-generated method stubif (curPage >= maxPage) {return;}curPage++;Bitmap bm = mMemoryCache.get(curPage + "");if (bm == null) {curPath = parentPath + curPage + ".png";bm = creatBm(curPage);}iv.setImageBitmap(bm);isTouchedAgain = false;// 缓存下一张图片if (curPage < maxPage) {savePage(curPage + 1);}}});/** * 为imageview设置点击事件。作用:进行图片的放大和缩小。 */iv.setOnTouchListener(new OnTouchListener() {// 当前的缩放比private float scale = 0.0f;@Overridepublic boolean onTouch(View v, MotionEvent event) {// TODO Auto-generated method stubswitch (event.getAction() & MotionEvent.ACTION_MASK) {// 第一个手指按下case MotionEvent.ACTION_DOWN:// 记录按下位置,方便后面单指拖拽操作startPoint.set(event.getX(), event.getY());break;// 第二个手指按下case MotionEvent.ACTION_POINTER_DOWN:touchAgain = true;oldDis = spacing(event);break;// 手指移动case MotionEvent.ACTION_MOVE:if (touchAgain == false) {// 仅有一个手指下做拖拽操作matrix.postTranslate((event.getX() - startPoint.x) / 16.0f,(event.getY() - startPoint.y) / 16.0f);iv.setImageMatrix(matrix);break;}newDis = spacing(event);// 微小变化不作处理if (newDis > (oldDis - 10.0f) && newDis < (oldDis + 10.0f)) {break;}// 计算缩放比scale = newDis / oldDis;if (scale > 1) {float t = scale - 1.0f;t = t / 2.0f;scale = scale - t;}if (scale < 1) {float t = 1.0f - scale;t = t / 2.0f;scale = scale + t;}// 如果是原来的页面if (isTouchedAgain == true) {// 如果在该页面是第一次移动if (isFirstMoved == true) {scale = scarePre;isFirstMoved = false;} else {// 在原来的页面不是第一次移动scale = scale * scarePre;}}// 计算出新的宽高matrix.setScale(scale, scale);// 图片居中center();iv.setImageMatrix(matrix);newDis = oldDis;break;case MotionEvent.ACTION_POINTER_UP:touchAgain = false;// 保存这次结束后的缩放比scarePre = scale;isTouchedAgain = true;isFirstMoved = true;break;default:break;}return true;}});}/** *  * 缓存图片函数 *  * @param page *            :要缓存图片的页码 *  *  */private void savePage(int page) {Bitmap curPic = mMemoryCache.get(page + "");if (curPic == null) {curPic = creatBm(page);}mMemoryCache.put(page + "", curPic);}/** * 根据屏幕大小进行创建并缩放图片 *  * @param page *            :要创建的图片的标示 * @return 创建的Bitmap */private Bitmap creatBm(int page) {String path = parentPath + page + ".png";Options opts = new Options();opts.inJustDecodeBounds = true;BitmapFactory.decodeFile(path, opts);picWidth = opts.outWidth;picHeight = opts.outHeight;float scareWidth = (float) picWidth / windowsWidth;float scareHeight = (float) picHeight / windowsHeight;float scare = (scareWidth > scareHeight) ? scareWidth : scareHeight;if (scare < 1) {scare = 1;}opts.inJustDecodeBounds = false;opts.inSampleSize = (int) scare;Bitmap bm = BitmapFactory.decodeFile(path, opts);return bm;}/** * 求出两点之间的距离 *  * @param event *            触摸事件 * @return 两点之间的距离 */private float spacing(MotionEvent event) {float x = event.getX(0) - event.getX(1);float y = event.getY(0) - event.getY(1);return FloatMath.sqrt(x * x + y * y);}/** * 居中图片 */protected void center() {center(true, true);}/** *  * @param horizontal *            水平方向是否居中 * @param vertical *            竖直方向是否居中 */private void center(boolean horizontal, boolean vertical) {RectF rect = new RectF(0, 0, picWidth, picHeight);matrix.mapRect(rect);float height = rect.height();float width = rect.width();float deltaX = 0, deltaY = 0;if (vertical) {if (height < windowsHeight) {deltaY = (windowsHeight - height) / 2 - rect.top;} else if (rect.top > 0) {deltaY = -rect.top;} else if (rect.bottom < windowsHeight) {deltaY = windowsHeight - rect.bottom;} else {deltaY = -(height - windowsHeight) / 2;}}if (horizontal) {if (width < windowsWidth) {deltaX = (windowsWidth - width) / 2 - rect.left;System.out.println(1);} else if (rect.left > 0) {deltaX = -rect.left;System.out.println(2);} else if (rect.right < windowsWidth) {deltaX = windowsWidth - rect.right;System.out.println(3);} else {deltaX = -(width - windowsWidth) / 2;}}matrix.postTranslate(deltaX, deltaY);}@Overrideprotected void onDestroy() {// TODO Auto-generated method stubsuper.onDestroy();SharedPreferences sp = getSharedPreferences("config",Context.MODE_PRIVATE);Editor ed = sp.edit();ed.putInt("page", curPage);ed.commit();}}


0 0
原创粉丝点击