大图显示

       本文源码适用于原始图片高度大于宽度的场景,且图片宽度小于或略大于屏幕宽度的场景。界面水平方向不能滑动,垂直方向可以滑动查看完整大图。
原理:根据用户的滑动位移,裁剪大图的一部分,然后绘制出来;考虑到BitmapRegionDecoder.decodeRegion裁剪耗时,我们只decodeRegion出上次没有decode过的图片区域。SurfaceView控件可以在后台线程中执行图片裁剪绘制操作,可以避免主线程阻塞。

public class BigImageView1 extends SurfaceView implements SurfaceHolder.Callback{
    private static final String IMAGE_NAME = "11.jpg";
    private Rect rect;  //当前要绘制的图片裁剪区域
    private Rect lastRect;  //上一次绘制的图片裁剪区域
    private Rect diffRect;  //绘制区域差
    private Bitmap lastBmp; //缓存上次从图片中裁剪的bitmap

    private BitmapRegionDecoder decoder;
    private BitmapFactory.Options options;
    private int imageWidth, imageHeight; //原始图片宽高
    private GestureDetector detector;   //手势检测
    //图片宽度和View宽度的缩放比
    private float scale = 1;
    private SurfaceHolder holder;
    private DecoderThread thread;   //绘图线程

    public BigImageView1(Context context) {
        super(context);
    }

    public BigImageView1(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public BigImageView1(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    public BigImageView1(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init();
    }

    private void init(){
        holder = getHolder();
        getHolder().addCallback(this);

        lastRect = new Rect(0, 0, 0, 0);
        diffRect = new Rect(0, 0, 0, 0);

        rect = new Rect();
        detector = new GestureDetector(getContext(), onGestureListener);

        try {
            InputStream inputStream = getContext().getAssets().open(IMAGE_NAME);
            decoder = BitmapRegionDecoder.newInstance(inputStream, false);

            options = new BitmapFactory.Options();
            options.inPreferredConfig = Bitmap.Config.RGB_565;
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(inputStream, null, options);
            imageWidth = options.outWidth;
            imageHeight = options.outHeight;

            //初始化缩放尺度
            scale = imageWidth * 1.0f / Constants.SCREEN_WIDTH;
            if(scale < 1){
                scale = 1;
            }

            options.inJustDecodeBounds = false;
        }catch (Exception e){
        }
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        scale =   imageWidth * 1.0f / getWidth() ;
        if(scale < 1){
            scale = 1;
        }
        rect.left = 0;
        rect.top = 0;
        rect.right = imageWidth;
        rect.bottom = (int)(getHeight() * scale);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }

    GestureDetector.OnGestureListener onGestureListener = new GestureDetector.SimpleOnGestureListener(){
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
//            mTranslationY = distanceY + mTranslationY;

            //判断如果是顶部的下拉动作,则直接忽略不处理
            if(rect.top <= 0 && distanceY < 0){
                return true;
            }
            //判断如果是底部的上拉动作,则直接忽略不处理
            if(rect.bottom >= imageHeight && distanceY > 0){
                return true;
            }
            //用户手指滑动时,重定位图片绘制区域rect坐标
            synchronized (BigImageView1.this) {
                rect.offset(0, (int) Math.floor(distanceY * scale));
                //处理rect下边界大于图片尺寸的情况
                if (rect.bottom > imageHeight) {
                    rect.top = imageHeight - (int) Math.floor(getHeight() * scale);
                    rect.bottom = imageHeight;
                }
                //处理rect上边界小于0的情况
                if (rect.top < 0) {
                    rect.top = 0;
                    rect.bottom = (int) Math.floor(getHeight() * scale);
                }
            }
            return true;
        }
    };

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        detector.onTouchEvent(event);
        return true;
    }


    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        thread = new DecoderThread();
        thread.start();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        //结束线程
        if(thread != null){
            thread.isRun =false;
        }
    }

    /**
     * 后台线程循环绘图
     */
    class DecoderThread extends Thread {
        //线程运行标示变量
        public boolean isRun = true;

        @Override
        public void run() {
            super.run();
            boolean flag = false;
            float distanceY = 0;

            while(isRun){
                synchronized (BigImageView1.this) {
                    // 用户没有滑动界面,绘制的图片区域无变化,走if分支
                    if (lastRect.bottom == rect.bottom && lastRect.top == rect.top) {
                        flag = true;
                    }else{
                        distanceY = rect.top - lastRect.top;
                        //比较本次用户滑动后,比上次图片裁剪区域多出的部分,存放在diffrect中
                        if(lastRect.bottom < rect.bottom){
                            diffRect.top = lastRect.bottom;
                            diffRect.bottom = rect.bottom;

                            diffRect.left = rect.left;
                            diffRect.right = rect.right;
                        }else{
                            diffRect.top = rect.top;
                            diffRect.bottom = lastRect.top;
                            diffRect.left = rect.left;
                            diffRect.right = rect.right;
                        }
                        //缓存图片裁剪区域
                        lastRect.top = rect.top;
                        lastRect.bottom = rect.bottom;
                        lastRect.right = rect.right;
                        lastRect.left = rect.left;
                    }
                }
                if(flag){
                    flag = false;
                    try {
                        //sleep 1ms,减少cpu消耗
                        Thread.sleep(1);
                    } catch (Exception e) {
                    }
                    continue;
                }

                Canvas canvas = holder.lockCanvas();

                Bitmap bm = decoder.decodeRegion(diffRect, options);
                //本次绘制的Bitmap = 上次绘制的图片中仍在可视区域的一部分Bitmap + 本次滑动位移产生的图片裁剪Bitmap
                if(lastBmp == null){
                    lastBmp = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), Bitmap.Config.RGB_565);
                    Canvas _canvas = new Canvas(lastBmp);
                    _canvas.drawBitmap(bm, 0, 0, null);
                    bm.recycle();
                    bm = null;
                }else{
                    //将需要显示的图片区域分为两部分,上次已经显示的bitmap
                    Bitmap temp = Bitmap.createBitmap(lastBmp.getWidth(), lastBmp.getHeight(), Bitmap.Config.RGB_565);
                    Canvas _canvas = new Canvas(temp);
                    if(distanceY <= 0) {
                        _canvas.drawBitmap(lastBmp, new Rect(0, 0, lastBmp.getWidth(), lastBmp.getHeight() - diffRect.height()),
                                new RectF(0, diffRect.height(), lastBmp.getWidth(), lastBmp.getHeight()), null);
                        _canvas.drawBitmap(bm, 0, 0, null);
                    }else{
                        _canvas.drawBitmap(lastBmp, new Rect(0, diffRect.height(), lastBmp.getWidth(), lastBmp.getHeight()),
                                new RectF(0, 0, lastBmp.getWidth(), lastBmp.getHeight() - diffRect.height()), null);
                        _canvas.drawBitmap(bm, 0, lastBmp.getHeight() - diffRect.height(), null);
                    }
                    lastBmp.recycle();
                    lastBmp = null;
                    lastBmp = temp;
                    bm.recycle();
                    bm = null;
                }

                //执行绘制操作
                if(imageWidth > getWidth()) {
                    Bitmap bm1 = Bitmap.createScaledBitmap(lastBmp, getWidth(), getHeight(), false);
                    canvas.drawBitmap(bm1, 0, 0, null);
                    bm1.recycle();
                    bm1 = null;
                }else{
                    //水平居中绘制图片
                    int diff = (int)((getWidth() - imageWidth) / 2.0);
                    canvas.drawBitmap(lastBmp, diff, 0, null);
                }
                holder.unlockCanvasAndPost(canvas);
            }
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值