Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 443|回复: 0

【原】android【手机】屏幕适配解决方案,完美适配适配hdpi,xhdpi,xxhdpi的做法。

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-6-10 17:23:54 | 显示全部楼层 |阅读模式
    • 1.先说要怎么做,后面在慢慢讲解:

    • 2.现在来讲解为什么要放这三套:

      • 这三套其实按内容来说就两种,为什么这两种可以适配hdpi,xhdpi,xxhdpi呢?

      • 那么两种类型的dimens就可以了,为什么要用三套,为什么默认的dimens要是hdpi的?

    • 3.关于图片的适配

    • 4.最后大概讲讲现有的适配方案

    • 5.附上dimens转换的代码


     

    dp单位解决的是你所设置的按钮的实际大小保持稳定,但是设备的物理尺寸不一定,并不能完美适配。

    写这个文章的时候只是接触到目前的主流手机,所以对于如下关系是适用的,但是最近接触到电视适配之后,MD我写的这是什么鬼==。。。。当然对于平板也不适用,所以下面的内容参考参考还可以

    ldpi   1dp = 0.75px    320*240      
    mdpi   1dp = 1px       480*320     
    hdpi   1dp = 1.5px     800*480      
    xhdpi  1dp = 2px       1280*720    
    xxhdpi 1dp = 3px      1920*1080 



     

    1.先说要怎么做,后面在慢慢讲解:

    1.单位全部用dp,优先使用包裹内容和填充父窗体和权重来完成布局。

    2.通过dimens文件来适配,需要三套,不考虑横屏

      2.1 默认的dimens.xml       放按hdpi适配的参数;

      2.2 hdpi的dimens.xml      放按hdpi适配的参数;

      2.3 xhdpi的dimens.xml    放按xhdpi适配的参数;

    3.适配的时候只用完美的完成一套xhdpi的dimens文件,然后通过代码生成hdpi的,因为就dp来说,他们有固定的比例关系,代码后面会贴出。

     

    2.现在来讲解为什么要放这三套:

    贴一个基本知识:(仅对于一般手机来说)

    ldpi   1dp = 0.75px    320*240      160dp = 120px
    mdpi   1dp = 1px       480*320      160dp = 160px
    hdpi   1dp = 1.5px     800*480      160dp = 240px
    xhdpi  1dp = 2px       1280*720    160dp = 320px<360px      180dp = 360px
    xxhdpi 1dp = 3px      1920*1080 160dp = 480px  <  540px     180dp = 540px 
     

    这三套其实按内容来说就两种,为什么这两种可以适配hdpi,xhdpi和xxhdpi呢?

    ldpi,mdpi,hdpi是一组;xhdpi和xxhdpi是一组;
    从上面贴出的基本知识可以看出,160dp在ldpi,mdpi,hdpi三种下,都是屏幕宽度的一半,也就是说以dp为单位的话,在这三种分辨率下,屏幕的显示效果是一样的;但是高度是不一样的,一半分别是213dp,240dp,267dp;我们适配的时候没有适配ldpi和mdpi的;
                   180dp在xhdpi和xxhdpi下的效果是一样的,道理同上。而且宽高都成比例。
     

    那么两种类型的dimens就可以了,为什么要用三套,为什么默认的dimens要是hdpi的?

    先说测试结果:

    1.没有ldpi和mdpi对应的dimens.xml的情况下:会加载默认的dimens.xml

    2.而hdpi,xhdpi,xxhdpi这三种会加载最近的dimens.xml文件

    下面是测试过程:

    我的测试dimens:

    --默认的dimens.xml

    <resources>
        <dimen name="activity_horizontal_margin">5dp</dimen>
        <dimen name="activity_vertical_margin">5dp</dimen>
    </resources>

    --hdpi的dimens.xml:

    <resources>
        <dimen name="activity_horizontal_margin">50dp</dimen>
        <dimen name="activity_vertical_margin">50dp</dimen>
    </resources>

    --xhdpi的dimens.xml:

    <resources>
        <dimen name="activity_horizontal_margin">500dp</dimen>
        <dimen name="activity_vertical_margin">100dp</dimen>
    </resources>

    测试布局:

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent">
    
        <TextView
            android:layout_centerInParent="true"
            android:background="#000000"
            android:layout_width="@dimen/activity_horizontal_margin"
            android:layout_height="@dimen/activity_vertical_margin"/>
    
    </RelativeLayout>

    在不同分辨率手机下的效果:(为了好看一些,图片大小被我拉伸过),下面依次为:ldpi,mdpi,hdpi,hdpi(删除hdpi对应的dimens之后),xhdpi,xxhdpi

               (ldpi)                                        (mdpi)   

                 (hdpi)                              hdpi(删除hdpi对应的dimens之后)    

             (xhdpi)                                      (xxhdpi)

    分析结果:

    1.ldpi和mdpi在没有对应的dimens的情况下,会去加载默认的dimens。而ldpi和mdpi和hdpi可以共用一套。 所以默认的dimens放hdpi的标准。

    2.hdpi,xhdpi,xxhdpi会加载最近的dimens文件,所以删除hdpi对应的之后,加载了xhdpi的dimens。      所以要放一套hdpi的dimens。

    3.xhdpi和xxhdpi用的一套标准,他们又会加载最近的。                                                                     所以要放一套xhdpi的。

     

    3.关于图片的适配

    也是分两种考虑

    1.大图且内容复杂的   2.小图和大图但是内容简单的

    有上面贴出的基本知识可算出,ldpi,mdpi和hdpi的宽缩放比例是一样的;xhdpi和xxhpdi的长宽是一样的。

     

    所以关于图片部分的解决方案就是:

    1.小图和大图但是内容简单的:

        我们就把图片的控件写死,让图片的xy适配控件,发生变形。 只用切一套图,这样图片会有拉伸的情况出现,但是大图但是比如纯色的,拉伸也看不出来,小图拉伸也不明显。所以就这样做。

     

      所以小图或大图且内容简单的解决方案就是,写死控件,让图片的xy适配控件。

    2.大图且内容复杂的:        

        这种图片拉伸变形明显,所以我们要针对不同分辨率做处理:

             其中xhdpi(1280*720)和xxhdpi(1920*1080)他们的长宽缩放是成比例的,都是1.5。所以他们可以共用一套图片。放在xhdpi对应的drawable目录下或者xxhdpi对应的drawable目录下即可。

               hdpi,mdpi,ldpi,是不成比例的,所以要想获得最佳的适配效果,我们需要分别适配这三套,但是我觉得按现在市场是的手机情况,我们在适配一下hdpi就可以了。

        所以大图且复杂的解决方案就是,适配两套,xhdpi的和hdpi的。

     

    (ps:这里讨论的是app原生布局的适配,所以不适用于填充的图片是动态变化的且长宽不成比例的情况,比如,用户上传图片,这里为健壮还要做很多处理,不在讨论的范围内)

    4.最后大概讲讲现有的适配方案

    除了用dimens适配还有用layout布局文件适配的方案,通过代码动态设置的方案(我之前启动界面用过一个gif图片 ,就用的动态设置)

     

    5.附上dimens转换的代码

    对于px,dp,sp,dimens,权重这些基本概念我就不在这里一一介绍了。

    转换dimens的代码:old放的是适配xhdpi的,

    转换比例:

    水平:是xhdpi屏幕宽的一半是180dp除以hdpi屏幕宽的一半是160dp得到的1.125.

    竖直:是........................320dp...................................367dp得到的1.1985

     

    这样的话只要完美适配一套xhdpi的,然后生成hdpi的就好了。

    你需要区分你布局中写的参数是水平方向的,还是竖直方向的,下面代码中changes是转换因子,转换两次,水平一次,竖直一次,自己替换转换因子;

    package convert;
    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.File;
    import java.io.FileReader;
    import java.io.FileWriter;
    import java.io.IOException;
    
    public class DimensTools {
         static String oldFilePath = "src/convert/dimens.xml";
         
         static String filePathHdpi="src/convert/dimensHdpi.xml";
         
      
         static float changes = 1.125f;
         public static void main(String[] args) {
              String st = convertStreamToString(oldFilePath, changes);
              DeleteFolder(filePathHdpi);
              writeFile(filePathHdpi, st);
         }
         public static String convertStreamToString(String filepath, float f) {
              StringBuilder sb = new StringBuilder();
              try {
                   BufferedReader bf = new BufferedReader(new FileReader(filepath));
                   String line = null;
                   System.out.println("q1");
                   String endmark = "dp</dimen>";
                   String startmark = ">";
                   while ((line = bf.readLine()) != null) {
                        if (line.contains(endmark)) {
                             int end = line.lastIndexOf(endmark);
                             int start = line.indexOf(startmark);
                             String stdp = line.substring(start + 1, end);
                             //int dp = Integer.parseInt(stpx);
                             float dp=Float.parseFloat(stdp);
                             //float newdp =  ((float) dp / f);
                             
                             System.out.println("dp:"+dp);
                             
                             float newdp=dp/f;
                             
                             System.out.println("newdp:"+newdp);
                             
                             String dpStr=String.valueOf(dp);
                             String newline;
                             if(dpStr.contains(".0")){
                                 int x=dpStr.indexOf(".");
                                 System.out.println("x:"+x);
                                 dpStr= dpStr.substring(0,x);
                                 newline= line.replace(dpStr + "dp", newdp + "dp");
                             }else{
                                 newline = line.replace(dp + "dp", newdp + "dp");
                             }
                             
                             System.out.println("newline:"+newline);
                             sb.append(newline + "\r\n");
                        } else {
                             sb.append(line + "\r\n");
                        }
                   }
                  // System.out.println(sb.toString());
              } catch (IOException e) {
                   e.printStackTrace();
              }
              return sb.toString();
         }
         public static boolean DeleteFolder(String sPath) {
              File file = new File(sPath);
              if (!file.exists()) { 
                   return true;
              } else {
                   if (file.isFile()) { 
                        return deleteFile(sPath);
                   } else { 
                   // return deleteDirectory(sPath);
                   }
              }
              return false;
         }
         public static void writeFile(String filepath, String st) {
              try {
                   FileWriter fw = new FileWriter(filepath);
                   BufferedWriter bw = new BufferedWriter(fw);
                   bw.write(st);
                   bw.flush();
                   bw.close();
              } catch (IOException e) {
                   e.printStackTrace();
              }
         }
         public static boolean deleteFile(String sPath) {
              boolean flag = false;
              File file = new File(sPath);
              if (file.isFile() && file.exists()) {
                   file.delete();
                   flag = true;
              }
              return flag;
         }
    }

     

    补充:有人问到美工怎么出视觉规范,给android出一套xhdpi的就行,单位用px标。自己按上面的基础知识,转成xhdpi的dp单位。最后用代码自动生成hdpi的一套就好了。 

     

    最后,我也是自己摸索,有什么问题,还望大家指点。

     

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-1-11 20:55 , Processed in 0.070396 second(s), 27 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表