Android智能平板应用,界面适配的另一种轻量级方法

简介: Android智能平板应用,界面适配的另一种轻量级方法

Android的界面适配,很常见的需求。


各种设备种类和尺寸那么多,基于一种原型设计好的界面,换到另一种设备上去若不适配全乱套了。好在还是有很多方案的,这减少了不少的开发工作量。最流行的就是头条的方案了,使用也超级简单。然而,如果不想引入,还可以简单的一个工具类实现,原理类似于头条的方案。


这里简单介绍下,使用起来也很简单。


原理就是转换设备的显示像素密度Density。


头条的UI适配的低成本方案AndroidAutoSize也是基于这个原理,只是它封装的更好,稳定性也更好。



就是智能平板UI尺寸虽然不一样,但是长宽比例差不多。比如基于1920*1080的界面尺寸设计的应用,现在新的设备屏幕是1366x768。若不加适配肯定显示不全,若能等比例缩小0.71倍就好了,那么方法是有的。就一个类文件Density.java


package com.newcapec.visitorsystem.utils;
import android.content.Context;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.WindowManager;
public class Density {
    /**
     * 设置屏幕像素密度
     * 思路讲解,计算 B601的老固件像素密度1.5 ,新固件像素密度1 600*32/48 = 400
     * 首先我们需要获取当前机型的屏幕密度信息:appDensity,appScaleDensity
     *
     * 我们的设计尺寸会根据默认机型计算出一个固定的以dp为单位的宽度:WIDTH
     *
     * 比如:默认机型的宽高为1080*1920,该设备的屏幕密度为3
     * 那么WIDTH = 1080/3 = 360dp;因此所有适配机型的宽也就等于360dp。
     * 根据 屏幕宽度 / 屏幕密度=WIDTH公式,现在知道屏幕宽度和WIDTH,也就能求出:屏幕密度=屏幕宽度 / WIDHT;
     *
     * 现在屏幕宽度(dp):targetDensity = displayMetrics.widthPixels / WIDTH 求出。
     *
     * 接下来,就需要求出适配机型的scaleDensity
     *
     * appScaleDensity / appDensity = targetScaleDensity / targetDensity ;
     *
     * targetScaleDensity = targetDensity * (appScaleDensity / appDensity) ;
     *
     * densityDpi = density * 160 ;
     *
     * 最后,把获取到的数据,设置到activity的displayMetrics中。
     *
     * 计算出来后,我们需要在绘制view之前先设置好
     *
     * 在onCreate中的setContentView之前添加
     * ———————————————
     * 原文链接:https://blog.csdn.net/weixin_45365889/article/details/102660467
     */
    private final static float WIDTH = 1920;//适配机型的宽为1920dp,屏幕宽/屏幕密度=1920/1=1920
    private static float appDensity;
    private static float appScaleDensity;
    public static void setDensity(Context appcontx, Context contx) {
        //获取当前app的屏幕显示信息
        WindowManager wm = (WindowManager)appcontx.getSystemService(Context.WINDOW_SERVICE);
        int width = wm.getDefaultDisplay().getWidth();
        Log.d("Utils","app width:"+width);
        DisplayMetrics displayMetrics = appcontx.getResources().getDisplayMetrics();
        appDensity = displayMetrics.density;
        appScaleDensity = displayMetrics.scaledDensity;
        Log.d("Utils","appDensity:"+appDensity+",appScaleDensity:"+appScaleDensity);
        //计算等比缩放后的density和scaleDensity
        //WIDTH相对于所有屏幕宽度都是相等的,它是用dp作为单位,所以 屏幕宽度/屏幕密度=WIDTH
        //targetDensity = targetWidht/WIDTH
        float targetDensity = displayMetrics.widthPixels / WIDTH;
        //appScaleDensity/appDensity=targetScaleDensity/targetDensity;
        float targetScaleDensity = targetDensity * (appScaleDensity / appDensity);
        int targetDensityDpi = (int) (targetDensity * 160);
        //替换activity的density,appdensity,densityDpi
        DisplayMetrics aDisplayMertics = contx.getResources().getDisplayMetrics();
        Log.d("Utils","presentDensity:"+aDisplayMertics.density+",presentScaleDensity:"+aDisplayMertics.scaledDensity);
        aDisplayMertics.density = targetDensity;
        aDisplayMertics.scaledDensity = targetScaleDensity;
        aDisplayMertics.densityDpi = targetDensityDpi;
        Log.d("Utils","targetDensity:"+targetDensity+",targetScaleDensity:"+targetScaleDensity);
    }
}


