Android全面屏最大纵横比适配

遇到的问题

在项目开发中遇到屏幕底部或顶部出现了黑条,页面没有全部占满屏幕,情况如下:
屏幕底部或顶部出现黑条

解决方案

影响因素:
1 项目 targetSdkVerion 值
2 项目是否支持分屏模式:
如果设置了android:resizeableActivity=“true”,则代表支持分屏模式。(此设置只针对Activity有效)

设置最大纵横比方法:
方法一: 在AndroidManifest.xml中节点下做如下配置即可:

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

其中ratio_float为浮点数,官方建议为2.1或更大,因为18.5:9=2.055555555……,如果日后出现纵横比更大的手机,此值将需要设为更大。

方法二:max_aspect值也可以在Java代码中动态地设置,通过下面的方法即可实现:

public void setMaxAspect() {
        ApplicationInfo applicationInfo = null;
        try {
            applicationInfo = getPackageManager().getApplicationInfo(getPackageName(), PackageManager.GET_META_DATA);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        if(applicationInfo == null){
            throw new IllegalArgumentException(" get application info = null, has no meta data! ");
        }
        applicationInfo.metaData.putString("android.max_aspect", "2.1");
    }

场景1:
targetSdkVerion >= 26或者支持分屏模式,删除最大纵横比设置:
删除最大纵横比方法:删除android:name="android.max_aspect"即可,Android会自动根据屏幕调节(推荐)
场景2:
targetSdkVerion >= 26且不支持分屏模式时,删除最大纵横比设置或者将其设置为最大值:
(1)删除最大纵横比方法:删除android:name="android.max_aspect"即可,Android会自动根据屏幕调节(推荐)
(2)设置最大纵横比

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

场景三:
targetSdkVerion <= 25且不支持分屏模式时(android:resizeableActivity API 级别 24 添加的,如果应用面向 API 级别 24 或更高级别,但未对该属性指定值,则该属性的值默认设为 true):
默认的apsect ratio为1.86,必须对最大纵横比进行设置,否则在大于1.86的手机上运行App会出现黑条的现象。

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

解释下什么是最大屏幕纵横比

android官网的解释
理解:
当Activity设置了分屏模式:android:resizeableActivity=“true”,则maxAspectRatio属性将失效(即"android.max_aspect"属性将不起作用)

原理:

// 解析activity时候如设置了maxAspectRatio就将设置好的传输进去。
 private Activity parseActivity(Package owner, Resources res,
            XmlResourceParser parser, int flags, String[] outError, CachedComponentArgs cachedArgs,
            boolean receiver, boolean hardwareAccelerated)
            throws XmlPullParserException, IOException {
	if (sa.hasValue(R.styleable.AndroidManifestActivity_maxAspectRatio)
                    && sa.getType(R.styleable.AndroidManifestActivity_maxAspectRatio)
                    == TypedValue.TYPE_FLOAT) {
                a.setMaxAspectRatio(sa.getFloat(R.styleable.AndroidManifestActivity_maxAspectRatio,
                        0 /*default*/));
            }
            ....
//接着看一下setMaxAspectRatio,先判断是否可以resize,也就是前面的android:resizeableActivity="false"。
private void setMaxAspectRatio(float maxAspectRatio) {
            if (info.resizeMode == RESIZE_MODE_RESIZEABLE
                    || info.resizeMode == RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) {
                // Resizeable activities can be put in any aspect ratio.
                return;
            }

            if (maxAspectRatio < 1.0f && maxAspectRatio != 0) {
                // Ignore any value lesser than 1.0.
                return;
            }

            info.maxAspectRatio = maxAspectRatio;
            mHasMaxAspectRatio = true;
        }

//如果没有该属性 再设置默认的。
    private static final float DEFAULT_PRE_O_MAX_ASPECT_RATIO = 1.86f;
    ....
    /**
     * Sets every the max aspect ratio of every child activity that doesn't already have an aspect
     * ratio set.
     */
    private void setMaxAspectRatio(Package owner) {
        // Default to (1.86) 16.7:9 aspect ratio for pre-O apps and unset for O and greater.
        // NOTE: 16.7:9 was the max aspect ratio Android devices can support pre-O per the CDD.
        float maxAspectRatio = owner.applicationInfo.targetSdkVersion < O
                ? DEFAULT_PRE_O_MAX_ASPECT_RATIO : 0;
                //android o 之前的用默认1.86,之后的就根据手机;屏幕。

        if (owner.applicationInfo.maxAspectRatio != 0) {
            // Use the application max aspect ration as default if set.
            maxAspectRatio = owner.applicationInfo.maxAspectRatio;
        } else if (owner.mAppMetaData != null
                && owner.mAppMetaData.containsKey(METADATA_MAX_ASPECT_RATIO)) {
            maxAspectRatio = owner.mAppMetaData.getFloat(METADATA_MAX_ASPECT_RATIO, maxAspectRatio);
        }

        for (Activity activity : owner.activities) {
            // If the max aspect ratio for the activity has already been set, skip.
            if (activity.hasMaxAspectRatio()) {
                continue;
                //如果activity已经有这个属性了就不在重新设置,如果没有在设置一个默认的。
            }

            // By default we prefer to use a values defined on the activity directly than values
            // defined on the application. We do not check the styled attributes on the activity
            // as it would have already been set when we processed the activity. We wait to process
            // the meta data here since this method is called at the end of processing the
            // application and all meta data is guaranteed.
            final float activityAspectRatio = activity.metaData != null
                    ? activity.metaData.getFloat(METADATA_MAX_ASPECT_RATIO, maxAspectRatio)
                    : maxAspectRatio;

            activity.setMaxAspectRatio(activityAspectRatio);
        }
    }

// frameworks/base/services/core/java/com/android/server/am/ActivityRecord.java
/**
     * Computes the bounds to fit the Activity within the bounds of the {@link Configuration}.
     */
    // TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer.
    private void computeBounds(Rect outBounds) {
        outBounds.setEmpty();
        final float maxAspectRatio = info.maxAspectRatio;
        final ActivityStack stack = getStack();
        if (task == null || stack == null || !task.mFullscreen || maxAspectRatio == 0
                || isInVrUiMode(getConfiguration())) {
            // We don't set override configuration if that activity task isn't fullscreen. I.e. the
            // activity is in multi-window mode. Or, there isn't a max aspect ratio specified for
            // the activity. This is indicated by an empty {@link outBounds}. We also don't set it
            // if we are in VR mode.
            return;
            //如果是0直接就pass了没有后面计算过程了。
        }
        ...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值