【Android】通过手机系统设置放大字体后,样式布局错乱解决方案

1. 所有的Activity都继承同一个BaseActivity

2. 在BaseActivity的attachBaseContext方法中获取系统出厂时的DPI的

    @Override
    protected void attachBaseContext(Context newBase) {
        Resources res = newBase.getResources();
        Configuration configuration = res.getConfiguration();
        int defaultDpi = getScreenHelper().getDefaultDpi(newBase);
        configuration.fontScale = FONT_SCALE;    //固定字体大小
        configuration.densityDpi = defaultDpi;   //固定DPI显示
        Context newContext = newBase.createConfigurationContext(configuration);
        super.attachBaseContext(newContext);
    }
    
3. ScreenHelper.java用来获取默认的DPI

4. 配置IWindowManager.aidl
具体添加方式可以参考
https://blog.csdn.net/u010378579/article/details/48413901?utm_medium=distribute.pc_relevant.none-task-blog-baidulandingword-2&spm=1001.2101.3001.4242
 

ScreenHelper.java


import android.annotation.SuppressLint;
import android.content.Context;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.IWindowManager;
import android.view.WindowManager;


import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**Screen Helper Class to get default dpi .*/
public class ScreenHelper {

    /**Dcm Log Tag .*/
    private static final String TAG = "ScreenHelper";

    /**The defalut LDPI value .*/
    private static final int LDPI = DisplayMetrics.DENSITY_DEFAULT;
    /**The defalut HDPI value .*/
    private static final int HDPI = DisplayMetrics.DENSITY_HIGH;
    /**The defalut XHDPI value .*/
    private static final int XHDPI = DisplayMetrics.DENSITY_XHIGH;
    /**The defalut XXHDPI value .*/
    private static final int XXHDPI = DisplayMetrics.DENSITY_XXHIGH;
    /**The 560 dpi value .*/
    private static final int DPI_560 = DisplayMetrics.DENSITY_560;

    /**The defalut XXXHDPI value .*/
    private static final int XXXHDPI = DisplayMetrics.DENSITY_XXXHIGH;

    /** The standard 720p device width.*/
    private static final int DEFALUT_SCREEN_WIDTH = 720;
    /** The standard 1080p device width.*/
    private static final int MEDIUM_SCREEN_WIDTH = 1080;
    /** The standard 4k device width.*/
    private static final int HIGH_SCREEN_WIDTH = 1440;
    /** The standard max device width.*/
    private static final int MAX_SCREEN_WIDTH = 2160;

    /**The Max Screen DP to distinguish phone and tablet.*/
    private static final int MAX_SCREEN_DP = 600;
    /**Default Mode Name . */
    private static final String DEFAULT_MODE = "defaultMode";

    /**
     * getDefaultDpi.<br>
     * Note : get default dpi when Display Size has changed
     *
     * @param context attach activity context
     * @return  default dpi
     */
    public int getDefaultDpi(Context context) {
        WindowManager windowManager = (WindowManager) context
                .getSystemService(Context.WINDOW_SERVICE);
        Display display = windowManager.getDefaultDisplay();
        DisplayMetrics metrics = new DisplayMetrics();
        display.getRealMetrics(metrics);

        boolean changed = isChangedResolution(display, metrics);
        // if it is tablet,no need to keep current dpi
        if (isTablet(context)) {
            return metrics.densityDpi;
        } else if (changed) {
            // get special device dpi
            return getSpecialDeviceDpi(metrics);
        } else {
            return getInitialDisplayDensity(metrics);
        }
    }