注意把里面的WIDTH配置为原设计模型的宽度。


原理介绍



首先我们需要获取当前机型的屏幕密度信息:appDensity,appScaleDensity


我们的设计尺寸会根据默认机型计算出一个固定的以dp为单位的宽度:WIDTH


比如:默认机型的宽高为1080*1920,该设备的屏幕密度为3


那么WIDTH = 1080/3 = 360dp;因此所有适配机型的宽也就等于360dp。


根据 屏幕宽度 / 屏幕密度=WIDTH公式,现在知道屏幕宽度和WIDTH,也就能求出:屏幕密度=屏幕宽度 / WIDHT;


现在屏幕宽度(dp):targetDensity = displayMetrics.widthPixels / WIDTH 求出。


接下来,就需要求出适配机型的scaleDensity


appScaleDensity / appDensity = targetScaleDensity / targetDensity ;


targetScaleDensity = targetDensity * (appScaleDensity / appDensity) ;


densityDpi = density * 160 ;


最后,把获取到的数据,设置到activity的displayMetrics中。


计算出来后,我们需要在绘制view之前先设置好。


使用方法


在BaseActivity的onCreate中调用一下就可以了。


Utils.setDensity(App.getContext(),this);


package com.newcapec.visitorsystem.activity.frontscreen;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import androidx.annotation.Nullable;
import com.newcapec.visitorsystem.app.App;
import com.newcapec.visitorsystem.threads.ReadCardThread;
import com.newcapec.visitorsystem.utils.Utils;
public class BaseActivity extends Activity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Utils.setDensity(App.getContext(),this);
    }
    /*
     * 隐藏系统键盘
     */
    public void hideXtView(){
        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
        View view = this.getCurrentFocus();
        if (view != null) {
            InputMethodManager inputMethodManager = (InputMethodManager) this.getSystemService(Activity.INPUT_METHOD_SERVICE);
            inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
        }
    }
}


以上只是一个简单的方法,可作为一个学习界面适配原理的例子。但是对于自定义view和listview,RecyclerView是失效的。


这里再介绍下基于头条的UI适配的低成本方案AndroidAutoSize:


AndroidAutoSize对于自定义view,listview,和RecyclerView适配也完全没问题,原理类似。


对于RecyclerView只需在Adapter 的onCreateViewHolder里,调用一下:


AutoSizeCompat.autoConvertDensityOfGlobal(context.getResources());


即可完美适配RecyclerView的UI显示。


AndroidAutoSize:


github地址


https://github.com/JessYanCoding/AndroidAutoSize


gradle引入


implementation 'me.jessyan:autosize:1.1.2'


manifase配置


如果只使用副单位 (pt、in、mm) 就可以直接以像素作为单位填写设计图的尺寸, 不需再把像素转化为 dp


<!-- 如果只使用副单位 (pt、in、mm) 就可以直接以像素作为单位填写设计图的尺寸, 不需再把像素转化为 dp-->
<!-- 用mm副单位开发,这里配置和设计稿一样的尺寸px , 1920 x 1080px -->
<manifest>
    <application>            
        <meta-data
            android:name="design_width_in_dp"
            android:value="1080"/>
        <meta-data
            android:name="design_height_in_dp"
            android:value="1920"/>           
     </application>           
</manifest>


注意上面的meta-data是原始设计尺寸的宽,高。可不用设置成新设备的屏幕尺寸了。


以上基本满足你的基本需求了,若还有问题,可以参见这个贴,汇总了常见问题的解决办法:


https://github.com/JessYanCoding/AndroidAutoSize/issues/13


还有一种屏幕适配方案,原理跟上述的差不多,是AndroidScreenAdaptation。


AndroidScreenAdaptation:


地址:https://github.com/yatoooon/AndroidScreenAdaptation


AndroidScreenAdaptation库特点:


完全不用改变自己的布局编写习惯,你原先是怎么写布局,就怎么写布局.不用去继承适配类,不用在最外层包裹适配布局,不用新建茫茫多的分辨率适配文件夹,不要求强制使用px为单位,可以实时预览布局,全面屏或带虚拟按键手机适配也没问题。


