android實(shí)現(xiàn)長圖加載效果
長圖加載要用到一個(gè)關(guān)鍵的類BitmapRegionDecoder,長圖加載會(huì)使用到bitmap內(nèi)存復(fù)用, 比如view大小是440*654,圖片的寬高是440*12000,那么這個(gè)時(shí)候就要獲取圖片的寬和高, 跟view的寬和高進(jìn)行對比,獲取到一個(gè)縮小比例,那么會(huì)得到寬一個(gè)比例,高一個(gè)比例,用大的比例作為縮放因子,然后配合手勢滑動(dòng)滑動(dòng)長圖
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapRegionDecoder;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Scroller;
import java.io.IOException;
import java.io.InputStream;
public class BigView extends View implements GestureDetector.OnGestureListener, View.OnTouchListener {
private static final String TAG = "BigView";
private Scroller mScroller;
private GestureDetector mGestureDetector;
private BitmapFactory.Options mOptions;
private Rect mRect;
private int mImageWidth;
private int mImageHeight;
private BitmapRegionDecoder mDecoder;
private int mViewWidth;
private int mViewHeight;
private float mScale;
private Bitmap bitmap;
public BigView(Context context) {
this(context, null, 0);
}
public BigView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public BigView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//指定要加載的矩形區(qū)域
mRect = new Rect();
//解碼圖片的配置
mOptions = new BitmapFactory.Options();
//手勢
mGestureDetector = new GestureDetector(context, this);
setOnTouchListener(this);
// 滑動(dòng)幫助
mScroller = new Scroller(context);
}
/**
* 由使用者輸入一張圖片 輸入流
*
* @param is
*/
public void setImage(InputStream is) {
//先讀取原圖片的 寬、高
mOptions.inJustDecodeBounds = true;
BitmapFactory.decodeStream(is, null, mOptions);
mImageWidth = mOptions.outWidth;
mImageHeight = mOptions.outHeight;
//復(fù)用 內(nèi)存復(fù)用
mOptions.inMutable = true;
//設(shè)置像素格式為 rgb565
mOptions.inPreferredConfig = Bitmap.Config.RGB_565;
mOptions.inJustDecodeBounds = false;
//創(chuàng)建區(qū)域解碼器 用于區(qū)域解碼圖片
try {
mDecoder = BitmapRegionDecoder.newInstance(is, false);
} catch (IOException e) {
e.printStackTrace();
}
requestLayout();
}
/**
* 測量 view的大小
*
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//獲得測量的view的大小
mViewWidth = getMeasuredWidth();
mViewHeight = getMeasuredHeight();
//如果解碼器是null 表示沒有設(shè)置過要現(xiàn)實(shí)的圖片
if (null == mDecoder) {
return;
}
//確定要加載的圖片的區(qū)域
mRect.left = 0;
mRect.top = 0;
mRect.right = mImageWidth;
// Log.e(TAG,"縮放因子="+(mViewWidth*1.0f/mImageWidth*1.0f));
// Log.e(TAG,"縮放因子="+(mViewHeight*1.0f/mImageHeight*1.0f));
//獲得縮放因子
mScale = mViewWidth / (float) mImageWidth;
// 需要加載的高 * 縮放因子 = 視圖view的高
// x * mScale = mViewHeight
mRect.bottom = (int) (mViewHeight / mScale);
Log.e(TAG,"l="+mRect.left);
Log.e(TAG,"t="+mRect.top);
Log.e(TAG,"r="+mRect.right);
Log.e(TAG,"b="+mRect.bottom);
}
/**
* 把圖片畫上去
*
* @param canvas
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 如果解碼器是null 表示沒有設(shè)置過要現(xiàn)實(shí)的圖片
if (null == mDecoder) {
return;
}
//復(fù)用上一張bitmap
Log.e(TAG,"復(fù)用上一張bitmap="+bitmap);
mOptions.inBitmap = bitmap;
//解碼指定區(qū)域
bitmap = mDecoder.decodeRegion(mRect, mOptions);
//使用矩陣 對圖片進(jìn)行 縮放
Matrix matrix = new Matrix();
matrix.setScale(mScale, mScale);
//畫出來
canvas.drawBitmap(bitmap, matrix, null);
}
/**
* 手指按下屏幕的回調(diào)
* @param e
* @return
*/
@Override
public boolean onDown(MotionEvent e) {
//如果滑動(dòng)還沒有停止 強(qiáng)制停止
if (!mScroller.isFinished()){
mScroller.forceFinished(true);
}
//繼續(xù)接收后續(xù)事件
return true;
}
@Override
public void onShowPress(MotionEvent e) {
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
@Override
public void onLongPress(MotionEvent e) {
}
/**
* 手指 不離開屏幕 拖動(dòng)
* @param e1 手指按下去 的事件 -- 獲取開始的坐標(biāo)
* @param e2 當(dāng)前手勢事件 -- 獲取當(dāng)前的坐標(biāo)
* @param distanceX x軸 方向移動(dòng)的距離
* @param distanceY y方向移動(dòng)的距離
* @return
*/
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
// 手指從下往上 圖片也要往上 distanceY是負(fù)數(shù), top 和 bottom 在減
// 手指從上往下 圖片也要往下 distanceY是正數(shù), top 和 bottom 在加
//改變加載圖片的區(qū)域
mRect.offset(0, (int) distanceY);
//bottom大于圖片高了, 或者 top小于0了
if (mRect.bottom > mImageHeight){
mRect.bottom = mImageHeight;
mRect.top = mImageHeight-(int) (mViewHeight / mScale);
}
if (mRect.top < 0){
mRect.top = 0;
mRect.bottom = (int) (mViewHeight / mScale);
}
//重繪
invalidate();
return false;
}
/**
* 手指離開屏幕 滑動(dòng) 慣性
* @param e1
* @param e2
* @param velocityX 速度 每秒x方向 移動(dòng)的像素
* @param velocityY y
* @return
*/
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
/**
* startX: 滑動(dòng)開始的x坐標(biāo)
* startY: 滑動(dòng)開始的y坐標(biāo)
* 兩個(gè)速度
* minX: x方向的最小值
* max 最大
* y
*/
//計(jì)算器
mScroller.fling(0,mRect.top,
0,(int)-velocityY,
0,0,0,
mImageHeight - (int) (mViewHeight / mScale));
return false;
}
//獲取計(jì)算結(jié)果并且重繪
@Override
public void computeScroll() {
//已經(jīng)計(jì)算結(jié)束 return
if (mScroller.isFinished()){
return;
}
//true 表示當(dāng)前動(dòng)畫未結(jié)束
if (mScroller.computeScrollOffset()){
//
mRect.top = mScroller.getCurrY();
mRect.bottom = mRect.top+ (int) (mViewHeight / mScale);
invalidate();
}
}
@Override
public boolean onTouch(View v, MotionEvent event) {
//交由手勢處理
return mGestureDetector.onTouchEvent(event);
}
}
如果是面試關(guān)鍵二點(diǎn),第一個(gè)要說出來這個(gè)類,第二個(gè)要知道使用了內(nèi)存復(fù)用.
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android如何使用Glide加載清晰長圖
- Android仿微博加載長圖滾動(dòng)查看效果
- Android 官推 kotlin-first 的圖片加載庫——Coil的使用入門
- Android如何加載Base64編碼格式圖片
- Android Fresco圖片加載優(yōu)化的方案
- Android實(shí)現(xiàn)圖片加載進(jìn)度提示
- Android適配利用webview加載后圖片顯示過大的問題解決
- Android框架Volley之利用Imageloader和NetWorkImageView加載圖片的方法
- Android框架Volley使用:ImageRequest請求實(shí)現(xiàn)圖片加載
- Android高效安全加載圖片的方法詳解
- Android加載長圖的多種方案分享
相關(guān)文章
Android 自定義輸入支付密碼的軟鍵盤實(shí)例代碼
這篇文章主要介紹了Android 自定義輸入支付密碼的軟鍵盤實(shí)例代碼的相關(guān)資料,并附簡單實(shí)例代碼和實(shí)現(xiàn)效果圖,需要的朋友可以參考下2016-11-11
ANDROID中使用VIEWFLIPPER類實(shí)現(xiàn)屏幕切換(關(guān)于坐標(biāo)軸的問題已補(bǔ)充更改)
本篇文章主要介紹了ANDROID中使用VIEWFLIPPER類實(shí)現(xiàn)屏幕切換,具有一定的參考價(jià)值,有興趣的可以了解一下。2016-11-11
android閃關(guān)燈的開啟和關(guān)閉方法代碼實(shí)例
這篇文章主要介紹了android閃關(guān)燈的開啟和關(guān)閉方法代碼實(shí)例,本文直接給出代碼和配置實(shí)例,需要的朋友可以參考下2015-05-05
Android12?藍(lán)牙適配的實(shí)現(xiàn)步驟
本文主要介紹了Android12?藍(lán)牙適配的實(shí)現(xiàn)步驟,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04
Android EasyPermissions官方庫高效處理權(quán)限相關(guān)教程
Easypermissions簡化了Android M的運(yùn)行時(shí)權(quán)限的申請、結(jié)果處理、判斷等步驟。這篇文章主要介紹了Android EasyPermissions官方庫高效處理權(quán)限相關(guān)教程,需要的朋友可以參考下2017-11-11

