Android今日头条适配方案对AlertDialog的影响

Android今日头条适配方案对AlertDialog的影响

前言

前段时间维护公司老项目时发现系统弹框显示不全,右边总是会少一部分,手机比较窄的直接只显示一半.然后找了半天才发现是使用的今日头适配方案。

今日头适配方案

先来说今日头适配方案,简单来说就是直接修改Activity的density值。但是我们在调用AlertDialog弹框时是不会去使用的这个density值,就会导致我的弹框超出屏幕。

使用:
在Application的onCreate方法中调用setDensity,并自己设定一个width,width是一个UI图的参照值,单位是dp,例如参照的是1280*720像素的XHDPI图,width就是720/2 = 360,这个根据你拿到的实际设计图来计算。
然后我们来看下px与dp的转换
在这里插入图片描述
不过现在我们可以不用直接去写Density类了,有大佬给你封装好了,拿去直接用,而且提供了取消适配的接口。传送门,具体的使用方法可以参考

Density类

 	private static float appDensity;
    private static float appScaledDensity;
    private static DisplayMetrics appDisplayMetrics;
    /**
     * 用来参照的的width
     */
    private static float WIDTH;

    public static void setDensity(@NonNull final Application application, float width) {
        appDisplayMetrics = application.getResources().getDisplayMetrics();
        WIDTH = width;
        registerActivityLifecycleCallbacks(application);
        if (appDensity == 0) {
            //初始化的时候赋值
            appDensity = appDisplayMetrics.density;
            appScaledDensity = appDisplayMetrics.scaledDensity;

            //添加字体变化的监听
            application.registerComponentCallbacks(new ComponentCallbacks() {
                @Override
                public void onConfigurationChanged(Configuration newConfig) {
                    //字体改变后,将appScaledDensity重新赋值
                    if (newConfig != null && newConfig.fontScale > 0) {
                        appScaledDensity = application.getResources().getDisplayMetrics().scaledDensity;
                    }
                }
                @Override
                public void onLowMemory() {
                }
            });
        }
    }
    private static void setDefault(Activity activity) {
        setAppOrientation(activity);
    }
    private static void setAppOrientation(@Nullable Activity activity) {
        float targetDensity = 0;
        try {
            targetDensity = appDisplayMetrics.widthPixels / WIDTH;
        } catch (NumberFormatException e) {
            e.printStackTrace();
        }
        float targetScaledDensity = targetDensity * (appScaledDensity / appDensity);
        int targetDensityDpi = (int) (160 * targetDensity);

        /**
         *
         * 最后在这里将修改过后的值赋给系统参数
         *
         * 只修改Activity的density值
         */
        DisplayMetrics activityDisplayMetrics = activity.getResources().getDisplayMetrics();
        activityDisplayMetrics.density = targetDensity;
        activityDisplayMetrics.scaledDensity = targetScaledDensity;
        activityDisplayMetrics.densityDpi = targetDensityDpi;
    }
    private static void registerActivityLifecycleCallbacks(Application application) {
        application.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
            @Override
            public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
                setDefault(activity);
            }
            @Override
            public void onActivityStarted(Activity activity) {
            }
            @Override
            public void onActivityResumed(Activity activity) {
            }
            @Override
            public void onActivityPaused(Activity activity) {
            }
            @Override
            public void onActivityStopped(Activity activity) {
            }
            @Override
            public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
            }
            @Override
            public void onActivityDestroyed(Activity activity) {

            }
        });
    }

AlertDialog

简单介绍一下AlertDialog,它是其他 Dialog的的父类!比如ProgressDialog,TimePickerDialog等,而AlertDialog的父类是:Dialog! 另外AlertDialog并不能直接new出来,如果你打开 AlertDialog的源码,会发现构造方法是protected的,如果我们要创建AlertDialog的话,我们 需要使用到该类中的一个静态内部类:public static class Builder,然后来调用AlertDialog 里的相关方法,来对AlertDialog进行定制,最后调用show()方法来显示我们的AlertDialog对话框。

回到我们的问题:调用AlertDialog弹框时没有使用的Avtiaity的density值,那么问题又来了,那自定义的Dialog,是不是也是这样呢?

我们先写一个AlertDialog

	 public static AlertDialog.Builder getDialog(Context context) {
	        return new AlertDialog.Builder(context, R.style.App_Theme_Dialog_Alert);
	 }

  	 public static AlertDialog.Builder getMessageDialog(
            Context context,
            String title,
            String message,
            boolean cancelable) {
        return getDialog(context)
                .setCancelable(cancelable)
                .setTitle(title)
                .setMessage(message)
                .setPositiveButton("确定", null);
    }