使用:


1.添加依赖


implementation 'me.yatoooon:screenadaptation:1.1.1'


2.初始化工具类


(1)创建自己的application继承Application


public class App extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        ScreenAdapterTools.init(this);
    }
//如果应用屏幕固定了某个方向不旋转的话(比如qq和微信),下面可不写.
    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        ScreenAdapterTools.getInstance().reset(this);
    }
}


(2)在AndroidManifest.xml文件中声明使用你自己创建的application并且添加meta-data数据,例子上标明了这些数据的代表的意义


<application
        android:name=".App"
        .....
        <meta-data
            android:name="designwidth"
            android:value="1080" />  //设计图的宽,单位是像素,推荐用markman测量,量出来如果是750px那么请尽量去找ui设计师要一份android的设计图.
        <meta-data
            android:name="designdpi"
            android:value="480" />   //设计图对应的标准dpi,根据下面的那张图找到对应的dpi,比如1080就对应480dpi,如果拿到的是其他宽度的设计图,那么选择一个相近的dpi就好了
        <meta-data
            android:name="fontsize"
            android:value="1.0" />   //全局字体的大小倍数,有时候老板会觉得你的所有的字小了或者大了,你总不能一个一个去改吧
        <meta-data
            android:name="unit"
            android:value="px" />   //你的布局里面用的是px这就写px,你的布局里面用的是dp这就写dp,要统一,不要一会儿px一会儿dp,字体也用px或者dp,不要用sp,微信qq用的肯定不是sp.
</application>    



3. 开始使用


(1)在Activity中,找到setcontentview(R.layout.xxxxxx)


public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_dp);
        //在setContentView();后面加上下面这句话
        ScreenAdapterTools.getInstance().loadView((ViewGroup) getWindow().getDecorView());
    }
}


注: 自定义view的话,在 ScreenAdapterTools.getInstance().loadView((ViewGroup) view); 外面包裹一层判断如下,不然在使用自定义view编写布局文件时预览xml会有问题!但不影响真机运行效果.


       if (!isInEditMode()) {
            ScreenAdapterTools.getInstance().loadView((ViewGroup) view);
        }    


原理


1. px是分辨率的单位 比如现在主流手机分辨率1080*1920.


2. dp是安卓开发专有的单位 在 不同的手机下 1dp = 不同的 px.


3. sp是字体大小(前面清单文件中要求字体也用dp或者px),sp随系统字体大小变化而变化,但据我观察,像微信qq这些app的字体是不随系统显示字体大小变化的.


### 本库是按照设计图的宽度和对应标准dpi来适配的(宽度增加或减少,高度同比例增加或减少),在不同的分辨率,不同ppi(手机屏幕密度,又称为dpi),不同最小宽度(有的人喜欢去调开发者选项下面的最小宽度,主流手机默认为360dp)的手机下都做到了适配。


引用:


今日头条屏幕适配方案终极版 AndroidAutoSize-玩Android - wanandroid.com


安卓适配AutoSize详解_xxdw1992的博客-CSDN博客_me.jessyan:autosize


Android安卓中最棒的屏幕适配AndroidScreenAdaptation_快乐李同学的博客-CSDN博客_android screen


屏幕适配:修改屏幕像素密度,随便设dp_Android架构师丨小熊的博客-CSDN博客


Andoid屏幕适配终极手段(小编用过最得劲的dp适配)_奋斗的IT青年-CSDN博客_最小宽度多少dp让手机流畅


Android AutoLayout全新的适配方式 堪称适配终结者_Hongyang-CSDN博客_autolayout

