Android关于虚拟控件、全面屏及悬浮球机型适配时遇到的问题

现在市面上全面屏的手机,有些机型存在悬浮球的设置。在界面设计的时候就要考虑如全面屏/虚拟键/悬浮球三种情形的关于控件适配的问题。当遇到一些视频显示及图片显示时,全面屏/虚拟控件/悬浮球状态时会对控件进行缩放。这样就使得原本按比例显示的视频和图片出现拉伸的情况出现。这时我们要设定比例的控件不受全面屏/虚拟控件的显示及隐藏/悬浮球显示与否的影响。

1、全面屏:


2、虚拟控件隐藏:

3、悬浮球显示:

一,首先讨论虚拟键隐藏的情形:

虚拟键在不隐藏时,没有任何设置的话。控件设置为充满decorView时,虚拟键会占用显示空间,这样就要隐藏虚拟键,如下设置会隐藏虚拟键且不占用显示空间。

@SuppressLint("ResourceAsColor")
    public static void hideBottomUIMenu(Activity context) {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            context.getWindow().setNavigationBarColor(Color.parseColor("#00000000"));
        }
        //隐藏虚拟按键,并且全屏
        if (Build.VERSION.SDK_INT > 11 && Build.VERSION.SDK_INT < 19) { // lower api
            View v = context.getWindow().getDecorView();
            v.setSystemUiVisibility(View.GONE);
        } else if (Build.VERSION.SDK_INT >= 19) {
            //for new api versions.
            View decorView = context.getWindow().getDecorView();
            int uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION  //导航键不占显示屏幕的空间
                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION               //隐藏导航键(这里指时隐藏虚拟键)
                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY              //浸入式布局,当侧边划出导航键时自动隐藏
                    | View.SYSTEM_UI_FLAG_FULLSCREEN;
            decorView.setBackgroundColor(R.color.black);                //设置decorView背景为黑色
            decorView.setSystemUiVisibility(uiOptions);
        }
    }

二.接下来全面屏的设置的时候:

全面屏设置后,不会在出现虚拟键。这样控件设置为充满decorView时,就会充满整个屏幕。

三.设置显示悬浮球

当设置悬浮球后,如没有加入如下的设置。则当悬浮球操作时虚拟键显示且占用显示空间,而当加入如下的设置后,当悬浮球操作后,虚拟键会显示且不占用显示空间之后虚拟键不会隐藏。

int uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION ; //导航键不占显示屏幕的空间

四.现在假设一个videoView控件(为不让显示视频或者图片不拉伸)按照1080*1920的比例值横屏方式显示,在屏幕不显示不完的区域为decorView的背景色。而videovView控件显示在整个屏幕的中央位置的需求。

  • 现在构造如下的工具类:
package com.example.demo1;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
import android.os.Build;
import android.provider.Settings;
import android.support.annotation.RequiresApi;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.view.View;

import java.lang.reflect.Method;

/**
 * @author wangyongyao
 * @package com.example.demo1
 * @date 2019-07-18 20:15
 * @decribe TODO
 * @project
 */
public class NavigationBarUtils {

    public final static float STANDARD_SCREEN_SCALE = 1080f / 1920f;