在写一个自定义的Dialog


public class ConfirmDialog extends Dialog {
    private Context context;
    private String content;
    private View sLine;
    private View inflate;
    private TextView dialog_textView, dialog_sure, dialog_cancel;
    private OnDialogInterfaceClickListener sureClickListener, cancelClickListener;
    private boolean outSide = true;
    private String strSureText = "确定",strCancelText = "取消";
    private boolean isShowSureView = true,isShowCancelView = true,isShowLineView = true;

    public ConfirmDialog(@NonNull Context context) {
        super(context, R.style.ActionSheetDialogStyle);
        this.context = context;
    }
    public ConfirmDialog setOnSureClickListener(OnDialogInterfaceClickListener sureClickListener){
        this.sureClickListener = sureClickListener;
        return this;
    }
    public ConfirmDialog setCanOutSide(boolean outSide){
        this.outSide = outSide;
        return this;
    }
    public ConfirmDialog setOnCancelClickListener(OnDialogInterfaceClickListener cancelClickListener){
        this.cancelClickListener = cancelClickListener;
        return this;
    }
    public ConfirmDialog setMessage(String message){
        this.content = message;
        return this;
    }
    public ConfirmDialog setSureText(String strSureText){
        this.strSureText = strSureText;
        return this;
    }
    public ConfirmDialog setCancelText(String strCancelText){
        this.strCancelText = strCancelText;
        return this;
    }
    public ConfirmDialog setShowSureView(boolean isShowSureView){
        this.isShowSureView = isShowSureView;
        this.isShowLineView = this.isShowSureView;
        return this;
    }
    public ConfirmDialog setShowCancelView(boolean isShowCancelView){
        this.isShowCancelView = isShowCancelView;
        this.isShowLineView = this.isShowCancelView;
        return this;
    }

    public ConfirmDialog builder() {
        initView();
        return this;
    }

    private void initView() {
        inflate = LayoutInflater.from(context).inflate(
                R.layout.sure_cancel_dialog, null);
        // 初始化控件
        dialog_textView = inflate.findViewById(R.id.dialog_textView);
        dialog_sure = inflate.findViewById(R.id.dialog_sure);
        dialog_cancel = inflate.findViewById(R.id.dialog_cancel);
        sLine = inflate.findViewById(R.id.s_line);
        dialog_sure.setText(strSureText);
        dialog_cancel.setText(strCancelText);

        if(!isShowLineView)
            sLine.setVisibility(View.GONE);
        if(!isShowCancelView)
            dialog_cancel.setVisibility(View.GONE);
        if(!isShowSureView)
            dialog_sure.setVisibility(View.GONE);

        if (sureClickListener != null) {
            dialog_sure.setOnClickListener(v -> {
                dismiss();
                sureClickListener.onDialogClick(this);
            });
        } else {
            dialog_sure.setOnClickListener(v -> dismiss());
        }

        if (cancelClickListener != null) {
            dialog_cancel.setOnClickListener(v -> {
                dismiss();
                cancelClickListener.onDialogClick(this);
            });
        } else
            dialog_cancel.setOnClickListener(v -> dismiss());
        dialog_textView.setText(content);
        setCanceledOnTouchOutside(outSide);
        setContentView(inflate);
    }

}

结果如下
在这里插入图片描述
????????为啥呢
看了一下代码,找到了自动定义Dialog中的setContentView(inflate),我们set了一个我们的自定义的一个View,这个View是我们使用适配方案后的产物,而AlertDialog是使用的原生系统的View,好吧破案了。

 inflate = LayoutInflater.from(context).inflate(
                R.layout.sure_cancel_dialog, null);


 setContentView(inflate);

解决方案

 public static void getMessageDialog(
            Context context,
            String message,
            boolean cancelable, DialogInterface.OnClickListener positiveListener) {
        AlertDialog dialog = new AlertDialog.Builder(context).create();
        dialog.setCancelable(cancelable);
        dialog.setMessage(message);
        dialog.setButton(AlertDialog.BUTTON_POSITIVE, "确定", positiveListener);
        dialog.show();
        WindowManager.LayoutParams lp = dialog.getWindow().getAttributes();
//设置宽高,高度默认是自适应的,宽度根据屏幕宽度比例设置
        lp.width = ScreenUtils.getScreenWidth(context) * 9 / 10;
//这里设置居中
        lp.gravity = Gravity.CENTER;
        dialog.getWindow().setAttributes(lp);
    }

