美文网首页
【原创】永不变形的ImageView

【原创】永不变形的ImageView

作者: 刀放下好好说话 | 来源:发表于2018-04-20 14:59 被阅读42次

    前言

    昨天在写QQ空间广告图的水波纹的效果实现的时候,查了关于ImageView和Bitmap的相关知识。过程中也遇到了图片变形的问题,这个问题真是由来已久,但是一直没有很好的解决办法。

    最常用的办法就是ImageView的scaleType设置为centerCrop,我感觉这个已经能解决大部分的问题,但是我还是想要一个永不拉伸的图片容器。就算图片被截断,我也要不拉伸不变形。

    永不变形!!!!!!!!!

    代码实现

    1.首先我想到的是继承ImageView:

    public class AutoFitImageView extends ImageView {
    
        private int width;
        private int height;
        private Paint mPaint;
    
        public AutoFitImageView(Context context) {
            super(context);
        }
    
        public AutoFitImageView(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
            initView(context, attrs);
        }
    
        private void initView(Context context, AttributeSet attrs) {
            mPaint = new Paint();
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            width = MeasureSpec.getSize(widthMeasureSpec);
            height = MeasureSpec.getSize(heightMeasureSpec);
            setMeasuredDimension(width, height);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
    //        super.onDraw(canvas);
            Drawable drawable = getDrawable();
            if(drawable != null) {
                Bitmap bitmap = zoomBitmap(drawableToBitmap(drawable), width, height);
                canvas.drawBitmap(bitmap, new Rect(bitmap.getWidth() / 2 - width / 2, bitmap.getHeight() / 2 - height / 2, bitmap.getWidth() / 2 + width / 2, bitmap.getHeight() / 2 + height / 2), new RectF(0, 0, width, height), mPaint);
            }
        }
    
        /**
         * drawable转bitmap  顺便拉伸
         * @param drawable
         * @return
         */
        public static Bitmap drawableToBitmap(Drawable drawable) {
            // 取 drawable 的长宽
            int w = drawable.getIntrinsicWidth();
            int h = drawable.getIntrinsicHeight();
    
            Log.d("------>", w + " : " + h);
    
            // 取 drawable 的颜色格式
            Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
            // 建立对应 bitmap
            Bitmap bitmap = Bitmap.createBitmap(w, h, config);
            // 建立对应 bitmap 的画布
            Canvas canvas = new Canvas(bitmap);
            drawable.setBounds(0, 0, w, h);
            // 把 drawable 内容画到画布中
            drawable.draw(canvas);
            return bitmap;
        }
    
        /**
         * 对一张图片进行拉伸
         *
         * @param bm
         * @param newWidth
         * @param newHeight
         * @return
         */
        public static Bitmap zoomBitmap(Bitmap bm, int newWidth, int newHeight) {
            // 获得图片的宽高
            int width = bm.getWidth();
            int height = bm.getHeight();
            // 计算缩放比例
            float scaleWidth = ((float) newWidth) / width;
            float scaleHeight = ((float) newHeight) / height;
            // 取得想要缩放的matrix参数
            Matrix matrix = new Matrix();
            float maxScale = Math.max(scaleWidth, scaleHeight);
            matrix.postScale(maxScale, maxScale);
            // 得到新的图片
            Bitmap newbm = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, true);
            return newbm;
        }
    }
    

    注意一点,一定是使用src给ImageView设置图片源,不能使用background。

    2.继承自View:

    public class AutoFitView extends View {
    
        private int width;
        private int height;
        private Paint mPaint;
        private Bitmap mBitmap;
    
        public AutoFitView(Context context) {
            super(context);
        }
    
        public AutoFitView(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
            initView(context, attrs);
        }
    
        private void initView(Context context, AttributeSet attrs) {
            mPaint = new Paint();
    
            mBitmap = BitmapFactory.decodeResource(context.getResources(), R.mipmap.top_pic);
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            width = MeasureSpec.getSize(widthMeasureSpec);
            height = MeasureSpec.getSize(heightMeasureSpec);
            setMeasuredDimension(width, height);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            if(mBitmap != null) {
                Bitmap bitmap = zoomBitmap(mBitmap, width, height);
                canvas.drawBitmap(bitmap, new Rect(bitmap.getWidth() / 2 - width / 2, bitmap.getHeight() / 2 - height / 2, bitmap.getWidth() / 2 + width / 2, bitmap.getHeight() / 2 + height / 2), new RectF(0, 0, width, height), mPaint);
            }
        }
    
        /**
         * 对一张图片进行拉伸
         *
         * @param bm
         * @param newWidth
         * @param newHeight
         * @return
         */
        public static Bitmap zoomBitmap(Bitmap bm, int newWidth, int newHeight) {
            // 获得图片的宽高
            int width = bm.getWidth();
            int height = bm.getHeight();
            // 计算缩放比例
            float scaleWidth = ((float) newWidth) / width;
            float scaleHeight = ((float) newHeight) / height;
            // 取得想要缩放的matrix参数
            Matrix matrix = new Matrix();
            float maxScale = Math.max(scaleWidth, scaleHeight);
            matrix.postScale(maxScale, maxScale);
            // 得到新的图片
            Bitmap newbm = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, true);
            return newbm;
        }
    }
    

    写法相同,不过ImageView需要创建两次临时的Bitmap,内存开销比较大。继承View更合适。

    canvas.drawBitmap() 第一个Rect 代表要绘制的bitmap 区域,第二个 Rect 代表的是要将bitmap 绘制在屏幕的什么地方,这样就很容易能计算出需要绘制的区域。

    我选取了一张 650*360 的图片,分别看看效果:

    1.高度50dp:


    Screenshot_2018-04-20-12-38-48-074_com.rjp.sorryd.png

    2.高度100dp:


    Screenshot_2018-04-20-12-39-57-144_com.rjp.sorryd.png

    3.高度150dp:


    Screenshot_2018-04-20-12-40-24-584_com.rjp.sorryd.png

    4.高度500dp:


    Screenshot_2018-04-20-12-40-59-942_com.rjp.sorryd.png
    Screenshot_2018-04-20-12-41-04-804_com.rjp.sorryd.png

    这里图片宽高都很小,如果是一张超大的图片呢?能经受的住考验吗?

    选择的图片是一张清明上河图,立马崩溃了,java.lang.OutOfMemoryError,意料之中。但是在实际应用中,上面的方法已经是够用了。

    enough is ok!

    怎么加载超大的图呢?没有思路,但是已经有博客讲解了,传送门

    本博客就是一个小demo,没有源码了

    相关文章

      网友评论

          本文标题:【原创】永不变形的ImageView

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