    @SuppressLint("ResourceAsColor")
    public static void hideBottomUIMenu(Activity context) {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            context.getWindow().setNavigationBarColor(Color.parseColor("#00000000"));
        }
        //隐藏虚拟按键,并且全屏
        if (Build.VERSION.SDK_INT > 11 && Build.VERSION.SDK_INT < 19) { // lower api
            View v = context.getWindow().getDecorView();
            v.setSystemUiVisibility(View.GONE);
        } else if (Build.VERSION.SDK_INT >= 19) {
            //for new api versions.
            View decorView = context.getWindow().getDecorView();
            int uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION  //导航键不占显示屏幕的空间
                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION               //隐藏导航键(这里指时隐藏虚拟键)
                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY              //浸入式布局,当侧边划出导航键时自动隐藏
                    | View.SYSTEM_UI_FLAG_FULLSCREEN;
            decorView.setBackgroundColor(R.color.black);                //设置decorView背景为黑色
            decorView.setSystemUiVisibility(uiOptions);
        }
    }

    /**
     * 屏幕宽高比例与1080/1920对比
     * @param dm
     * @return
     */
    public static boolean isHWProportion(DisplayMetrics dm) {
        float scale = dm.heightPixels / (dm.widthPixels * 1.0f);
        if (scale <= STANDARD_SCREEN_SCALE) {
            return true;
        }else {
            return false;
        }
    }

    /**
     * 截取显示控件的宽高按照 1080/1920的比例
     * @param dm
     * @return
     */
    public static float[] getRootHeightAndWidth(DisplayMetrics dm) {
        float[] hw = new float[2];
        if (isHWProportion(dm)) {
            hw[0] = dm.heightPixels;
            hw[1] = dm.heightPixels / STANDARD_SCREEN_SCALE;
        }else {
            hw[0] = dm.widthPixels * STANDARD_SCREEN_SCALE;
            hw[1] = dm.widthPixels;
        }
        return hw;
    }

    /**
     * 判断当前设备是手机还是平板,代码来自 Google I/O App for Android
     * @param context
     * @return 平板返回 True,手机返回 False
     */
    public static boolean isPad(Context context) {
        return (context.getResources().getConfiguration().screenLayout
                & Configuration.SCREENLAYOUT_SIZE_MASK)
                >= Configuration.SCREENLAYOUT_SIZE_LARGE;
    }

    //判断是否存在NavigationBar
    public static boolean hasNavigationBar(Context context) {
        boolean hasNavigationBar = false;
        Resources rs = context.getResources();
        int id = rs.getIdentifier("config_showNavigationBar", "bool", "android");
        if (id > 0) {
            hasNavigationBar = rs.getBoolean(id);
        }
        try {
            //反射获取SystemProperties类,并调用它的get方法
            Class systemPropertiesClass = Class.forName("android.os.SystemProperties");
            Method m = systemPropertiesClass.getMethod("get", String.class);
            String navBarOverride = (String) m.invoke(systemPropertiesClass, "qemu.hw.mainkeys");
            if ("1".equals(navBarOverride)) {
                hasNavigationBar = false;
            } else if ("0".equals(navBarOverride)) {
                hasNavigationBar = true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return hasNavigationBar;
    }


    /**
     * 全面屏(是否开启全面屏开关 0 关闭  1 开启)
     *
     * @param context
     * @return
     */
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
    public static boolean navigationGestureEnabled(Context context) {
        int val = Settings.Global.getInt(context.getContentResolver(), getDeviceInfo(), 0);
        return val != 0;
    }

    /**
     * 获取设备信息(目前支持几大主流的全面屏手机,亲测华为、小米、oppo、魅族、vivo都可以)
     *
     * @return
     */
    private static String getDeviceInfo() {
        String brand = Build.BRAND;
        if(TextUtils.isEmpty(brand)) return "navigationbar_is_min";

        if (brand.equalsIgnoreCase("HUAWEI")) {
            return "navigationbar_is_min";
        } else if (brand.equalsIgnoreCase("XIAOMI")) {
            return "force_fsg_nav_bar";
        } else if (brand.equalsIgnoreCase("VIVO")) {
            return "navigation_gesture_on";
        } else if (brand.equalsIgnoreCase("OPPO")) {
            return "navigation_gesture_on";
        } else {
            return "navigationbar_is_min";
        }
    }


}
  • 构造一个使得videoView按照1080*1920比例显示的方法后在虚拟键是否隐藏和Android平板上显示屏幕的中央位置:
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
    private void adjustFullScreenLayout(Context mContext, Activity mActivity) {
        DisplayMetrics dm = mContext.getResources().getDisplayMetrics();

        int cHeight = (int) NavigationBarUtils.getRootHeightAndWidth(dm)[0];
        int cWidth = (int) NavigationBarUtils.getRootHeightAndWidth(dm)[1];
        if (NavigationBarUtils.isPad(mActivity)) {
            int height = dm.heightPixels;
            int diffHeight = (int) (height - NavigationBarUtils.getRootHeightAndWidth(dm)[0]);
            mLayoutParams.width = (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, cWidth, mContext.getResources().getDisplayMetrics()));
            mLayoutParams.height = (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, cHeight, mContext.getResources().getDisplayMetrics()));
            marginLayoutParams.setMargins(0, cHeight / 20,0,0);
        } else {
            if (NavigationBarUtils.isHWProportion(dm)) {
                int width = dm.widthPixels;
                int diffWidth = (int) (width - NavigationBarUtils.getRootHeightAndWidth(dm)[1]);
                mLayoutParams.width = (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, cWidth, mContext.getResources().getDisplayMetrics()));
                mLayoutParams.height = (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, cHeight, mContext.getResources().getDisplayMetrics()));
                if (NavigationBarUtils.hasNavigationBar(mActivity)) {
                    if (NavigationBarUtils.navigationGestureEnabled(mActivity)) {
                        //全面屏时
                        marginLayoutParams.setMargins(diffWidth / 2,0,diffWidth / 2,0);
                    }else {
                        //隐藏虚拟键
                        marginLayoutParams.setMargins(diffWidth,0,0,0);
                    }
                }else {
                    marginLayoutParams.setMargins(diffWidth / 2,0,diffWidth / 2,0);
                }
            }else {
                int height = dm.heightPixels;
                int diffHeight = (int) (height - NavigationBarUtils.getRootHeightAndWidth(dm)[0]);
                mLayoutParams.width = (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, cWidth, mContext.getResources().getDisplayMetrics()));
                mLayoutParams.height = (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, cHeight, mContext.getResources().getDisplayMetrics()));
