Android屏幕适配之加载网络图片的适配攻略

关于Android的屏幕适配方案网上有很多很多,很多大神讲的很全面也都很好,所以这里我就不班门弄斧了,这篇文章主要介绍安卓开发过程中加载网络图片(本文中加载图片的类库为Picasso),布局中ImageView不同宽高展示的适配方案,主要分为以下三大类:

一、ImageView宽度小于屏幕宽度的(即原图宽高确定,且在原型图中宽高有明确标注的),比如item中的一个图片元素,或者其他布局情况下的一个图片元素等,解决方案如下:
这类情况下的方案就比较简单了,基本上都是给ImageView设置一个固定宽高,并配合scaleType属性即可实现

<ImageView
   android:id="@+id/iv_detail_img"
   android:layout_width="70dp"
   android:layout_height="50dp"
   android:scaleType="fitXY"/>

scaleType指定了ImageView如何显示图片,包括是否进行缩放、等比缩放、缩放后展示的位置等,设置的方式有两种包括:
1.在xml中设置android:scaleType=”fitXY”
2.或在代码中调用.setScaleType(ImageView.ScaleType.fitXY);
Android提供了八种三大类scaleType的属性值,因图片太占篇幅,这里就不放效果图了,直接列举各属性作对比,如下表:

属性值 效果(可能是全网最详细解释)
fitXY 该模式下,不保持原图比例来缩放,而是按照ImageView指定的宽高对原图宽高进行缩放,使完全填充ImageView的宽和高展示(不会留白)。注意:此模式不是等比缩放
fitCenter 该模式是ImageView的默认模式,该模式下,对原图按等比例缩放至等于ImageView的宽或高使能够填充ImageView的宽或高并居中显示(可能会上下或左右留白)。
fitStart 该模式下,把原图按比例缩放至ImageView的宽或高,显示起始于ImageView的上边或左边(即上对齐或者左对齐)展示,若原图高大于宽则左对齐(即右留白)否则上对其(即下留白)。
fitEnd 该模式下,把原图按比例缩放至ImageView的宽或高,显示起始于ImageView的下边或右边(即下对齐或者右对齐)展示,若原图高大于宽则右对齐(即左留白),否则下对其(即上留白)。
center 该模式下,不会进行缩放,而是会保持原图的大小,并居中显示。若原图的宽高小于ImageView的宽高,那么原图会被居中显示(会留白)。若原图的宽高大于ImageView的宽高,超出部分会被裁剪处理不再显示(不会留白)。
centerCrop 该模式下,以填满整个ImageView为目的,原图会被等比缩放至完全填充整个ImageView(指的是ImageView的宽和高都要填满),并居中显示。原图超过ImageView的部分作裁剪处理(即是使原图最小边等于ImageView的相应边)使原图的宽或高可以完全展示出来(不会留白)。(难点)
centerInside 该模式下,以完全显示原图为目的。如果原图的宽高本身就小于ImageView的宽高,则原图的宽高不作任何处理,直接居中显示(会留白,效果同center),否则原图宽或高被等比例缩放至等于ImageView的宽或高(即是使原图最大边等于ImageView的相应边)并居中显示(会留白,同fitCenter)。(难点)
matrix 该模式下,不改变原图的宽高,从ImageView的左上角开始绘制原图,原图超过ImageView的部分作裁剪处理(可能会留白—>由原图宽高决定)。(难点)

注:matrix模式需要创建一个矩阵用于指定原图如何展示。其实前面的7种模式都是通过ImageView在内部生成了相应的矩阵,即是提供了该模式的一种特定值,使用该模式只要传入相应的矩阵,就能实现上述七种显示属性所实现的效果。具体使用方法如下:

imageView.setScaleType(ImageView.ScaleType.MATRIX);//设置为矩阵模式
Matrix matrix = new Matrix();//创建一个矩阵
matrix.setTranslate(50, 50)//平移
matrix.preRotate(90);//旋转
imageView.setImageMatrix(matrix);//应用该矩阵

二、ImageView宽度等于屏幕宽度的(包括有padding的情况),比如某个详情页的一个图片元素,或者是图片列表中item的图片元素等
这个分类下又分为以下两种情况:

//首先,给出一个获取屏幕宽度的方法,后面会用到
public int getScreenWidth(Context context) {
       WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
       DisplayMetrics outMetrics = new DisplayMetrics();
       wm.getDefaultDisplay().getMetrics(outMetrics);
       return outMetrics.widthPixels;
    }

1、原图宽高比固定的情况(即在原型图中宽度充满屏幕,高度有明确标注的)
比如,设计给的原型图中,图片宽为700充满屏幕,高为350,那么宽高比就是(700/350=2),解决方案如下:

//xml布局中设置宽充满高自适应
id="@+id/imageView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"/>
//java代码中动态设置
ViewGroup.LayoutParams params = imageView.getLayoutParams();
int targetWidth = getScreenWidth(getContext());//获取屏幕宽度
params.height = targetWidth / 2;
imageView.setLayoutParams(params);

