Android屏幕适配(理论适配100%机型)

一、前言

前段时间开发小玩意的时候,我基于现在用的手机(分辨率2280 X 1080)设计的。结果在以前的一个5.0手机上出现了瑕疵,emm大家应该都懂——布局全乱了,我刚开始也是想到借助网络上大多数大神开发的框架直接用,我一想我应该可以试着自己研究下,实在不行再用大佬的。首先做这件事之前我们需要想好方向,我想从源码层入手更好,也更直观。

二、开发前准备

我们需要了解界面构造方法,onMeasure()、onLayout()、onDraw()。如果稍微不懂的可以去网上下载Framework和Sourse Insight工具查看,当然你也可以在线查阅。

创建项目
项目名字 包名 版本….这些应该是不用详细讲解的。

三、创建自定义RelativeLayout

我们首先想如果把这个自定义的RelativeLayout写进xml,然后将我们所有的组件(控件也行)放在它里面。到时候适配只需要将这个里面的子内容适配吧,当然你们或许有更好的方法我,我这里只讲思路。

然后继承RelativeLayout

public class UIRelativeLayout extends RelativeLayout {
public UIRelativeLayout(Context context) {
super(context);
}

public UIRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}

public UIRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
}

再去activity_main将自定义RelativeLayout用进去

<?xml version="1.0" encoding="utf-8"?>
<com.mobai.myapplication.UIRelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>

</com.mobai.myapplication.UIRelativeLayout>

四、处理组件

上面我们已经使用了UIRelativeLayout,接下来我们就应该来处理UIRelativeLayout里面的组件了
这里我先用1920 X 1080的分辨率写出界面。


然后用模拟器运行,首先是按照标准的1920 X 1080

然后是540 X 960

结果显而易见布局乱了,那接下来就开始适配的正题

新建一个管理ui的类

public class UIUtils {

Context context;

//设置标准的屏幕宽度和高度
private static float correctly_width = 1080F;
private static float correctly_height = 1920F;

//系统存放相关配置信息的地方 这里用来获取状态栏高度
private static String AndroidClass = "com.android.internal.R$dimen";

//实际Android的屏幕宽高
private static float actual_width;
private static float actual_height;

//水平和垂直的缩放比
private static float HorizontalScale;
private static float VerticalScale;

public float getHorizontalScale() {
return this.HorizontalScale;
}

public float getVerticalScale() {
return this.VerticalScale;
}
}

关键内容

public UIUtils(Context context) {
this.context = context;
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics displayMetrics = new DisplayMetrics();
if (actual_width == 0.0F || actual_height == 0.0F) {
windowManager.getDefaultDisplay().getMetrics(displayMetrics);
}

//获取状态栏的高度
int systemBarHeight = getSystemBarHeight(context);

//适配平板和手机
if (displayMetrics.widthPixels > displayMetrics.heightPixels) {
//平板
this.actual_width = displayMetrics.heightPixels;
this.actual_height = displayMetrics.widthPixels - systemBarHeight;
} else {
//手机
this.actual_width = displayMetrics.widthPixels;
this.actual_height = displayMetrics.heightPixels - systemBarHeight;
}

this.HorizontalScale = ((float) this.actual_width) / correctly_width;
this.VerticalScale = ((float) this.actual_height) / correctly_height;
}

/**
* 通过反射获取状态栏高度
* @param context
* @return
*/
private int getSystemBarHeight(Context context) {
try {
Class c = Class.forName(AndroidClass);
Object obj = c.newInstance();
Field field = c.getField("status_bar_height");
int h = Integer.parseInt(field.get(obj).toString());
return context.getResources().getDimensionPixelSize(h);
} catch (Exception e) {
e.printStackTrace();
return 48;
}
}

接下来在UIRelativeLayout里面实现显示

//现有属性和新属性的操作
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//获取所有组件的属性
int count = this.getChildCount();
UIUtils uiUtils = new UIUtils(getContext());
float scaleX = uiUtils.getHorizontalScale();
float scaleY = uiUtils.getVerticalScale();
if (flag) {
flag = false;
for (int i = 0; i < count; i++) {
View child = this.getChildAt(i);

//获取布局参数
LayoutParams layoutParams = (LayoutParams) child.getLayoutParams();
//完成缩放
layoutParams.width = (int) (layoutParams.width * scaleX);
layoutParams.height = (int) (layoutParams.height * scaleY);
layoutParams.topMargin = (int) (layoutParams.topMargin * scaleY);
layoutParams.bottomMargin = (int) (layoutParams.bottomMargin * scaleY);
layoutParams.leftMargin = (int) (layoutParams.leftMargin * scaleX);
layoutParams.rightMargin = (int) (layoutParams.rightMargin * scaleX);
}
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

帮助我们把自定义的属性封装到系统的param中

@Override
public RelativeLayout.LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LayoutParams(getContext(),attrs);
}

public static class LayoutParams extends RelativeLayout.LayoutParams {

public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
}

public LayoutParams(int w, int h) {
super(w, h);
}

public LayoutParams(ViewGroup.LayoutParams source) {
super(source);
}

public LayoutParams(MarginLayoutParams source) {
super(source);
}

public LayoutParams(RelativeLayout.LayoutParams source) {
super(source);
}
}

总结

其实原理也是非常的简单,就是根据一个缩放比来进行控制。缩放比又是通过 实际屏幕/标准的屏幕(540 / 1080 和 960 / 1920)。不过这里需要提出的是:不一定是需要自定义RelativeLayout 也可以别的。UIUtils里的获取scaleX 和 scaleY 实际上也是只要获取一次然后借助SharePreferences保存就好了。额 ,基本也是没有很大的难度,只是提供一种思路,如果文中出现了一些错误还望理解

下面是适配后的图

版权声明
本文是Mobai原创文章,转载请附上原文出处链接和本声明。
本文链接:http://boke.whitemo.xyz/index.php/archives/12/

梦雪

专注于AIDE教程分享

留下你的评论

*评论支持代码高亮<pre class="prettyprint linenums">代码</pre>

相关推荐