Android 屏幕适配

"Android 屏幕适配"-Android面试必问"精华技能点"汇总

作者:nzfxx

目录:

1. 屏幕适配的方式都有哪些?

1.1 方式之-dp

1.1.1 名词解释:

  • 分辨率

    480*800,1280*720,表示像素点的总和

  • px(pix)-像素

    是屏幕里的最小单元

  • dpi-像素密度

    • 每英寸屏幕具有的像素数量,像素密度越大,细节越丰富
    • 公式:像素密度 = √{(长度像素数^2+宽度像素数^2)}/ 屏幕尺寸
    • 尺寸单位为:英寸;屏幕尺寸为:对角线长度(如下图)
      这里写图片描述

1.1.2 res文件夹下的目录分类

(如图)
这里写图片描述
应用查找图片的顺序:

先从自己开始(没有)->逐个就往高的找(没有)->就往比自己低的

1.1.3 Android中的像素密度/分辨率/dp和px的关系

类型dip分辨率dp和px比例
ldip120240*3201dp = 0.75px
mdip(标准)160320*4801dp = 1px
hdip240480*8001dp = 1.75px
xhdip320720*12801dp = 2px
xxhdip4801080*19201dp = 3px

比例图如下:
这里写图片描述

  • 由上面的标准mdip,那么如果在320*480的手机上,只需要dp就等效于px,因为1:1
  • 我们在代码运算过程中经常要做dp和px的互换,根据上面的比例特点.我们只需通过获取资源.获取屏幕分辨率.获取比例即可
/*
       density   分辨率       dp和px的转换
ldip    120     240*320     1dp = 0.75px
mdip    160     320*480     1dp = 1px
hdip    240     480*800     1dp = 1.5px
xhdip   320     720*1280    1dp = 2px
xxhdip  480     1080*1920   1dp = 3px

px和dip的转换,只需获取比例值即可;得出dp和px
参考标准的mhdip,额算出其他:pixels=dips*(density/160)
如果是240*320的求得density肯定是1;
1.获取比例值-自动根据当前的手机获取比例值
(不同分辨率得到的不同,比如我的模拟器720*1280返回2)
(PS:传入dp得px:乘以比例即可;传入px得dp:除以比例即可),写成工具类
2.四舍五入

*/
public class DensityUtil {  

    /** 
     * 根据手机的分辨率从 dip 的单位 转成为 px(像素) 
     */  
    public static int dip2px(Context context, float dpValue) { 

        final float scale = context.getResources().getDisplayMetrics().density;    
        return (int) (dpValue * scale + 0.5f);  
    }  

    /** 
     * 根据手机的分辨率从 px(像素) 的单位 转成为 dp 
     */  
    public static int px2dip(Context context, float pxValue) {  

        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (pxValue / scale + 0.5f);  
    }  
}  
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

1.1.4布局里的160dp和180dp的

160dp:

  • 设置一个按钮的宽度为160dp,在320*480分辨率的机器里,那么正好是一半(因为1:1)
  • 在240*320的机器里,正好也显示一半,因为(1:0.75),160dp = 120px
  • 在480*800的机器里,也是一半,因为(1:1.5).160dp = 240px
  • 所以在以上三种分辨率下设置多少dp是等效的,归为一档.
    <Button
        android:background="#ff0000"
        android:layout_width="60dp"
        android:layout_height="wrap_content"/>
    <Button
        android:background="#00ff00"
        android:layout_width="100dp"
        android:layout_height="wrap_content"/>
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

三种分辨率同样的代码都显示这样的效果:
这里写图片描述


180dp:

  • 如果将上面的160dp,放到720*1280或者1920 *1080,那么得到的效果和以上机器是不同的
  • 设置180dp宽度的按钮,在这两者里面的效果是一样的
  • 因为:720*1280(比例是:1:2)所以180dp = 360px,就是一半
  • 1920*1080(比例是:1:3)所以180dp = 540px,也是一半
  • 所以这两种分辨率下设置的dp是等效的,也是一档
    <Button
        android:background="#ff0000"
        android:layout_width="80dp"
        android:layout_height="wrap_content"/>
    <Button
        android:background="#00ff00"
        android:layout_width="100dp"
        android:layout_height="wrap_content"/>
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

两种分辨率下都显示同样效果
这里写图片描述


