华为小米等折叠屏适配研究

        市面上折叠屏陆续出了几款手机,我们产品也下发了适配折叠屏的需求,以下对折叠屏是撇工作做一个记录,中间也包含网络搜罗资料整理,供大家参考。

一、目前主流折叠屏机型:

厂商 型号折叠分辨率展开分辨率
华为HUAWEI Mate Xs

主屏:2480 x 1148

副屏:2480 x 892

2480 x 2200
华为HUAWEI Mate X2外屏:2700 x 11602480 x 2200
小米MIX FOLD外屏:2520 x 8402480 x 1860
三星Galaxy Z Fold2外屏:2260 x 8162208 x 1768

二、折叠屏的物理姿态:

三、折叠屏的物理切分:

四、针对折叠屏基础的适配方案:

1、屏幕兼容性的支持:

(1)应用 resizeable 能力支持

设置方法:在 manifest 文件的或节点中设置 android:resizeableActivity 的值为 true,可 声明应用支持自适应显示,Activity 将能以分屏和 freeform 模式启动。

示例代码:

android:resizeableActivity=["true" | "false"] 

   (2)增加申明应用支持的屏幕比范围

申明最大比例:

通过在 < meta-data> 添加 android.max_aspect 声明的方式

示例代码:

<meta - data android: name = "android.max_aspect"   android: value = "2.4" / >

申明最小比例

通过在 < meta-data> 添加 android.max_aspect 声明的方式

示例代码:

 < meta - data android: name = "android.min_aspect"   android: value = "1.0" / >

 2、屏幕连续性的支持:

为了保证您的应用程序在展开/折叠过程无缝切换,您需要做应用连续性的设计,以确保您的应用程序任务不中断,

以MateX 为例,最佳的体验为,应用在展开切换过程中,不发生应用的重启,且切换之前的任务和应用相关状态得以保存和延续,

折叠展开的动作,会触发对smallestscreensize、screensize和screenlayout的配置更改。通过注册监听系统configchanges消息,

不重启应用的情况下处理配置更改,您需要向manifest中添加android:configchanges属性,其中至少包含以下值:

< activity

android: name == ".MyActivity"

  android: configChanges = "screenSize|smallestScreenSize|screenLayout" / >

需要复写 onConfigurationChanged() 方法,通过该方法的newConfig参数获得屏幕的分辨率等信息,就可以针对不同比例屏幕下的应用界面布局做相应调整,如切换布局、调整控件位置和间距等。

@Override

public void onConfigurationChanged(Configuration newConfig) {

    super.onConfigurationChanged(newConfig);

    Log.i("test", "newConfig.screenHeightDp:" + newConfig.screenHeightDp +

        ", newConfig.screenWidthDp" + newConfig.screenWidthDp);

    //根据屏幕分辨率信息调整应用的布局

    ...

}

2.2:我们研究过程中总结的较为通用的方案:

根据华为开发者文档提供的适配需要在每个页面和控件的 onConfigurationChanged方法中对页面进行重新布局和排版,实际测试过程中发现几乎每个页面都需要重新设置,工作量非常大,(我们使用的适配方案为smallestWidth 限定符最小宽度适配方案,在大屏幕进入页面,切换小屏幕时页面元素尺寸变得非常大,字体也非常大,因为大屏幕使用的大尺寸的dp,切换时没有自动切换sw文件夹)。后来发现在基类的attachBaseContext方法中判断是否是折叠屏的展开状态,重新设置Context,使其强制使用小屏幕的sw尺寸,代码如下:

@Override
protected void attachBaseContext(Context newBase) {
  
  super.attachBaseContext(FoldingScreenUtils.attachBaseContext(newBase));
}

 并在基类Activity的onConfigChanged回调中重新设置Context,避免小屏幕进入页面时不会调用方法,

  @Override
  public void onConfigurationChanged(Configuration newConfig) {
    FoldingScreenUtils.onConfigurationChanged(this,newConfig);
    super.onConfigurationChanged(newConfig);
  }

 工具类如下:


