android中怎么实现长图加载效果
创始人
2024-12-22 10:23:53
0次

长图加载要用到一个关键的类BitmapRegionDecoder,长图加载会使用到bitmap内存复用, 比如view大小是440*654,图片的宽高是440*12000,那么这个时候就要获取图片的宽和高, 跟view的宽和高进行对比,获取到一个缩小比例,那么会得到宽一个比例,高一个比例,用大的比例作为缩放因子,然后配合手势滑动滑动长图

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);    //指定要加载的矩形区域    mRect = new Rect();    //解码图片的配置    mOptions = new BitmapFactory.Options();    //手势    mGestureDetector = new GestureDetector(context, this);    setOnTouchListener(this);    // 滑动帮助    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;    //复用 内存复用    mOptions.inMutable = true;    //设置像素格式为 rgb565    mOptions.inPreferredConfig = Bitmap.Config.RGB_565;    mOptions.inJustDecodeBounds = false;    //创建区域解码器 用于区域解码图片    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 表示没有设置过要现实的图片    if (null == mDecoder) {      return;    }    //确定要加载的图片的区域    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 表示没有设置过要现实的图片    if (null == mDecoder) {      return;    }    //复用上一张bitmap    Log.e(TAG,"复用上一张bitmap="+bitmap);    mOptions.inBitmap = bitmap;    //解码指定区域    bitmap = mDecoder.decodeRegion(mRect, mOptions);    //使用矩阵 对图片进行 缩放    Matrix matrix = new Matrix();    matrix.setScale(mScale, mScale);    //画出来     canvas.drawBitmap(bitmap, matrix, null);  }    /**   * 手指按下屏幕的回调   * @param e   * @return   */  @Override  public boolean onDown(MotionEvent e) {    //如果滑动还没有停止 强制停止    if (!mScroller.isFinished()){      mScroller.forceFinished(true);    }    //继续接收后续事件    return true;  }   @Override  public void onShowPress(MotionEvent e) {   }   @Override  public boolean onSingleTapUp(MotionEvent e) {    return false;  }    @Override  public void onLongPress(MotionEvent e) {   }   /**   * 手指 不离开屏幕 拖动   * @param e1 手指按下去 的事件 -- 获取开始的坐标   * @param e2 当前手势事件 -- 获取当前的坐标   * @param distanceX x轴 方向移动的距离   * @param distanceY y方向移动的距离   * @return   */  @Override  public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {    // 手指从下往上 图片也要往上 distanceY是负数, top 和 bottom 在减    // 手指从上往下 图片也要往下 distanceY是正数, top 和 bottom 在加    //改变加载图片的区域    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;  }   /**   * 手指离开屏幕 滑动 惯性   * @param e1   * @param e2   * @param velocityX 速度 每秒x方向 移动的像素   * @param velocityY y   * @return   */  @Override  public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {    /**     * startX: 滑动开始的x坐标     * startY: 滑动开始的y坐标     * 两个速度     * minX: x方向的最小值     * max 最大     * y     */    //计算器    mScroller.fling(0,mRect.top,        0,(int)-velocityY,        0,0,0,        mImageHeight - (int) (mViewHeight / mScale));    return false;  }   //获取计算结果并且重绘  @Override  public void computeScroll() {    //已经计算结束 return    if (mScroller.isFinished()){      return;    }    //true 表示当前动画未结束    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);  }}

相关内容

热门资讯

空调连续工作多久需要停机休息 空调连续工作的时间取决于多个因素,包括空调的型号、功率、使用环境和维护情况等。一般来说,空调可以连续...
空调哪个符号是除湿的 空调除湿功能通常用一个水滴形状的符号表示。不同品牌和型号的空调遥控器可能会有所差异,但一般来说,除湿...
格力空调多长时间加一次氟利昂 1、一般情况下,空调对氟利昂的使用量是非常小的,所以在空调使用了四年左右的时候再考虑加也没问题。2、...
空调用多长时间需要加氟一次 一般情况下是五年。当出现以下这几种情况时,空调才需要加氟。1、空调的室内机和室外机各有两个接口,当接...
格调生活·C标思享荟:卡萨帝在... 9月12日的郑州龙湖金融岛,夜风轻拂,灯光璀璨。“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑...
品牌价值破千亿、高端份额持续领... 9月12日,“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑州站”在郑州龙湖金融岛举办。2026...
空调主板坏了修800还是换新的 空调主板坏了是修还是换新,需要考虑多个因素,以下是一些建议:1. 维修成本:如果维修费用较低,比如 ...
空调开多久需要休息多长时间 问题:空调开多久需要休息多长时间回答:1、在使用空调的过程中,一般空调开7~8个小时左右需要休息2~...
中央空调多长时间清洗一次 1、一般空调开机前清洗一次即可,空调开机中间时段再清洗一次,空调关机时清洗一次,这样比较合理。2、空...
中央空调氟利昂多久加一次 看空调制热和制冷程度,很多人的观点认为氟利昂必须一年放一次,其实这个观点是错误的,理解上面有点偏差,...