2.方式之-dimens(尺寸)

  • (PS:根据上一节的160dp和180dp的讲解,我们现在通过自动dimens解决自动适配问题)
  • 1.在res目录下有默认的values文件夹和dimens.xml文件
  • 2.为了自动适配1280 *720和1920 *1080分辨率,我们分边创建各自的文件夹
    • values-1280x720(eclipase写法),Android Studio写成values-w320dp
      这里写图片描述
  • 3.把刚才的dimens.xml复制一份到目标文件夹

    • 默认的dimens.xml写成160dp,移到新文件的定义成180dp;
      这里写图片描述
  • 4.最后在布局文件中写单位大小时,用@dimens/width即可,自动根据屏幕灵活调用
    这里写图片描述
    (PS:因为有默认的和指定各种分辨率(另外写1920*1080的,虽然和720等效,但是还是要写,否则他就用默认的了)的文件夹,所以找不到指定的就用默认的)

3.方式之-layout

  • 原理和上述情况一样,些不同的layout,会根据分辨率自动找到合适的layout
    这里写图片描述

4.方式之-代码适配

  • 需求:通过代码设置,让一个TextView的宽和高都为屏幕的一半;
  • 初始:布局是默认的包裹,如下:
<RelativeLayout 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:id="@+id/tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="#e18080"
        android:text="hello_world"/>
</RelativeLayout>
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

这里写图片描述
* 步骤:
* 1.获取tv控件
* 2.获取当前机器的分辨率.
* 3.新建一个和跟布局一样(根是线性就线性,是关系就设置关系)的参数,构造传入长和宽(分辨率的一半)
* 4.再让tv控件设置参数即可.
*代码如下:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //1.
        TextView tv = (TextView) findViewById(R.id.tv);
        //2.
        int height = getWindowManager().getDefaultDisplay().getHeight();
        int width = getWindowManager().getDefaultDisplay().getWidth();
        //3.
        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams((int) ((float)width/2+0.5), (int) ((float)height/2+0.5));
        //4.
        tv.setLayoutParams(params);
    }
}
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

效果:
这里写图片描述

5.方式之-weight权重

(PS:必须是线性布局)

1.多个相对的标准权重

  • 如果是横向:把高度设置为0dp

  • 如果是竖向:把宽度设置为0dp

  • 然后色字不同控件所占的权重

    <Button
        android:layout_weight="1"
        android:text="bt1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"/>
    <Button
        android:text="bt2"
        android:layout_weight="2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"/>
 </LinearLayout>
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

效果:
这里写图片描述

2.单个相对父布局的权重

  • 1.设置父布局的总权重:SumWeight
  • 2.设置自己的所占的权重即可
<LinearLayout
    android:weightSum="3"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">
    <Button
        android:layout_weight="2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="bt1"/>
</LinearLayout>
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

效果:
这里写图片描述

3.自动权重

  • 想让前面的完全填充,并且设置权重
  • 然后后面的用包裹即可
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">
    <EditText
        android:text="请输入内容"
        android:layout_weight="1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="输出"/>
</LinearLayout>
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

效果如下:
这里写图片描述


二.屏幕适配的处理技巧都有哪些?

横竖屏的切换

(正常情况下,每次横竖屏切换都会导致Activity的重新创建)

  • 1.在活动销毁前保存活动状态(重写onSaveInstanceState方法),可以参考前面我们讲的思维(点击访问).
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    //切换屏幕后获取信息
    if (savedInstanceState != null) {
        System.out.println(savedInstanceState.get("height")+"-------");
        System.out.println(savedInstanceState.get("width")+"-------");
    }
}
    //保存信息
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        outState.putInt("height", 100);
        outState.putInt("width", 50);
        super.onSaveInstanceState(outState);
    }
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 2.在清单文件把方向写死:

    • android:screenOrientation=”portrait”(landscape是横向,portrait是纵向)
  • 3.如果不想重新让Activity调用,就设置配置更改

    • 在清单文件设置三个参数:

      • 方向|按键隐藏|屏幕尺寸

        android:configChanges="orientation|keyboardHidden|screenSize"
        
    • 另外重写Activity里的更改方法

      • 如果切换横竖屏,之后重新调用这个方法
@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
        //横向就干嘛 TODO
    } 
    else if(this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT){
        //竖向就干嘛 TODO
    }
}
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

权重的反比例

经过改善一般我们都是设置0dp,然后使用权重,占多少就占用多少部分

如果反比例,比如按钮A权重是1,按钮B是2,那么就反过来了,代码和效果图如下.
就是不用0dp,而改用填充

        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="bt1"/>

        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="2"
            android:text="bt2"/>
    </LinearLayout>
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

这里写图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值