欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android虚拟键监听,并获取虚拟键高度

程序员文章站 2022-07-14 17:06:06
...
package com.ysl.pdf;

import android.app.Activity;
import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.widget.RelativeLayout;

/**
 * ViewTreeObserver.OnGlobalLayoutListener这个是监听布局和总只要有变化就会回调,如list的滑动等,比较敏感
 **/
public class BaseActivity extends Activity implements ViewTreeObserver.OnGlobalLayoutListener {
    /**
     * 该Activity的根布局rootView,Fragment或有些动态加载的布局操作一样的,取其根布局就好,
     **/
    RelativeLayout parent;
    private static final String TAG = "BaseActivity";
    private int mWidth = 0;
    /**
     * 设备的宽度
     **/
    private int mHeight = 0;

    /**
     * 设备的高度
     **/
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        parent = findViewById(android.R.id.content);
        mWidth = parent.getWidth();
        mHeight = parent.getHeight();
        /**这个监听如果在OnResume中注册,可能会被注册多次,所以选择这里,当然你也可以自己控制,保证值注册一次**/
        parent.getViewTreeObserver().addOnGlobalLayoutListener(this);

    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.e(TAG, "super.onPause();");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.e(TAG, "super.onResume();");
    }

    @Override
    public void onGlobalLayout() {/**这个方法,在ViewGroup中的子view生成(就是界面初始化)可能会被多次调用**/
        Log.e(TAG, "onGlobalLayout");
        onNavigationBarStatusChanged();
    }

    protected void onNavigationBarStatusChanged() {
        resetXY();
        // TODO: 2019/8/22  这里你也可能还会有其它事情处理,也就在这里完成,但是一定要在resetXY()之后,使用全局变量mWidth和mHeight

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        parent.getViewTreeObserver().removeOnGlobalLayoutListener(this);
    }

    /**
     * 下面几种方法是获取屏幕的宽高的,
     */
    private void getXYInfo() {
        /**Function1,这种方法获取到的是设备的宽高,(有些设备可以获取到除去虚拟键后的宽高,有些获取到的是定值和下面一样,为了适配所有设备强烈不建议使用这种)**/
        Display defaultDisplay = getWindowManager().getDefaultDisplay();
        Point point = new Point();
        defaultDisplay.getSize(point);
        int x = point.x;
        int y = point.y;
        Log.i(TAG, "x = " + x + ",y = " + y);

        /**Funtion2,这种其实和上面不同点是,这个是定值,设备一旦定型了,这个也就是定值,**/
        Point outSize = new Point();
        getWindowManager().getDefaultDisplay().getRealSize(outSize);
        int rx = outSize.x;
        int ry = outSize.y;
        Log.w(TAG, "x = " + rx + ",y = " + ry);

        /**Function3,这种也可以获取屏幕宽高,设配问题最后总结**/
        Rect routSize = new Rect();
        getWindowManager().getDefaultDisplay().getRectSize(routSize);
        int left = routSize.left;
        int top = routSize.top;
        int right = routSize.right;
        int bottom = routSize.bottom;
        Log.d(TAG, "left = " + left + ",top = " + top + ",right = " + right + ",bottom = " + bottom);

        /**Function4,这红也可以获取屏幕宽高**/
        DisplayMetrics outMetrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(outMetrics);
        int widthPixels = outMetrics.widthPixels;
        int heightPixels = outMetrics.heightPixels;
        Log.i(TAG, "widthPixels = " + widthPixels + ",heightPixels = " + heightPixels);

        /**补充下,很多时候大家可能会看到网上有下面这种**/
        WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics outMetrics0 = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(outMetrics0);
        int width = outMetrics0.widthPixels;
        int height = outMetrics0.heightPixels;
        /**
         其实通过getSystemService获取WindowManager和getWindowManager().getDefaultDisplay()获取WindowManager都可以的,
         就像在动态添加View的时候大家使用的LayoutInflate一样,也可以通过LayoutInflate inflate=getSystemService(Context.LAYOUT_INFLATER_SERVICE)获取一样的

         自己在测试一台基于Android7.0的主板上开发的软件的时候,有个问题是,上面几种情况都获取到的是屏幕宽高的定值,所以并不能通过指望它们的变化来知晓是否设备底部虚拟键是否显示,
         也在网上找了些资料,但是都没有满意的办法,也有可能只是别人的笔记,方便它们自己在需要的时候看自己笔记而已,所以害的自己来
         **/
    }

    /**
     * 这个时候我们就需要思考虚拟键的显示与隐藏对我们布产生挤压的原因,挤压后我们的布局都发生了变化,说的简单点,虚拟键的的显示挤压了根布局rootView,最外层ViewGroup变化了,高度(某些设备横屏时宽度)
     * 变化了,那我们就只需要在onGlobalLayout()方法中测量rootView的高度(或宽度)不就好了么,(注意:这里不考虑屏幕旋转的情况,旋转的情况也就是Activity的生命周期发生率改变而已,让监听的注册次数发生了变化,这个
     * 开篇就说了开发者自己处理,这里就不提了),好了,我们知道了原因后,就来处理。
     **/
    private void resetXY() {
        if (mWidth != 0 && mWidth < parent.getWidth()) {

        }
        if (mHeight != 0 && mHeight < parent.getWidth()) {//说明现在隐藏了底部虚拟键

        } else if (mHeight != 0 && mHeight == parent.getWidth()) {//不论是当前是否隐藏虚拟键,这时候表示上次和这次的操作都没有去改变虚拟键

        } else if (mHeight != 0 && mHeight > parent.getWidth()) {//说明现在底部虚拟键显示了

        }
        // TODO: 2019/8/22  mHeight操作一样,因为只可能是X或者Y一个方向改变,所以根据你的业务需求来设置mWidth或mHeight就好
        mWidth = parent.getWidth();
        mHeight = parent.getHeight();

    }
    /**
     总结下为什么会这么麻烦,那是没办法,我开发的东西在原生的Android系统上跑的,没有经过手机开发商二次开发,所有只能这样,我设备上的虚拟键可以再任何一个界面任何一个时候都可以打开或者关闭不同于单纯的手机,在设置中操作
     另外还有一个比较有意思的是:
     如果我不用 mHeight=parent.getHeight();,而是用mHeight=parent.getPivotY();得到的结果是parent.getHeight()的值得一半,这样在回调中用它也能区分是否开启了虚拟键或者是否隐藏了***/
}
相关标签: 移动

上一篇: Handler 使用

下一篇: Handler倒计时