android實(shí)現(xiàn)長(zhǎng)圖加載效果
長(zhǎng)圖加載要用到一個(gè)關(guān)鍵的類BitmapRegionDecoder,長(zhǎng)圖加載會(huì)使用到bitmap內(nèi)存復(fù)用, 比如view大小是440*654,圖片的寬高是440*12000,那么這個(gè)時(shí)候就要獲取圖片的寬和高, 跟view的寬和高進(jìn)行對(duì)比,獲取到一個(gè)縮小比例,那么會(huì)得到寬一個(gè)比例,高一個(gè)比例,用大的比例作為縮放因子,然后配合手勢(shì)滑動(dòng)滑動(dòng)長(zhǎ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();
//手勢(shì)
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();
}
/**
* 測(cè)量 view的大小
*
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//獲得測(cè)量的view的大小
mViewWidth = getMeasuredWidth();
mViewHeight = getMeasuredHeight();
//如果解碼器是null 表示沒(méi)有設(shè)置過(guò)要現(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);
}
/**
* 把圖片畫(huà)上去
*
* @param canvas
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 如果解碼器是null 表示沒(méi)有設(shè)置過(guò)要現(xiàn)實(shí)的圖片
if (null == mDecoder) {
return;
}
//復(fù)用上一張bitmap
Log.e(TAG,"復(fù)用上一張bitmap="+bitmap);
mOptions.inBitmap = bitmap;
//解碼指定區(qū)域
bitmap = mDecoder.decodeRegion(mRect, mOptions);
//使用矩陣 對(duì)圖片進(jìn)行 縮放
Matrix matrix = new Matrix();
matrix.setScale(mScale, mScale);
//畫(huà)出來(lái)
canvas.drawBitmap(bitmap, matrix, null);
}
/**
* 手指按下屏幕的回調(diào)
* @param e
* @return
*/
@Override
public boolean onDown(MotionEvent e) {
//如果滑動(dòng)還沒(méi)有停止 強(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) {
}
/**
* 手指 不離開(kāi)屏幕 拖動(dòng)
* @param e1 手指按下去 的事件 -- 獲取開(kāi)始的坐標(biāo)
* @param e2 當(dāng)前手勢(shì)事件 -- 獲取當(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;
}
/**
* 手指離開(kāi)屏幕 滑動(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)開(kāi)始的x坐標(biāo)
* startY: 滑動(dòng)開(kāi)始的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)畫(huà)未結(jié)束
if (mScroller.computeScrollOffset()){
//
mRect.top = mScroller.getCurrY();
mRect.bottom = mRect.top+ (int) (mViewHeight / mScale);
invalidate();
}
}
@Override
public boolean onTouch(View v, MotionEvent event) {
//交由手勢(shì)處理
return mGestureDetector.onTouchEvent(event);
}
}
如果是面試關(guān)鍵二點(diǎn),第一個(gè)要說(shuō)出來(lái)這個(gè)類,第二個(gè)要知道使用了內(nèi)存復(fù)用.
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android如何使用Glide加載清晰長(zhǎng)圖
- Android仿微博加載長(zhǎng)圖滾動(dòng)查看效果
- Android 官推 kotlin-first 的圖片加載庫(kù)——Coil的使用入門
- Android如何加載Base64編碼格式圖片
- Android Fresco圖片加載優(yōu)化的方案
- Android實(shí)現(xiàn)圖片加載進(jìn)度提示
- Android適配利用webview加載后圖片顯示過(guò)大的問(wèn)題解決
- Android框架Volley之利用Imageloader和NetWorkImageView加載圖片的方法
- Android框架Volley使用:ImageRequest請(qǐng)求實(shí)現(xiàn)圖片加載
- Android高效安全加載圖片的方法詳解
- Android加載長(zhǎng)圖的多種方案分享
相關(guān)文章
Android 通過(guò)API獲取數(shù)據(jù)庫(kù)中的圖片文件方式
這篇文章主要介紹了Android 通過(guò)API獲取數(shù)據(jù)庫(kù)中的圖片文件方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-03-03
Android 實(shí)現(xiàn)仿QQ拖拽氣泡效果的示例
這篇文章主要介紹了Android 實(shí)現(xiàn)仿QQ拖拽氣泡效果的示例,幫助大家更好的理解和學(xué)習(xí)使用Android,感興趣的朋友可以了解下2021-04-04
Android中Fragment多層嵌套時(shí)onActivityResult無(wú)法正確回調(diào)問(wèn)題的解決方法
這篇文章主要介紹了Android中Fragment多層嵌套時(shí)onActivityResult無(wú)法正確回調(diào)問(wèn)題的解決方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09
Android使用ViewDragHelper實(shí)現(xiàn)QQ聊天氣泡拖動(dòng)效果
這篇文章主要為大家詳細(xì)介紹了Android使用ViewDragHelper實(shí)現(xiàn)QQ聊天氣泡拖動(dòng)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01
Flutter有狀態(tài)組件StatefulWidget生命周期詳解
這篇文章主要為大家介紹了Flutter有狀態(tài)組件StatefulWidget生命周期詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
Android實(shí)現(xiàn)ListView分頁(yè)加載數(shù)據(jù)
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)ListView分頁(yè)加載數(shù)據(jù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-11-11
Android 動(dòng)態(tài)注冊(cè)監(jiān)聽(tīng)網(wǎng)絡(luò)變化實(shí)例詳解
這篇文章主要介紹了Android 動(dòng)態(tài)注冊(cè)監(jiān)聽(tīng)網(wǎng)絡(luò)變化實(shí)例詳解的相關(guān)資料,這里提供簡(jiǎn)單實(shí)例及實(shí)現(xiàn)效果圖,需要的朋友可以參考下2017-07-07
Android自定義View實(shí)現(xiàn)星星評(píng)分效果
這篇文章主要為大家詳細(xì)介紹了Android如何利用自定義View實(shí)現(xiàn)一個(gè)星星評(píng)分的控件,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以嘗試一下2022-11-11

