在我们平常开发的过程中在做引导页适配的时候,有时候会犯难,怎么样作图可以将各种不同尺寸分辨率的手机都适配好也就是不变形不拉伸,官方给的说法也只是做多套图去适配不同的分辨率,遇到全屏展示引导这种问题的时候就有些力不从心了。接下来我们就展示一下如何使用一张图来适配市面上的绝大部分手机:
这个办法是反编译微信得出的想法,微信的包里面只有一张1920*1080的图,我们观察了微信在不同尺寸手机上的展示效果,它肯定是没有变形的,根据这个思路,我们发现它在适配不同的手机对图片做了缩放裁剪等处理。
接下来我们就实现一下如何对图片进行适当的缩放及裁剪:
大伙也都看到了,我们选择了两台具有代表性的设备:一台分辨率是800*480,一台是1152*1920.这两台设备的高宽比是不一样的。
为了适配这两台代表性的设备,首先我们需要对图片进行等比缩放:
我们需要先行计算将要放大的图片的高度:
将要放大的图片的高度=原图的宽度*屏幕的高度/屏幕的宽度;
上面这个计算公式不用我说为什么吧,小学就学过的。至于原图放大会模糊的问题,一般屏幕的宽度最大也就是1080,只是魅族有些奇葩会是1152,如果担心这个问题的话,请美工给图的时候,直接按照1152的宽来就好了。
其次,我们为了良好的展示在节目上,面对于不同尺寸屏幕的手机,它们的高宽比是不一样的,所以我们的基本思想就是以宽度为基准,放大图片,然后以中心为准裁剪多余的部分(对于图片高度不足裁剪的手机,可能才疏学浅,还没见过)。
贴代码:
package com.sahadev.guide; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Point; import android.graphics.drawable.BitmapDrawable; import android.os.Bundle; import android.view.View; import android.view.ViewTreeObserver.OnGlobalLayoutListener; import android.view.Window; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { requestWindowFeature(Window.FEATURE_NO_TITLE); super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); scaleImage(this, findViewById(R.id.rootView), R.drawable.guide); } public static void scaleImage(final Activity activity, final View view, int drawableResId) { // 获取屏幕的高宽 Point outSize = new Point(); activity.getWindow().getWindowManager().getDefaultDisplay().getSize(outSize); // 解析将要被处理的图片 Bitmap resourceBitmap = BitmapFactory.decodeResource(activity.getResources(), drawableResId); if (resourceBitmap == null) { return; } // 开始对图片进行拉伸或者缩放 // 使用图片的缩放比例计算将要放大的图片的高度 int bitmapScaledHeight = Math.round(resourceBitmap.getHeight() * outSize.x * 1.0f / resourceBitmap.getWidth()); // 以屏幕的宽度为基准,如果图片的宽度比屏幕宽,则等比缩小,如果窄,则放大 final Bitmap scaledBitmap = Bitmap.createScaledBitmap(resourceBitmap, outSize.x, bitmapScaledHeight, false); view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { //这里防止图像的重复创建,避免申请不必要的内存空间 if (scaledBitmap.isRecycled()) //必须返回true return true; // 当UI绘制完毕,我们对图片进行处理 int viewHeight = view.getMeasuredHeight(); // 计算将要裁剪的图片的顶部以及底部的偏移量 int offset = (scaledBitmap.getHeight() - viewHeight) / 2; // 对图片以中心进行裁剪,裁剪出的图片就是非常适合做引导页的图片了 Bitmap finallyBitmap = Bitmap.createBitmap(scaledBitmap, 0, offset, scaledBitmap.getWidth(), scaledBitmap.getHeight() - offset * 2); if (!finallyBitmap.equals(scaledBitmap)) {//如果返回的不是原图,则对原图进行回收 scaledBitmap.recycle(); System.gc(); } // 设置图片显示 view.setBackgroundDrawable(new BitmapDrawable(context.getResources(), finallyBitmap)); return true; } }); } }
最后看实际运行效果:
1. 2. 3.
4. 5.
1.MX4 1152*1920
2.SAMSUNG G7106 720*1280
3.HTC D316d 540*960
4.NUBIA X6 1920*1080
5.HUAWEI Y330-C00 480*800
怎么样,效果还不错吧,不过肉眼几乎看不出来它们是否变形,如果有疑问,可以使用PS对他们进行等比缩放,然后叠加测试效果。比例相同的分辨率显示效果是一致的,如果比例不同会有一部分偏差,所以在美工设计图片的时候,请不要在最顶部以及最底部设置特殊标志,以免被裁剪。
最后注意scaleImage()方法请不要被外部多次调用,否则该方法内会生成多个Bitmap对象,容易造成内存溢出。
PS:scaleImage()方法内部针对于绘制测量的多次调用做了处理,避免了重复绘制与重复测量造成的多次Bitmap对象创建,可以放心使用。