    private int getInitialDisplayDensity(DisplayMetrics metrics) {
        int physicalDensity = metrics.densityDpi;
        boolean isError = false;
        try {
            @SuppressLint("PrivateApi") Class<?> clazz = Class.forName("android.os.ServiceManager");
            try {
                @SuppressLint("DiscouragedPrivateApi") Method method = clazz.getDeclaredMethod("checkService", String.class);
                try {
                    IWindowManager mWindowManager = IWindowManager.Stub.asInterface((IBinder) method.invoke(null, Context.WINDOW_SERVICE));
                    try {
                        if (mWindowManager != null) {
                            physicalDensity = mWindowManager.getInitialDisplayDensity(Display.DEFAULT_DISPLAY);
                        }
                    } catch (RemoteException e) {
                        e.printStackTrace();
                        isError = true;
                    }
                } catch (IllegalAccessException | InvocationTargetException e) {
                    e.printStackTrace();
                    isError = true;
                }
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
                isError = true;
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            isError = true;
        }
        if (isError) {
            physicalDensity = getSpecialDeviceDpi(metrics);
        }
        return physicalDensity;
    }

    /**
     * isChangedResolution.<br>
     * Note : check if huawei device
     *
     * @param display view display instance
     * @param displayMetrics view displayMetrics to get some device screen attr
     * @return true is huawei device,false is not
     */
    private boolean isChangedResolution(Display display, DisplayMetrics displayMetrics) {
        Display.Mode[] modes = display.getSupportedModes();
        if (modes.length > 1) {
            String displayInfo = display.toString();

            int firstIndex = displayInfo.indexOf(DEFAULT_MODE);
            int length = DEFAULT_MODE.length();
            String defaultModeInfo = displayInfo.substring(firstIndex);
            int firstSymbolIndex = defaultModeInfo.indexOf(",");
            String defaultMode = defaultModeInfo.substring(length, firstSymbolIndex);
            int defaultModeIndex = Integer.parseInt(defaultMode.replace(" ", ""));
            for (Display.Mode mode : modes) {
                if (mode.getModeId() == defaultModeIndex) {
                    int defaultWidth = mode.getPhysicalWidth();
                    return defaultWidth != displayMetrics.widthPixels;
                }
            }
        }

        // get the init screen Pixels
        int physicalWidth = display.getMode().getPhysicalWidth();
        int physicalHeight = display.getMode().getPhysicalHeight();

        // get current screen Pixels
        int currentWidth = displayMetrics.widthPixels;
        int currentHeight = displayMetrics.heightPixels;

        //if init size is different with current size, this means resolution
        //has changed
        if (physicalWidth != currentWidth && physicalHeight != currentHeight) {
            return true;
        }

        return false;
    }

    /**
     * getSpecialDeviceDpi.<br>
     * Note : when the Resolution could be changed, according to stardand Resolution to
     *        get the dpi
     *
     * @param displayMetrics display metrics instances
     * @return standard dpi
     */
    private int getSpecialDeviceDpi(DisplayMetrics displayMetrics) {
        int widthPixels = displayMetrics.widthPixels;
        int heightPixels = displayMetrics.heightPixels;

        // get min Pixels.
        int minPixels = Math.min(widthPixels, heightPixels);


        // get the apposite dpi
        if (minPixels < DEFALUT_SCREEN_WIDTH) {
            return HDPI;
        } else if (minPixels >= DEFALUT_SCREEN_WIDTH && minPixels < MEDIUM_SCREEN_WIDTH) {
            return XHDPI;
        } else if (minPixels >= MEDIUM_SCREEN_WIDTH && minPixels < HIGH_SCREEN_WIDTH) {
            return XXHDPI;
        } else if (minPixels >= HIGH_SCREEN_WIDTH && minPixels < MAX_SCREEN_WIDTH) {
            return DPI_560;
        } else {
            return XXXHDPI;
        }
    }

    /**
     * isTablet.<br>
     * Note : check if current device is tablet.
     *
     * @param context attach activity context
     * @return true is tablet, false is not
     */
    private boolean isTablet(Context context) {
        return context.getResources().getBoolean(R.bool.isTablet);
    }
}

 IWindowManager.aidl

// IWindowManger.aidl
package android.view;

// Declare any non-default types here with import statements

interface IWindowManager {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    int getInitialDisplayDensity(int displayId);
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值