//                if (NavigationBarUtils.hasNavigationBar(mContext)) {
//                    if (NavigationBarUtils.navigationGestureEnabled(mContext)) {
//                        marginLayoutParams.setMargins(0,diffHeight / 2,0,diffHeight / 2);
//                    }else {
//                        marginLayoutParams.setMargins(cWidth / 26,diffHeight / 2,0,diffHeight / 2);
//                    }
//                }else {
                    marginLayoutParams.setMargins(0,diffHeight / 2,0,diffHeight / 2);
//                }
            }
        }
    }
  • 在view显示时隐藏虚拟控件:
@Override
    protected void onResume() {
        super.onResume();
        NavigationBarUtils.hideBottomUIMenu(this);
    }
  • 最后,在设置悬浮球后,点击悬浮球后会显示虚拟键。虽在onResume()方法中设置隐藏虚拟键的操作。但最终虚拟键显示后就没有消失。经过生命周期的打印输出,操作悬浮球后回到activity中并没有走onResume()这方法。现在考虑悬浮球的是操作只是夺取了activity显示的焦点并没有让activity重走onResume(),这样就要了解activity中另一个方法onWindowFocusChanged()这个方法,其在activity失去焦点和获取焦点中调用。
 @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        NavigationBarUtils.hideBottomUIMenu(this);
    }

 

如下贴上videoView按照1080*1920比例显示的代码:

package com.example.demo1;

import android.app.Activity;
import android.content.Context;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.ViewGroup;
import android.widget.RelativeLayout;

import java.util.HashSet;
import java.util.Set;

public class MainActivity extends Activity {

    private RelativeLayout videoView;
    private ViewGroup.LayoutParams mLayoutParams;
    private ViewGroup.MarginLayoutParams marginLayoutParams = null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        initEvent();

    }

    private void initView() {
        videoView = (RelativeLayout) findViewById(R.id.rl_full_view);
        mLayoutParams = videoView.getLayoutParams();
        //获取view的margin设置参数
        if (mLayoutParams instanceof ViewGroup.MarginLayoutParams) {
            marginLayoutParams = (ViewGroup.MarginLayoutParams) mLayoutParams;
        } else {
            //不存在时创建一个新的参数
            //基于View本身原有的布局参数对象
            marginLayoutParams = new ViewGroup.MarginLayoutParams(mLayoutParams);
        }

    }

    private void initEvent() {

    }


    @Override
    protected void onResume() {
        super.onResume();
        NavigationBarUtils.hideBottomUIMenu(this);
    }

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        NavigationBarUtils.hideBottomUIMenu(this);
    }

    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
    private void adjustFullScreenLayout(Context mContext, Activity mActivity) {
        DisplayMetrics dm = mContext.getResources().getDisplayMetrics();

        int cHeight = (int) NavigationBarUtils.getRootHeightAndWidth(dm)[0];
        int cWidth = (int) NavigationBarUtils.getRootHeightAndWidth(dm)[1];
        if (NavigationBarUtils.isPad(mActivity)) {
            int height = dm.heightPixels;
            int diffHeight = (int) (height - NavigationBarUtils.getRootHeightAndWidth(dm)[0]);
            mLayoutParams.width = (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, cWidth, mContext.getResources().getDisplayMetrics()));
            mLayoutParams.height = (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, cHeight, mContext.getResources().getDisplayMetrics()));
            marginLayoutParams.setMargins(0, cHeight / 20,0,0);
        } else {
            if (NavigationBarUtils.isHWProportion(dm)) {
                int width = dm.widthPixels;
                int diffWidth = (int) (width - NavigationBarUtils.getRootHeightAndWidth(dm)[1]);
                mLayoutParams.width = (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, cWidth, mContext.getResources().getDisplayMetrics()));
                mLayoutParams.height = (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, cHeight, mContext.getResources().getDisplayMetrics()));
                if (NavigationBarUtils.hasNavigationBar(mActivity)) {
                    if (NavigationBarUtils.navigationGestureEnabled(mActivity)) {
                        //全面屏时
                        marginLayoutParams.setMargins(diffWidth / 2,0,diffWidth / 2,0);
                    }else {
                        //隐藏虚拟键
                        marginLayoutParams.setMargins(diffWidth,0,0,0);
                    }
                }else {
                    marginLayoutParams.setMargins(diffWidth / 2,0,diffWidth / 2,0);
                }
            }else {
                int height = dm.heightPixels;
                int diffHeight = (int) (height - NavigationBarUtils.getRootHeightAndWidth(dm)[0]);
                mLayoutParams.width = (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, cWidth, mContext.getResources().getDisplayMetrics()));
                mLayoutParams.height = (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, cHeight, mContext.getResources().getDisplayMetrics()));
//                if (NavigationBarUtils.hasNavigationBar(mContext)) {
//                    if (NavigationBarUtils.navigationGestureEnabled(mContext)) {
//                        marginLayoutParams.setMargins(0,diffHeight / 2,0,diffHeight / 2);
//                    }else {
//                        marginLayoutParams.setMargins(cWidth / 26,diffHeight / 2,0,diffHeight / 2);
//                    }
//                }else {
                    marginLayoutParams.setMargins(0,diffHeight / 2,0,diffHeight / 2);
//                }
            }
        }
    }

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值