相关文章
|
1天前
|
Java 编译器 Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
【5月更文挑战第1天】 在移动开发的世界中,性能优化始终是开发者关注的焦点。随着Kotlin的兴起,许多团队和开发者面临着一个选择:是坚持传统的Java语言,还是转向现代化、更加简洁的Kotlin?本文通过深入分析和对比Kotlin与Java在Android应用开发中的性能表现,揭示两者在编译效率、运行速度和内存消耗等方面的差异。我们将探讨如何根据项目需求和团队熟悉度,选择最适合的语言,以确保应用的高性能和流畅体验。
|
1天前
|
缓存 安全 Android开发
构建高效Android应用:采用Kotlin进行内存优化
【5月更文挑战第1天】随着移动设备的普及,用户对应用程序的性能要求越来越高。特别是对于Android开发者来说,理解并优化应用的内存使用是提升性能的关键。本文将探讨使用Kotlin语言在Android开发中实现内存优化的策略和技术。我们将深入分析Kotlin特有的语言特性和工具,以及它们如何帮助开发者减少内存消耗,避免常见的内存泄漏问题,并提高整体应用性能。
|
1天前
|
安全 Android开发 开发者
构建高效Android应用:采用Kotlin与Jetpack的实践指南
【4月更文挑战第30天】 在移动开发领域,随着技术的不断进步,为了提高应用的性能和用户体验,开发者们不断地探索新的工具和框架。对于Android平台而言,Kotlin语言以其简洁性和功能性成为了开发的首选。而Jetpack组件则提供了一套高质量的库、工具和指南,帮助开发者更轻松地构建高质量的应用程序。本文将探讨如何结合Kotlin语言和Jetpack组件来优化Android应用的开发流程,提升应用性能,并保证代码的可维护性和可扩展性。
|
1天前
|
Java 编译器 Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
【4月更文挑战第30天】在Android开发领域,Kotlin作为一种现代化的编程语言,因其简洁性和功能性受到了开发者的广泛欢迎。尽管与传统的Java相比,Kotlin提供了诸多便利,但关于其性能表现的讨论始终未息。本文将深入分析Kotlin和Java在Android平台上的性能差异,通过实际测试数据揭示两种语言在编译效率、运行速度以及内存占用方面的具体表现,并探讨如何利用Kotlin的优势来提升Android应用的整体性能。
|
2天前
|
移动开发 调度 Android开发
构建高效Android应用:Kotlin协程的实践之路
【4月更文挑战第30天】 在移动开发领域,性能优化与流畅的用户体验始终是开发者追求的目标。随着Kotlin语言在Android开发中的普及,其提供的协程特性成为了解决异步编程问题的有力工具。本文将通过深入分析Kotlin协程的原理与实践,展示如何在Android应用中利用协程提升响应速度和处理效率,同时保证代码的简洁性和可维护性。我们将从基本概念出发,逐步深入到协程的高级使用场景,帮助开发者构建更加高效的Android应用。
|
2天前
|
移动开发 Java Android开发
构建高效Android应用:Kotlin协程的实践之路
【4月更文挑战第30天】在移动开发领域,随着用户需求的不断增长和设备性能的持续提升,实现流畅且高效的用户体验已成为开发者的首要任务。针对Android平台,Kotlin协程作为一种新兴的异步编程解决方案,以其轻量级线程管理和简洁的代码逻辑受到广泛关注。本文将深入探讨Kotlin协程的概念、优势以及在实际Android应用中的运用,通过实例演示如何利用协程提升应用性能和响应能力,为开发者提供一条构建更高效Android应用的实践路径。
|
2天前
|
安全 网络安全 Android开发
云端防御策略:融合云服务与网络安全的未来构建高效的Android应用:从内存优化到电池寿命
【4月更文挑战第30天】 随着企业加速向云计算环境转移,数据和服务的云端托管成为常态。本文探讨了在动态且复杂的云服务场景下,如何构建和实施有效的网络安全措施来保障信息资产的安全。我们将分析云计算中存在的安全挑战,并展示通过多层次、多维度的安全框架来提升整体防护能力的方法。重点关注包括数据加密、身份认证、访问控制以及威胁检测与响应等关键技术的实践应用,旨在为读者提供一种结合最新技术进展的网络安全策略视角。 【4月更文挑战第30天】 在竞争激烈的移动市场中,Android应用的性能和资源管理已成为区分优秀与平庸的关键因素。本文深入探讨了提升Android应用效率的多个方面,包括内存优化策略、电池
|
Android开发
android和OPhone模拟器界面对比
 本文为原创,如需转载,请注明作者和出处,谢谢!     OPhone是中国移动推出的手机操作系统平台,是基于android的,只是做了一些扩展。
820 0
|
9天前
|
消息中间件 网络协议 Java
Android 开发中实现数据传递:广播和Handler
Android 开发中实现数据传递:广播和Handler
13 1