我们在AlertDialog 的show()方法后设置dialog的弹出位置,这样我们就可以不管系统的原生View就可以把他固定到当前Avtivity上了,当然Dialog也可以这么做。ScreenUtils.getScreenWidth(context)是获取当前Activity的宽,好吧ScreenUtils工具类也贴出来吧

ScreenUtils工具类

public class ScreenUtils {
    private ScreenUtils()
    {
        /* cannot be instantiated */
        throw new UnsupportedOperationException("cannot be instantiated");
    }

    /**
     * 获得屏幕宽度
     *
     * @param context
     * @return
     */
    public static int getScreenWidth(Context context)
    {
        WindowManager wm = (WindowManager) context
                .getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics outMetrics = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(outMetrics);
        return outMetrics.widthPixels;
    }

    /**
     * 获得屏幕高度
     *
     * @param context
     * @return
     */
    public static int getScreenHeight(Context context)
    {
        WindowManager wm = (WindowManager) context
                .getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics outMetrics = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(outMetrics);
        return outMetrics.heightPixels;
    }

    /**
     * 获得状态栏的高度
     *
     * @param context
     * @return
     */
    public static int getStatusHeight(Context context)
    {

        int statusHeight = -1;
        try
        {
            Class<?> clazz = Class.forName("com.android.internal.R$dimen");
            Object object = clazz.newInstance();
            int height = Integer.parseInt(clazz.getField("status_bar_height")
                    .get(object).toString());
            statusHeight = context.getResources().getDimensionPixelSize(height);
        } catch (Exception e)
        {
            e.printStackTrace();
        }
        return statusHeight;
    }

    /**
     * 获取当前屏幕截图,包含状态栏
     *
     * @param activity
     * @return
     */
    public static Bitmap snapShotWithStatusBar(Activity activity)
    {
        View view = activity.getWindow().getDecorView();
        view.setDrawingCacheEnabled(true);
        view.buildDrawingCache();
        Bitmap bmp = view.getDrawingCache();
        int width = getScreenWidth(activity);
        int height = getScreenHeight(activity);
        Bitmap bp = null;
        bp = Bitmap.createBitmap(bmp, 0, 0, width, height);
        view.destroyDrawingCache();
        return bp;

    }

    /**
     * 获取当前屏幕截图,不包含状态栏
     *
     * @param activity
     * @return
     */
    public static Bitmap snapShotWithoutStatusBar(Activity activity)
    {
        View view = activity.getWindow().getDecorView();
        view.setDrawingCacheEnabled(true);
        view.buildDrawingCache();
        Bitmap bmp = view.getDrawingCache();
        Rect frame = new Rect();
        activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
        int statusBarHeight = frame.top;

        int width = getScreenWidth(activity);
        int height = getScreenHeight(activity);
        Bitmap bp = null;
        bp = Bitmap.createBitmap(bmp, 0, statusBarHeight, width, height
                - statusBarHeight);
        view.destroyDrawingCache();
        return bp;

    }

}
  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Android Studio中,可以通过AlertDialog来创建一个带有单个复选框的对话框。首先,我们需要创建一个AlertDialog.Builder对象,并设置它的标题和消息。然后,使用setMultiChoiceItems()方法来设置复选框的选项和默认选中的状态。接下来,我们可以通过调用setPositiveButton()和setNegativeButton()方法来设置对话框的确认按钮和取消按钮。最后,调用create()方法来创建AlertDialog对象并显示出来。 以下是一个示例代码: AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("请选择"); builder.setMultiChoiceItems(items, checkedItems, new DialogInterface.OnMultiChoiceClickListener() { @Override public void onClick(DialogInterface dialog, int which, boolean isChecked) { // 处理复选框的点击事件 } }); builder.setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // 处理确认按钮的点击事件 } }); builder.setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // 处理取消按钮的点击事件 } }); AlertDialog dialog = builder.create(); dialog.show(); 在onClick()方法中,我们可以处理复选框的点击事件,并根据需要执行相应的操作。在确认按钮和取消按钮的点击事件中,我们可以处理用户的确认或取消操作。最后,调用create()方法创建AlertDialog对象,并调用show()方法显示出对话框。这样,就实现了一个带有单个复选框的AlertDialog
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值