超大图片显示,可任意缩放,移动,不用DiskLruCache
1.演示,代码
下载示例apk 下载项目 : https://gitee.com/xi/LImage.git

2.遇到的问题
- 想省内存,不太可能
- 只支持拖拽手势,不支持缩放相对简单,解码view对应的区域就可以。
- 不支持缩放好像说不过去,同时支持缩放+拖拽后变复杂,如转屏后的位置,指定锚点缩放,缩放后又移动,移动后又缩放。
- 用系统图库打开图片?直接打开超大图片不能正常显示.用图库打开图片所在目录?没有找到相关代码.
3.缩放,移动的思路
3.1 缩放思路
- 用一张解码区域是整张图片,但是inSampleSize大小适中的缩略图缩放.虽然图片是不清晰的,但是省内存,省解码时间.
- 缩小过程不需要高清的.
- 放大到100%的时候就重新解码当前view对应区域的位图,inSampleSize = 1 .
3.2 移动思路
- 当缩放比例小于100%时,就移动缩略图,
- 当缩放比例等于100%时,按当前view区域大小平移,重新解码对应的位图.
4.核心代码
4.1 解码
- BitmapRegionDecoder 可以指定一个区域(大图范围内,超出会抛异常)对一张大位图解码,解出一张小位图.然后在view上显示这个小位图.
- BitmapFactory.Options 解码选项,下面是常用的几个重要选项:
| inSampleSize | 缩略大小,值为2的n次幂(n为自然数).其它值无意义 |
|
inPreferredConfig |
色彩模式,决定一个像素占用的字节数 |
|
inBitmap |
指定复用的位图..不用在申请内存. |
- 代码
private BitmapRegionDecoder mDecoder;
private BitmapFactory.Options mOptions;
private Rect mDecodeRegion;
void initRegionDecoder(){
try {
InputStream fs = getResources().getAssets().open("world_map.jpg");
mDecoder = BitmapRegionDecoder.newInstance(fs,false);
mBitmapWidth = mDecoder.getWidth();
mBitmapHeight = mDecoder.getHeight();
mOptions = new BitmapFactory.Options();
mOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
mOptions.inSampleSize = ;
} catch (IOException e) {
e.printStackTrace();
}
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//...
mDecodeRegion = new Rect(left,top,left + viewWidth ,top + viewHeight );
// mDecodeRegion = new Rect(0,0,mBitmapWidth ,mBitmapHeight);
mOptions.inSampleSize = calculateInSampleSize(mDecodeRegion.width(),mDecodeRegion.height(),viewWidth,viewHeight);
// mOptions.inSampleSize = 2;
long begin,end;
begin = SystemClock.elapsedRealtime();
mBitmap = mDecoder.decodeRegion(mDecodeRegion,mOptions);
end = SystemClock.elapsedRealtime();
//..
}
4.2 手势
- ScaleGestureDetector 缩放手势识别器
- GestureDetectorCompat 移动手势识别器
这两个比较简单,先构造,然后在 public boolean onTouchEvent(MotionEvent event) 里接收触摸事件,最后在相应的手势回调方法处理手势就可以.
4.3 变形
缩放: 用变形矩阵.小于100%时移动也用变形矩阵,等于100%时自己计算.
@Override
protected void onDraw(Canvas canvas) {
if (mPercentage < 100.0f && mThumbnailBitmap != null){
canvas.drawBitmap(mThumbnailBitmap,mMatrix,mPaint);
}else if(mPercentage == 100.0f && mBitmap != null){
canvas.drawBitmap(mBitmap,mBitmapLeft,mBitmapTop,mPaint);
}
//...
}
4.4 LargeImageView.java
package com.example.ff.limage;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapRegionDecoder;
import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.AsyncTask;
import android.os.Environment;
import android.os.Parcelable;
import android.os.SystemClock;
import android.support.annotation.Nullable;
import android.support.v4.view.GestureDetectorCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import static android.os.Environment.isExternalStorageRemovable;
public class LargeImageView extends View {
private String TAG = "LargeImageView";
private Paint mPaint;
private BitmapRegionDecoder mDecoder;
private BitmapFactory.Options mOptions;
private Rect mDecodeRegion;
private static Bitmap mThumbnailBitmap;
private Bitmap mBitmap;
private Matrix mMatrix;
private float thumbnailWidth,thumbnailHeight;
private float mPercentage;
private float mThumbnailLeft,mThumbnailTop,mBitmapLeft,mBitmapTop;
private int mBitmapWidth,mBitmapHeight;
private Point mFocus;
private boolean mScaling = false;
private DiskLruCache mDiskLruCache;
public void destroyBitmaps(){
Log.e(TAG, "destroyBitmaps: release bitmaps" );
if (!mDecoder.isRecycled()) {
mDecoder.recycle();
}
if (!mBitmap.isRecycled()){
mBitmap.recycle();
mBitmap = null;
}
}
public void destroyThumbnailBitmap(){
if (!mThumbnailBitmap.isRecycled()){
mThumbnailBitmap.recycle();
mThumbnailBitmap = null;
}
}
public void createThumbnailBitmap(){
if (null == mThumbnailBitmap){
DecodeTask task = new DecodeTask();
task.execute(mDecodeRegion);
}
}
public void createBitmaps(){
}
private class DecodeTask extends AsyncTask<Rect,Void,Void>{
@Override
protected Void doInBackground(Rect... rects) {
Log.e(TAG, "doInBackground: " );
long begin,end;
mDecodeRegion = ,,mBitmapWidth,mBitmapHeight);
mOptions.inSampleSize = ;
begin = SystemClock.elapsedRealtime();
mThumbnailBitmap = mDecoder.decodeRegion(mDecodeRegion,mOptions);
end = SystemClock.elapsedRealtime();
Log.e(TAG, "doInBackground: decode mThumbnailBitmap need " + (end - begin) + " ms. " );
return null;
}
}
@Override
protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
}
// 打印Matrix内数据
void showMatrix(Matrix matrix,String tag){
// 下面的代码是为了查看matrix中的元素
];
matrix.getValues(matrixValues);
String temp ;
; i < ; ++i) {
temp = "";
; j < ; ++j) {
temp += matrixValues[ * i + j] + "\t";
}
Log.e(tag, temp);
}
}
private void printThumbnailRect(){
float left = mThumbnailLeft;
float top = mThumbnailTop;
float right = mThumbnailLeft + thumbnailWidth;
float bottom = mThumbnailTop + thumbnailHeight;
Log.e(TAG, "printThumbnailRect: left = " + left + " top = " + top + " right = " + right + " bottom = " + bottom
+ " width = " + thumbnailWidth + " height = " + thumbnailHeight);
}
private ScaleGestureDetector scaleDetector;
private ScaleGestureDetector.SimpleOnScaleGestureListener scaleGestureListener = new ScaleGestureDetector.SimpleOnScaleGestureListener() {
@Override
public boolean onScale(ScaleGestureDetector detector) {
float factor = detector.getScaleFactor();
) return true;
&& factor > ){
return true;
}
if (thumbnailWidth * factor < mBitmapWidth){
if (thumbnailWidth * factor >= mBitmapWidth * 0.01f){
thumbnailWidth *= factor;
thumbnailHeight *= factor;
mMatrix.postScale(factor,factor,detector.getFocusX(),detector.getFocusY());
}
}else{
factor = mBitmapWidth / thumbnailWidth;
mMatrix.postScale(factor,factor,detector.getFocusX(),detector.getFocusY());
thumbnailWidth = mBitmapWidth;
thumbnailHeight = mBitmapHeight;
mPercentage = 100.0f;
];
mMatrix.getValues(matrix);
mThumbnailLeft = matrix[];
mThumbnailTop = matrix[];
float left = mThumbnailLeft;
float top = mThumbnailTop;
float right = mThumbnailLeft + thumbnailWidth;
float bottom = mThumbnailTop + thumbnailHeight;
int viewWith = getWidth();
int viewHeight = getHeight();
mBitmapLeft = ;
mBitmapTop = ;
){
mBitmapLeft = left;
mDecodeRegion.left = ;
mDecodeRegion.right = (int) (viewWith - left);
){
mBitmapTop = top;
mDecodeRegion.top = ;
mDecodeRegion.bottom = (int) (viewHeight - top);
}else if(bottom < viewHeight){
mDecodeRegion.bottom = mBitmapHeight;
mDecodeRegion.top = (int) (mBitmapHeight - bottom);
}else {
mDecodeRegion.top = (int) -top;
mDecodeRegion.bottom = mDecodeRegion.top + viewHeight;
}
}){
mBitmapTop = top;
mDecodeRegion.top = ;
mDecodeRegion.bottom = (int) (viewHeight - top);
if (right < viewWith){
mDecodeRegion.right = mBitmapWidth;
mDecodeRegion.left = (int) (mBitmapWidth - right);
}else{
mDecodeRegion.left = (int) -left;
mDecodeRegion.right = mDecodeRegion.left + viewWith;
}
}else if(right < viewWith ){
mDecodeRegion.right = mBitmapWidth;
mDecodeRegion.left = (int) (mBitmapWidth - right);
if(bottom < viewHeight){
mDecodeRegion.bottom = mBitmapHeight;
mDecodeRegion.top = (int) (mBitmapHeight - bottom);
}else{
mDecodeRegion.top = (int) -top;
mDecodeRegion.bottom = mDecodeRegion.top + viewHeight;
}
}else if(bottom < viewHeight){
mDecodeRegion.left = (int) -left;
mDecodeRegion.right = mDecodeRegion.left + viewWith;
mDecodeRegion.bottom = mBitmapHeight;
mDecodeRegion.top = (int) (mBitmapHeight - bottom);
}else{
mDecodeRegion.left = (int) -left;
mDecodeRegion.right = mDecodeRegion.left + viewWith;
mDecodeRegion.top = (int) -top;
mDecodeRegion.bottom = mDecodeRegion.top + viewHeight;
}
mOptions.inSampleSize = ;
&& mDecodeRegion.height() > ){
mBitmap = mDecoder.decodeRegion(mDecodeRegion,mOptions);
}else{
if (mBitmap != null && !mBitmap.isRecycled()){
mBitmap.recycle();
mBitmap = null;
}
}
}
BigDecimal bd = ).setScale(,BigDecimal.ROUND_HALF_UP);
mPercentage = bd.floatValue();
Log.i(TAG, "onScale: bitmap.w = " + mThumbnailBitmap.getWidth() + " bitmap.h = " + mThumbnailBitmap.getHeight()
+ " thumbnailWidth = " + thumbnailWidth + " thumbnailHeight = " + thumbnailHeight);
invalidate();
return true;
}
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
mScaling = true;
float focusX = detector.getFocusX();
float focusY = detector.getFocusY();
mFocus = new Point((int)focusX,(int)focusY);
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector detector) {
mScaling = false;
mFocus = null;
super.onScaleEnd(detector);
}
};
private GestureDetectorCompat scrollDetector;
private GestureDetector.SimpleOnGestureListener simpleOnGestureListener = new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
&& Math.abs(distanceY) < ) return true;
];
mMatrix.getValues(matrix);
mThumbnailLeft = matrix[];
mThumbnailTop = matrix[];
int viewWith = getWidth();
int viewHeight = getHeight();
if (mThumbnailLeft <= viewWith && mThumbnailLeft >= -thumbnailWidth
&& mThumbnailTop <= viewHeight && mThumbnailTop >= -thumbnailHeight){
&& viewWith - mThumbnailLeft < -distanceX){
distanceX = -(viewWith - mThumbnailLeft);
} && mThumbnailLeft + thumbnailWidth < distanceX){
distanceX = mThumbnailLeft + thumbnailWidth;
}
&& viewHeight - mThumbnailTop < -distanceY){
distanceY = -(viewHeight - mThumbnailTop);
} && mThumbnailTop + thumbnailHeight < distanceY){
distanceY = mThumbnailTop + thumbnailHeight;
}
mMatrix.postTranslate(-distanceX,-distanceY);
if (mPercentage == 100.0f){
mMatrix.getValues(matrix);
mThumbnailLeft = matrix[];
mThumbnailTop = matrix[];
float left = mThumbnailLeft;
float top = mThumbnailTop;
float right = mThumbnailLeft + thumbnailWidth;
float bottom = mThumbnailTop + thumbnailHeight;
mBitmapLeft = ;
mBitmapTop = ;
){
mBitmapLeft = left;
mDecodeRegion.left = ;
mDecodeRegion.right = (int) (viewWith - left);
){
mBitmapTop = top;
mDecodeRegion.top = ;
mDecodeRegion.bottom = (int) (viewHeight - top);
}else if(bottom < viewHeight){
mDecodeRegion.bottom = mBitmapHeight;
mDecodeRegion.top = (int) (mBitmapHeight - bottom);
}else {
mDecodeRegion.top = (int) -top;
mDecodeRegion.bottom = mDecodeRegion.top + viewHeight;
}
}){
mBitmapTop = top;
mDecodeRegion.top = ;
mDecodeRegion.bottom = (int) (viewHeight - top);
if (right < viewWith){
mDecodeRegion.right = mBitmapWidth;
mDecodeRegion.left = (int) (mBitmapWidth - right);
}else{
mDecodeRegion.left = (int) -left;
mDecodeRegion.right = mDecodeRegion.left + viewWith;
}
}else if(right < viewWith ){
mDecodeRegion.right = mBitmapWidth;
mDecodeRegion.left = (int) (mBitmapWidth - right);
if(bottom < viewHeight){
mDecodeRegion.bottom = mBitmapHeight;
mDecodeRegion.top = (int) (mBitmapHeight - bottom);
}else{
mDecodeRegion.top = (int) -top;
mDecodeRegion.bottom = mDecodeRegion.top + viewHeight;
}
}else if(bottom < viewHeight){
mDecodeRegion.left = (int) -left;
mDecodeRegion.right = mDecodeRegion.left + viewWith;
mDecodeRegion.bottom = mBitmapHeight;
mDecodeRegion.top = (int) (mBitmapHeight - bottom);
}else{
mDecodeRegion.left = (int) -left;
mDecodeRegion.right = mDecodeRegion.left + viewWith;
mDecodeRegion.top = (int) -top;
mDecodeRegion.bottom = mDecodeRegion.top + viewHeight;
}
mOptions.inSampleSize = ;
Log.e(TAG, "onScroll: mDecodeRegion = " + mDecodeRegion );
&& mDecodeRegion.height() > ){
mBitmap = mDecoder.decodeRegion(mDecodeRegion,mOptions);
}else{
mBitmap = null;
}
}
invalidate();
}
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
return true;
}
};
private void initGestureDetector() {
scrollDetector = new GestureDetectorCompat(getContext(), simpleOnGestureListener);
scaleDetector = new ScaleGestureDetector(getContext(), scaleGestureListener);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean ret = scaleDetector.onTouchEvent(event);
ret |= scrollDetector.onTouchEvent(event);
return ret || true;
}
* * ; // 256MB
private static final String DISK_CACHE_SUBDIR = "thumbnails";
void initCache(){
try {
Context context = getContext();
File cacheDir = context.getCacheDir();
cacheDir = context.getExternalCacheDir();
final String cachePath = Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) ||!isExternalStorageRemovable()
? context.getExternalCacheDir().getPath()
: context.getCacheDir().getPath();
cacheDir = new File(cachePath + File.separator + DISK_CACHE_SUBDIR);
PackageManager pm = context.getPackageManager();
PackageInfo pi = pm.getPackageInfo(context.getPackageName(), );
int appVersion = pi.versionCode;
;
mDiskLruCache = DiskLruCache.open(cacheDir, appVersion,valueCount,DISK_CACHE_SIZE);
} catch (IOException e) {
e.printStackTrace();
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}
void init(){
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setTextSize();
setLayerType(View.LAYER_TYPE_SOFTWARE,mPaint);
// LinearGradient backGradient = new LinearGradient(0, 0, 0, mPaint.getTextSize(), new int[]{Color.BLACK, Color.GRAY ,Color.YELLOW}, null, Shader.TileMode.CLAMP);
// mPaint.setShader(backGradient);
mMatrix = new Matrix();
// initCache();
initGestureDetector();
initRegionDecoder();
}
void initRegionDecoder(){
try {
InputStream fs = getResources().getAssets().open("world_map.jpg");
mDecoder = BitmapRegionDecoder.newInstance(fs,false);
mBitmapWidth = mDecoder.getWidth();
mBitmapHeight = mDecoder.getHeight();
mOptions = new BitmapFactory.Options();
mOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
mOptions.inSampleSize = ;
} catch (IOException e) {
e.printStackTrace();
}
}
private void getAttrs(Context context, AttributeSet attrs) {
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.LargeImageViewAttrs);
String file = ta.getString(R.styleable.LargeImageViewAttrs_src);
ta.recycle();
}
public LargeImageView(Context context) {
super(context);
init();
}
public LargeImageView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
getAttrs(context,attrs);
init();
}
public LargeImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
getAttrs(context,attrs);
init();
}
@SuppressLint("NewApi")
public LargeImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
getAttrs(context,attrs);
init();
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
super.onRestoreInstanceState(state);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
}
public static int calculateInSampleSize(int width, int height, int reqWidth, int reqHeight) {
// Raw height and width of image
;
if (height > reqHeight || width > reqWidth) {
final ;
final ;
|| halfWidth <= ) return inSampleSize;
if (width > height) {
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfWidth / inSampleSize) >= reqWidth) {
inSampleSize *= ;
}
} else {
while ((halfHeight / inSampleSize) >= reqHeight) {
inSampleSize *= ;
}
}
}
return inSampleSize;
}
@Override
protected void onDraw(Canvas canvas) {
if (mPercentage < 100.0f && mThumbnailBitmap != null){
canvas.drawBitmap(mThumbnailBitmap,mMatrix,mPaint);
}else if(mPercentage == 100.0f && mBitmap != null){
canvas.drawBitmap(mBitmap,mBitmapLeft,mBitmapTop,mPaint);
}
if (mFocus != null){
mPaint.setColor(Color.RED);
mPaint.setMaskFilter(, BlurMaskFilter.Blur.SOLID));
mPaint.setColor(Color.parseColor("#ff0000"));
canvas.drawCircle(mFocus.x,mFocus.y,,mPaint);
}
//draw percentage
String percentage = mPercentage + "%";
float textSize = mPaint.getTextSize();
float percentWidth = mPaint.measureText("100.0%");
float circleX = getWidth() - percentWidth ;
float circleY = percentWidth ;
mPaint.setColor(Color.parseColor("#7f7A378B"));
mPaint.setMaskFilter(, BlurMaskFilter.Blur.NORMAL));
canvas.drawCircle(circleX ,circleY,percentWidth * 0.66f,mPaint);
mPaint.setColor(Color.WHITE);
mPaint.setMaskFilter(null);
percentWidth = mPaint.measureText(percentage);
circleY += textSize / ;
circleX -= percentWidth / ;
canvas.drawText(percentage,circleX ,circleY,mPaint);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Log.e(TAG, "onMeasure: " );
int viewWidth = getPaddingLeft() + getPaddingRight() + getSuggestedMinimumWidth();
) viewWidth = ;
viewWidth = resolveSizeAndState(viewWidth, widthMeasureSpec, );
int viewHeight = getSuggestedMinimumHeight() + getPaddingBottom() + getPaddingTop();
) viewHeight = ;
//计算最佳值,在其中解析了 heightMeasureSpec
viewHeight = resolveSizeAndState(viewHeight, heightMeasureSpec, );
//将量算的结果保存到View的成员变量mMeasuredWidth 和mMeasuredHeight中。
setMeasuredDimension(viewWidth, viewHeight);
// 量算完成之后,View的父控件就可以通过调用
// getMeasuredWidth、getMeasuredState、getMeasuredWidthAndState
// 这三个方法获取View的量算结果。
mBitmapLeft = ;
mBitmapTop = ;
- viewWidth / ;
- viewHeight / ;
mDecodeRegion = new Rect(left,top,left + viewWidth ,top + viewHeight );
// mDecodeRegion = new Rect(0,0,mBitmapWidth ,mBitmapHeight);
mOptions.inSampleSize = calculateInSampleSize(mDecodeRegion.width(),mDecodeRegion.height(),viewWidth,viewHeight);
// mOptions.inSampleSize = 2;
long begin,end;
begin = SystemClock.elapsedRealtime();
mBitmap = mDecoder.decodeRegion(mDecodeRegion,mOptions);
end = SystemClock.elapsedRealtime();
thumbnailWidth = mBitmapWidth;
thumbnailHeight = mBitmapHeight;
BigDecimal bd = ).setScale(,BigDecimal.ROUND_HALF_UP);
mPercentage = bd.floatValue();
Log.e(TAG, "init region = " + mDecodeRegion + " ratio = " + (float) mDecodeRegion.width() / mDecodeRegion.height()
+ " bitmap.w = " + mBitmap.getWidth() + " bitmap.h = " + mBitmap.getHeight() + " ratio = " + (float) mBitmap.getWidth() / mBitmap.getHeight()
+ " need " + (end - begin) + " ms");
if (mThumbnailBitmap != null){
Log.e(TAG, "onMeasure : mThumbnailBitmap is ok.");
float width = mThumbnailBitmap.getWidth();
float height = mThumbnailBitmap.getHeight();
- width / ;
- height / ;
mMatrix.setTranslate(dx,dy);
float factor = mBitmapWidth / width;
mMatrix.postScale(factor,factor,viewWidth/ ,viewHeight /);
}
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
Log.e(TAG, "onFinishInflate: " );
createThumbnailBitmap();
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
Log.e(TAG, "onAttachedToWindow: " );
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
Log.e(TAG, "onDetachedFromWindow: " );
}
@Override
protected void onWindowVisibilityChanged(int visibility) {
super.onWindowVisibilityChanged(visibility);
Log.e(TAG, "onWindowVisibilityChanged : " + visibility);
}
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
Log.e(TAG, "onWindowFocusChanged: hasWindowFocus = " + hasWindowFocus );
}
Bitmap loadBitmapFromCache(String key){
Bitmap bitmap = null;
try {
DiskLruCache.Snapshot snapshot = mDiskLruCache.get(key);
if (snapshot != null) {
InputStream );
bitmap = BitmapFactory.decodeStream(is);
}
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
}
void pushToCache(String key, Bitmap value){
try {
DiskLruCache.Editor editor = mDiskLruCache.edit(key);
if (editor != null){
OutputStream );
value.compress(Bitmap.CompressFormat.JPEG, , out);
out.flush();
editor.commit();
mDiskLruCache.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
超大图片显示,可任意缩放,移动,不用DiskLruCache的更多相关文章
- JS控制图片显示的大小(图片等比例缩放)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- Java图片工具类,完成图片的截取和任意缩放
package com.common.util; import java.awt.Graphics2D; import java.awt.Image; import java.awt.Renderin ...
- 【JS控制图片显示的大小(图片等比例缩放)】
效果: 代码: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www ...
- C++对于大型图片的加载缩放尝试
Qt对于图片的操作主要集中在这几个类 QImage ,QImageReader ,QPixmap 其中QImage这个类对图片的缩放有几个很不错的技巧,不过对于大图片却并不好使,当我们去看QImage ...
- C#图片处理示例(裁剪,缩放,清晰度,水印)
C#图片处理示例(裁剪,缩放,清晰度,水印) 吴剑 2011-02-20 原创文章,转载必需注明出处:http://www.cnblogs.com/wu-jian/ 前言 需求源自项目中的一些应用,比 ...
- wpf图片浏览器,实现缩放平移操作图片切换等功能
wpf经常要用到控件来查看图片,尤其是高清图片,于是做了一个例子: 1.定义图片的队列,用list来存. private readonly List<string> files; 2.切换 ...
- 实现图片的2次缩放后再进行candy边缘检测
//实现图片的2次缩放后再进行candy边缘检测//Author:SD//Date:2015-9-27#include "cv.h"#include "highgui.h ...
- VS2010 MFC GDI+ 实现PNG透明图片显示
网上找了一些资料学习了一下PNG图的显示,这里总结一下. 参考:http://blog.csdn.net/czyt1988/article/details/7965066 一.VS2010配置GDI+ ...
- 蚂蚁代理免费代理ip爬取(端口图片显示+token检查)
分析 蚂蚁代理的列表页大致是这样的: 端口字段使用了图片显示,并且在图片上还有各种干扰线,保存一个图片到本地用画图打开观察一下: 仔细观察蓝色的线其实是在黑色的数字下面的,其它的干扰线也是,所以这幅图 ...
随机推荐
- RegularExpression
目录 文章背景 目录 概述 基本概念 目的 特点 符号 实例 说明 参考文章 版本记录 layout: default title: RegularExpression category: [Tech ...
- 编写高质量代码改善C#程序的157个建议——建议157:从写第一个界面开始,就进行自动化测试
建议157:从写第一个界面开始,就进行自动化测试 如果说单元测试是白盒测试,那么自动化测试就是黑盒测试.黑盒测试要求捕捉界面上的控件句柄,并对其进行编码,以达到模拟人工操作的目的.具体的自动化测试请学 ...
- 重叠IO
一. 异步IO 说到重叠模型首先还是提一下异步IO比较好,因为从本质上讲,重叠模型也是一种异步IO模型. 我们知道,相对于计算机执行的其他操作而言,设备IO(文件.管道.套接 ...
- apache mina2.0源码解析(一)
apache mina是一个基于java nio的网络通信框架,为TCP UDP ARP等协议提供了一致的编程模型:其源码结构展示了优秀的设计案例,可以为我们的编程事业提供参考. 依照惯例,首先搭建a ...
- 通过python实现wc基本功能
---恢复内容开始--- 1.Github项目地址: https://github.com/zhg1998/ww/blob/master/wc.py 2.项目相关要求: 写一个命令行程序,模仿已有wc ...
- mysql按照天或小时group分组统计
select DATE_FORMAT( deteline, "%Y-%m-%d %H" ) , COUNT( * ) FROM test GROUP BY DATE_FORMAT( ...
- MacOS安装使用Node.js
1. 到官网https://nodejs.org/zh-cn/download/下载,选择Macintosh Installer, 如下: 2. 按预设的下一步,Node.js版本为v6.10.0, ...
- NLP常用开源/免费工具
一些常见的NLP任务的开源/免费工具, *Computational Linguistics ToolboxCLT http://complingone.georgetown.edu/~linguis ...
- win10 git 报错 Host key verification failed
从code.aliyun.com切回github 原先的known_hosts里记录的是code.aliyun.com的ip,必须新加一个github的. known_hosts报错Host key ...
- C#多线程学习(三) 生产者和消费者
前面说过,每个线程都有自己的资源,但是代码区是共享的,即每个线程都可以执行相同的函数.这可能带来的问题就是几个线程同时执行一个函数,导致数据的混乱,产生不可预料的结果,因此我们必须避免这种情况的发生. ...