import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.util.DisplayMetrics;

public class FoldingScreenUtils {
    public static final float MAX_WIDTH_HEIGHT = 3f / 4f;

    /**
     * 会创建一个新的Context来替代baseContext用以设置sw
     * @param context
     * @return
     */
    public static Context attachBaseContext(Context context) {
        if (isFoldingScreen(context)) {
            Resources resources = context.getResources();
            Configuration configuration = resources.getConfiguration();
            DisplayMetrics displayMetrics = resources.getDisplayMetrics();
            int smallestScreenWidthDp = configuration.smallestScreenWidthDp;
            // 8.0需要使用createConfigurationContext处理
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                return updateResources(context, smallestScreenWidthDp);
            } else {
                configuration.smallestScreenWidthDp = (int) (smallestScreenWidthDp * 0.52);
                resources.updateConfiguration(configuration, displayMetrics);
                return context;
            }
        } else {
            return context;
        }
    }

    @TargetApi(Build.VERSION_CODES.N)
    private static Context updateResources(Context context, int smallestScreenWidthDp) {
        Resources resources = context.getResources();
        Configuration configuration = resources.getConfiguration();
        configuration.smallestScreenWidthDp = (int) (smallestScreenWidthDp * 0.52);
        return context.createConfigurationContext(configuration);
    }

    /**
     * 返回当前设备是否是展开状态折叠屏,目前没有提供准确api,暂用屏幕宽高比判断.
     *
     * @param context 上下文
     * @return 是否是折叠屏展开状态
     */
    public static boolean isFoldingScreen(Context context) {
        Resources resources = context.getResources();
        DisplayMetrics displayMetrics = resources.getDisplayMetrics();
        float widthPixels = displayMetrics.widthPixels * 1.0f;
        float heightPixels = displayMetrics.heightPixels * 1.0f;
        return widthPixels / heightPixels > MAX_WIDTH_HEIGHT;
    }

    /***
     * 根据新屏幕参数判断是否是折叠屏宽屏状态.
     * @param newConfig context取值不准时拿到onConfigurationChanged中的新屏幕参数
     * @return 是否是折叠屏的宽屏状态
     */
    @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB_MR2)
    public static boolean isFoldingScreen(Configuration newConfig) {
        return (float) newConfig.screenWidthDp / (float) newConfig.screenHeightDp > MAX_WIDTH_HEIGHT;
    }

    /**
     * 只用这个方法来更新config
     * @param context
     * @param newConfig
     */
    public static void onConfigurationChanged(Context context, Configuration newConfig) {
        try {
            if (isFoldingScreen(context)) {
                newConfig.smallestScreenWidthDp = (int) (newConfig.smallestScreenWidthDp * 0.52);
                context.getResources().updateConfiguration(newConfig, context.getResources().getDisplayMetrics());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

大家有注意到我们工具类中isFoldingScreen方法有两份重写,一个是使用activity类的Context参数取当前屏幕的宽高来判断比例,但在一些popWindow和Dialog中并不能直接实现此方法,需要在类中传入的context监听ComponentCallbacks全局的状态改变回调,

 context.registerComponentCallbacks(new ComponentCallbacks() {
            @Override
            public void onConfigurationChanged(Configuration newConfig) {
                
            }

            @Override
            public void onLowMemory() {

            }
        });

但是当屏幕改变时注册时的context中取出的屏幕宽高已经不准,所以需要用onConfigurationChanged中返回的newConfig对象取当前准确的屏幕尺寸来判断是否是展开状态的折叠屏,目前当前厂家和google并没有提供具体api来判断是否是折叠屏,所以暂时通过这种方法判断,同时对pad也有一定适配效果。

注意在控件销毁时做解除监听处理:

context.unregisterComponentCallbacks

 参考文档:

https://developer.huawei.com/consumer/cn/doc/90101  华为折叠屏应用开发指导

https://www.jianshu.com/p/83efb0eaeee3 Android 折叠屏适配攻略

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值