美文网首页
Andoird-APP长图加载的处理方案

Andoird-APP长图加载的处理方案

作者: 信仰年輕 | 来源:发表于2021-08-12 15:06 被阅读0次

    本文目标

    Andoird-APP长图加载的处理方案,可以拿来即用

    思路

    我们可以自己写个自定义View继承自View,想想都需要怎么做?
    当这个自定义view初始化的时候

    • 1.我们需要创建个Rect指定要加载的区域,这个rect和手机屏幕一样宽高
    • 2.需要复用图片
    • 2.需要手势识别,在这rect区域上面添加GestureDetector手势,可以自由的滑动

    调用者从外面传入一张巨图,需要转成InputStream

    • 1.我们要读取原图片的信息高和宽
    • 2.创建一个区域解码器去解析这个InputStream
    • 3.调用requestLayout();开启View的测量,绘制

    重写onMeasure(),在测量的时候把我们需要的内存区域获取到 存入到Rect区域中

    • 1.获取测量的view的大小
    • 2.确定要加载的图片的区域

    重写onDraw(),画出内容

    重写onTouch()``onDown(),onScroll()等等方法来处理相关手势

    具体的代码BigView

    /**
     * Author: 信仰年轻
     * Date: 2019-06-12 18:07
     * Email: hydznsqk@163.com
     * Des: 大图加载
     *
     *   写个BigView自定义View继承View
     *       在其构造方法中
     *       1.使用rect指定要加载的区域,这个rect和手机屏幕一样宽高
     *       2.需要复用图片
     *       3.需要手势识别,在这rect区域上面添加GestureDetector手势,可以滑动
     *
     *   由调用者从外面传入一张巨图,需要转成IO流
     *       1.先读取原图片的信息   高,宽
     *       2.创建一个区域解码器
     *
     *    重写onMeasure测量
     *        在测量的时候把我们需要的内存区域获取到  存入到mRect中
     *    重写onDraw画出内容
     *
     *    然后就是手势相关的处理
     */
    public class BigView extends View implements
            GestureDetector.OnGestureListener, View.OnTouchListener {
    
        private Rect mRect;
        private BitmapFactory.Options mOptions;
        private GestureDetector mGestureDetector;
        private Scroller mScroller;
        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);
            //设置onTouchListener
            setOnTouchListener(this);
    
            //滑动帮助
            mScroller = new Scroller(context);
        }
    
        /**
         * 由使用者输入一张图片
         */
        public void setImage(InputStream is) {
            //先读取原图片的信息   高,宽
            mOptions.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(is, null, mOptions);
            mImageWidth = mOptions.outWidth;
            mImageHeight = mOptions.outHeight;
            //开启复用
            mOptions.inMutable = true;
            //设置格式成RGB_565
            mOptions.inPreferredConfig = Bitmap.Config.RGB_565;
            mOptions.inJustDecodeBounds = false;
    
            //创建一个区域解码器
            try {
                mDecoder = BitmapRegionDecoder.newInstance(is, false);
            } catch (IOException e) {
                e.printStackTrace();
            }
            requestLayout();
        }
    
        /**
         * 在测量的时候把我们需要的内存区域获取到  存入到mRect中
         */
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            //获取测量的view的大小
            mViewWidth = getMeasuredWidth();
            mViewHeight = getMeasuredHeight();
    
            //确定要加载的图片的区域
            mRect.left = 0;
            mRect.top = 0;
            mRect.right = mImageWidth;
            //获取一个缩放因子
            mScale = mViewWidth / (float) mImageWidth;
            //高度就根据缩放比进行获取
            mRect.bottom = (int) (mViewHeight / mScale);
        }
    
        /**
         * 画出内容
         */
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            //如果解码器拿不到,表示没有设置过要显示的图片
            if (null == mDecoder) {
                return;
            }
            //复用上一张bitmap
            mOptions.inBitmap = bitmap;
            //解码指定的区域
            bitmap = mDecoder.decodeRegion(mRect, mOptions);
            //把得到的矩阵大小的内存进行缩放  得到view的大小
            Matrix matrix = new Matrix();
            matrix.setScale(mScale, mScale);
            //画出来
            canvas.drawBitmap(bitmap, matrix, null);
        }
    
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            //交给手势处理
            return mGestureDetector.onTouchEvent(event);
        }
    
        /**
         * 手按下的回调
         *
         * @param e
         * @return
         */
        @Override
        public boolean onDown(MotionEvent e) {
            //如果移动还没有停止,强制停止
            if (!mScroller.isFinished()) {
                mScroller.forceFinished(true);
            }
            //继续接收后续事件
            return true;
        }
    
        /**
         * @param e1        接下
         * @param e2        移动
         * @param distanceX 左右移动时的距离
         * @param distanceY 上下移动时的距离
         * @return
         */
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            //上下移动的时候,需要改变显示区域   改mRect
            mRect.offset(0, (int) distanceY);
            //处理移动时已经移到了两个顶端的问题
            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
         * @return
         */
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            //做计算
            mScroller.fling(0, mRect.top,
                    0, (int) -velocityY,
                    0, 0,
                    0, mImageHeight - (int) (mViewHeight / mScale));
            return false;
        }
    
        /*
        使用上一个接口的计算结果
         */
        @Override
        public void computeScroll() {
            if (mScroller.isFinished()) {
                return;
            }
            //true 表示当前滑动还没有结束
            if (mScroller.computeScrollOffset()) {
                mRect.top = mScroller.getCurrY();
                mRect.bottom = mRect.top + (int) (mViewHeight / mScale);
                invalidate();
            }
        }
    
        @Override
        public void onShowPress(MotionEvent e) {
        }
    
        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            return false;
        }
    
        @Override
        public void onLongPress(MotionEvent e) {
    
        }
    }
    

    外界使用

    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            BigView bigView=findViewById(R.id.bigView);
            InputStream is=null;
            try{
                //加载图片
                is=getAssets().open("big.png");
                bigView.setImage(is);
            }catch(Exception e){
                e.printStackTrace();
            }finally {
                if(is!=null){
                    try {
                        is.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    

    总结

    加载一张大图,我们的处理办法,就是写个自定义View,然后通过把大图转成IO流,然后把这个图片的IO流渲染到这个自定义View上,并增加其手势等处理

    相关文章

      网友评论

          本文标题:Andoird-APP长图加载的处理方案

          本文链接:https://www.haomeiwen.com/subject/xrelbltx.html