注:也可在xml中设置宽自适应然后java代码中设置params.width = targetWidth;

2、原图宽高比不固定的情况(即在原型图中宽度充满屏幕,但高度需要自适应的—>有三种解决方案)
方案一:通过直接调用Picasso的transform()方法来重设宽高

//xml布局中设置宽充满高自适应(因为java代码中设置了宽度为屏幕宽度,这里宽度设为自适应也可)
id="@+id/imageView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"/>
//Picasso加载图片url的代码
Picasso.with(getContext()).load(url)
                    .placeholder(R.mipmap.bg_default_120x90)
                    .error(R.mipmap.bg_default_120x90)
                    .transform(mTransformation)
                    .into(imageView);

注:url为要加载的图片的url,bg_default_120x90为自己设置的未加载完成时的默认图片

    //按原图进行完全的等比例缩放
    private Transformation mTransformation = new Transformation() {
        @Override
        public Bitmap transform(Bitmap source) {
            int targetWidth = getScreenWidth(getContext());//获取屏幕宽度
            if (source.getWidth() == 0) {
                return source;
            }
            double aspectRatio = (double) source.getHeight() / (double) source.getWidth();
            int targetHeight = (int) (targetWidth * aspectRatio);
            if (targetHeight != 0 && targetWidth != 0) {
                Bitmap result = Bitmap.createScaledBitmap(source, targetWidth, targetHeight, false);
                if (result != source) {
                    source.recycle();
                }
                return result;
            } else {
                return source;
            }
        }

        @Override
        public String key() {
            return "transformation" + " desiredWidth";
        }
    };

注:该方案主要是通过计算原图的宽高比,然后调用createScaledBitmap()方法将原图缩放到指定尺寸

方案二:不使用Picasso来加载图片,直接使用WebView来加载url(这里就不得不说css的强大了,它可以设置宽度充满的情况下,高度按照原图宽度缩放的比例进行等比例缩放,具有极强的跨平台性能)

//xml布局中设置宽充满高自适应
id="@+id/webView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />
//其中的url即是要加载的图片的url
String css = "\n" +
             "\n" +
             "<html>\n" +
             "<head>\n" +
             "<meta charset=\"UTF-8\">\n" +
             "<meta name=\"viewport\" " +
             "content=\"width=device-width, initial-scale=1.0, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0\">\n" +
             "<style>\n" +
             "*{margin:0;padding:0}\n" +
             "img{width:100%;display:block;}\n" +
             "style>\n" +
             "head>\n" +
             "<body>\n" +
             "<img src=\"" + url +
             "\"/>\n" +
             "body>\n" +
             "html>\n";
//然后直接通过webview来加载上面的自定义样式的url
webView.loadDataWithBaseURL(null, css, "text/html", "utf-8", null);

方案三:通过在xml中设置ImageView的adjustViewBounds属性,同时在Java代码中配合setMaxWidth()和setMaxHeight()方法使用

//xml布局中设置宽高自适应
id="@+id/imageView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:scaleType="fitXY"
    android:adjustViewBounds="true" />
int targetWidth = getScreenWidth(getContext());//获取屏幕宽度
ViewGroup.LayoutParams params = imageView.getLayoutParams();
params.width = targetWidth;
imageView.setLayoutParams(params);//设置宽充满
imageView.setMaxWidth(targetWidth);//设置宽最大为屏幕宽
imageView.setMaxHeight(targetWidth);//设置高最大也为屏幕宽

注:
1、也可在xml中设置宽充满,然后java代码中去掉设置宽的代码params.width = targetWidth;
imageView.setLayoutParams(params);
2、上述设置是因为明确知道宽大于高,所以设置的宽高的Max都是不大于屏幕宽,如果宽小于高的情况下,可以设置高最大为宽的2倍(即宽高的Max根据具体情况设置)

特别注意:
1、ImageView的adjustViewBounds属性,必须同时配合setMaxWidth()和setMaxHeight()方法一起使用才能生效,否则没有效果

三、ImageView宽度等于屏幕宽度固定比例的(比如原型图中标注ImageView的宽为屏幕宽度1/2的,或者其他比例的),解决方案如下:
这类情况实际上是第二类的特殊情况,所以第二类的解决方案完全适用于第三类,只需在涉及到设置ImageView宽度为屏幕宽度的地方,将宽度按照对应的比例设置即可


以上就是目前所总结到的所有的适配方案,具体使用哪种方案来进行适配,需要在开发过程中视情况而定。因图片资源较大,所以文中没有放效果图,如有童鞋需要demo,可以在评论区中说下,看到后我会把demo源码放出来。因能力有限,文中如有不对之处,还望指正~

你可能感兴趣的:(安卓开发进阶)