伴职创作「banzhi.cc」书客创作[ibooker.cc]互联网科技

【Android】漂亮的圆角Dialog

2017-10-13  本文已影响388人  吾非言

作者:邹峰立,微博:zrunker,邮箱:zrunker@yahoo.com,微信公众号:书客创作,个人平台:www.ibooker.cc

本文选自书客创作平台第42篇文章。阅读原文

书客创作

Dialog是Android应用程序上在常见不过的一个控件,圆角Dialog的实现对于大多数开发者来说也是非常容易。最终只有一个目的就是将显示Dialog的视图显示成圆角即可。而对视图的布局样式设置,可以通过XML文件进行定义,在Android系统中提供< shape>来设置视图的基本布局样式。

一、理解shape

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">

    <!--大小
        height:高度值。
        width:宽度值。
    -->
    <size
        android:height="100dp"
        android:width="100dp"/>

    <!--内部填充色
        color:颜色值。
    -->
    <solid
        android:color="#FFFFFF" />

    <!--边框
        color:边框颜色。
        width:边框宽度。
        dashGap:虚线的间隔。
        dashWidth:虚线宽度。
        如果不设置dashGap,dashWidth默认是实线。
    -->
    <stroke
        android:color="#DEDEDE"
        android:width="1dp"
        android:dashGap="5dp"
        android:dashWidth="2dp"/>

    <!--圆角
        radius:设置四角半径。
        bottomLeftRadius:左下角半径。
        bottomRightRadius:右下角半径。
        topLeftRadius:左上角半径。
        topRightRadius:右上角半径。
    -->
    <corners
        android:radius="5dp"
        android:bottomLeftRadius="5dp"
        android:bottomRightRadius="5dp"
        android:topLeftRadius="5dp"
        android:topRightRadius="5dp"/>

    <!--颜色渐变
        angle:integer类型,渐变角度,0表示从左到右,90表示从下到上,必须是45的整数倍,默认0。
        startColor:开启渐变颜色。
        endColor:结束渐变颜色。
        centerColor:中间渐变颜色。
        centerX:float(0 ~ 1.0) 相对X的渐变位置。
        centerY:float(0 - 1.0) 相对Y的渐变位置。
        gradientRadius:float类型,渐变颜色的半径,单位应该是像素点。需要android:type="radial"。如果没有设置android:gradientRadius,将会报错,error inflating class。
        type:渐变类型:
            linear:线性渐变,可以理解为y=kx+b。
            radial:圆形渐变,起始颜色从cenralX,centralY点开始。
            sweep:扫线梯度渐变。
    -->
    <gradient
        android:angle="0"
        android:startColor="#FFFFFF"
        android:endColor="#FF00FF00"
        android:centerColor="#00FFFF"
        android:centerX="0.5"
        android:centerY="0.5"
        android:gradientRadius="20"
        android:type="radial" />

    <!--内间距
        bottom:距离底部内间距。
        left:距离左边内间距。
        right:距离右侧内间距。
        top:距离顶部内间距。
    -->
    <padding
        android:bottom="5dp"
        android:left="5dp"
        android:right="5dp"
        android:top="5dp"/>

</shape>

二、理解style

在Android的style.xml中,可以通过< style>标签设置窗体的主题样式,对于Dialog窗体常常会用到以下七种属性。

<style name="diydialog" parent="@android:style/Theme.Dialog">
    <item name="android:windowFrame">窗体边框(resource)</item>
    <item name="android:windowIsFloating">窗体是否浮现在activity之上(true/false)</item>
    <item name="android:windowIsTranslucent">窗体是否半透明(true/false)</item>
    <item name="android:windowNoTitle">窗体是否无标题(true/false)</item>
    <item name="android:windowBackground">窗体背景(resource)</item>
    <item name="android:backgroundDimEnabled">背景是否为半透明(true/false)</item>
    <item name="android:windowContentOverlay">窗体是否有遮盖(resource)</item>
</style>

三、实现圆角Dialog

方式一:通过style设置属性windowBackground为圆角背景。

1、在style.xml文件中自定义MyDialog。

<!--自定义MyDialog样式-->
<style name="MyDialog" parent="Theme.AppCompat.Dialog">
    <!-- 边框 -->
    <item name="android:windowFrame">@null</item>
    <!-- 无标题 -->
    <item name="android:windowNoTitle">true</item>
    <!-- 背景透明 -->
    <item name="android:windowBackground">@drawable/bg_mydialog</item>
    <!-- 悬浮在Activity上 -->
    <item name="android:windowIsFloating">true</item>
    <!-- 对话框是否有遮盖 -->
    <item name="android:windowContentOverlay">@null</item>
</style>

2、在drawable文件中创建bg_mydialog.xml。

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#FFFFFF" />
    <stroke android:color="#DEDEDE" android:width="1dp"/>
    <corners android:radius="5dp"/>
    <padding android:bottom="5dp" android:left="5dp" android:right="5dp" android:top="5dp"/>
    <size android:width="200dp" android:height="200dp"/>
</shape>

3、展示MyDialog

Dialog myDialog = new Dialog(this, R.style.MyDialog);
myDialog.show();

方式二:设置Dialog显示View为圆角背景。

1、在style.xml文件中自定义cornerdialog。

<!--自定义cornerdialog样式-->
<style name="cornerdialog" parent="Theme.AppCompat.Dialog">
    <!-- 边框 -->
    <item name="android:windowFrame">@null</item>
    <!-- 无标题 -->
    <item name="android:windowNoTitle">true</item>
    <!-- 背景透明 -->
    <item name="android:windowBackground">@android:color/transparent</item>
    <!-- 悬浮在Activity上 -->
    <item name="android:windowIsFloating">true</item>
    <!-- 对话框是否有遮盖 -->
    <item name="android:windowContentOverlay">@null</item>
</style>

2、布局文件:dialog_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:background="@drawable/bg_corners"
    android:minWidth="200dp"
    android:orientation="vertical">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:padding="30dp"
        android:text="@string/app_name"
        android:textColor="#555" />

</LinearLayout>

背景文件bg_corners.xml:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <corners android:bottomLeftRadius="5dp" android:bottomRightRadius="5dp" android:topLeftRadius="5dp" android:topRightRadius="5dp" />
    <solid android:color="#FFFFFF" />
    <stroke android:color="#DEDEDE" android:width="1dp"/>
    <corners android:radius="5dp"/>
    <padding android:bottom="5dp" android:left="5dp" android:right="5dp" android:top="5dp"/>
</shape>

3、自定义Dialog,加载布局文件。

/**
 * 自定义Dialog
 * Created by 邹峰立 on 2017/10/13 0013.
 */
public class CornerDialog extends Dialog {

    public CornerDialog(@NonNull Context context) {
        this(context, R.style.cornerdialog);
    }

    public CornerDialog(@NonNull Context context, @StyleRes int themeResId) {
        super(context, themeResId);
        init();
    }

    // 初始化
    private void init() {
        this.setContentView(R.layout.dialog_layout);
        // 其他设置
    }
}

4、展示CornerDialog

CornerDialog cornerDialog = new CornerDialog(this);
cornerDialog.show();

方式三:封装Dialog,自定义Dialog相关属性方法。

1、在style.xml文件中自定义diydialog。

<!-- 自定义diydialog样式 -->
<style name="diydialog" parent="@android:style/Theme.Dialog">
    <item name="android:windowFrame">@null</item>
    <!-- 边框 -->
    <item name="android:windowIsFloating">true</item>
    <!-- 是否浮现在activity之上 -->
    <item name="android:windowIsTranslucent">true</item>
    <!-- 半透明 -->
    <item name="android:windowNoTitle">true</item>
    <!-- 无标题 -->
    <item name="android:windowBackground">@drawable/bg_white_gray_border</item>
    <!-- 背景 -->
    <item name="android:backgroundDimEnabled">true</item>
    <!-- 是否为半透明 -->
</style>

背景文件bg_white_gray_border.xml:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <!--内容-->
    <solid android:color="#FFFFFF" />
    <!--四角-->
    <corners android:radius="5dp" />
    <!--边框-->
    <stroke
        android:width="0.6dp"
        android:color="#CCCCCC" />
</shape>

2、自定义DiyDialog,封装Dialog相关方法。

/**
 * 自定义Dialog
 * Created by 邹峰立 on 2017/7/6.
 */
public class DiyDialog {
    private Context context;
    private Dialog dialog;

    public enum DiyDialogGravity {
        GRAVITY_CENTER,
        GRAVITY_LEFT,
        GRAVITY_RIGHT,
        GRAVITY_TOP,
        GRAVITY_BOTTOM
    }

    public DiyDialog(@NonNull Context context, @NonNull View view) {
        this(context, R.style.diydialog, view);
    }

    public DiyDialog(@NonNull Context context, @StyleRes int themeResId, @NonNull View view) {
        dialog = new Dialog(context, themeResId);
        this.context = context;
        init(view);
    }

    /**
     * 初始化控件
     */
    private void init(View view) {
        dialog.setContentView(view);
        // 按返回键是否取消
        dialog.setCancelable(true);
        // 点击Dialog外围是否取消
        dialog.setCanceledOnTouchOutside(true);
        // 设置默认透明度0.2f
        this.setDimAmount(0.2f);
        // 设置默认居中显示
        this.setDiyDialogGravity(DiyDialogGravity.GRAVITY_CENTER);
    }

    /**
     * 设置Dialog显示内容
     *
     * @param view 内容View
     */
    private void setContentView(View view) {
        if (view != null)
            dialog.setContentView(view);
    }

    /**
     * 按返回键是否取消
     *
     * @param cancelable true 取消 false 不取消  默认true
     */
    public DiyDialog setCancelable(boolean cancelable) {
        if (dialog != null)
            dialog.setCancelable(cancelable);
        return this;
    }

    /**
     * 点击Dialog外围是否取消
     *
     * @param cancelable true 取消 false 不取消  默认false
     */
    public DiyDialog setCanceledOnTouchOutside(boolean cancelable) {
        if (dialog != null)
            dialog.setCanceledOnTouchOutside(cancelable);
        return this;
    }

    /**
     * 设置取消事件
     *
     * @param onCancelListener 取消事件
     */
    public DiyDialog setOnCancelListener(DialogInterface.OnCancelListener onCancelListener) {
        if (dialog != null)
            dialog.setOnCancelListener(onCancelListener);
        return this;
    }

    /**
     * 设置Dialog宽度
     *
     * @param proportion 和屏幕的宽度比(10代表10%) 0~100
     */
    public DiyDialog setDiyDialogWidth(int proportion) {
        if (dialog != null) {
            Window window = dialog.getWindow();
            if (window != null) {
                WindowManager.LayoutParams lp = window.getAttributes();
                lp.width = getScreenW(context) * proportion / 100;
                window.setAttributes(lp);
            }
        }
        return this;
    }

    /**
     * 设置Dialog高度
     *
     * @param proportion 和屏幕的高度比(10代表10%) 0~100
     */
    public DiyDialog setDiyDialogHeight(int proportion) {
        if (dialog != null) {
            Window window = dialog.getWindow();
            if (window != null) {
                WindowManager.LayoutParams lp = window.getAttributes();
                lp.height = getScreenH(context) * proportion / 100;
                window.setAttributes(lp);
            }
        }
        return this;
    }

    /**
     * 设置Dialog显示位置
     *
     * @param diyDialogGravity 左上右下中
     */
    public DiyDialog setDiyDialogGravity(DiyDialogGravity diyDialogGravity) {
        if (dialog != null) {
            Window window = dialog.getWindow();
            int gravity = Gravity.CENTER;
            if (diyDialogGravity == DiyDialogGravity.GRAVITY_BOTTOM) {
                gravity = Gravity.BOTTOM;
            } else if (diyDialogGravity == DiyDialogGravity.GRAVITY_CENTER) {
                gravity = Gravity.CENTER;
            } else if (diyDialogGravity == DiyDialogGravity.GRAVITY_LEFT) {
                gravity = Gravity.START;
            } else if (diyDialogGravity == DiyDialogGravity.GRAVITY_RIGHT) {
                gravity = Gravity.END;
            } else if (diyDialogGravity == DiyDialogGravity.GRAVITY_TOP) {
                gravity = Gravity.TOP;
            }
            if (window != null)
                window.getAttributes().gravity = gravity;
        }
        return this;
    }

    /**
     * 设置背景层透明度
     *
     * @param dimAmount 0~1
     */
    public DiyDialog setDimAmount(float dimAmount) {
        if (dialog != null) {
            Window window = dialog.getWindow();
            if (window != null) {
                WindowManager.LayoutParams lp = window.getAttributes();
                // 设置背景层透明度
                lp.dimAmount = dimAmount;
                window.setAttributes(lp);
            }
        }
        return this;
    }

    /**
     * 设置Window动画
     *
     * @param style R文件
     */
    public DiyDialog setWindowAnimations(int style) {
        if (dialog != null) {
            Window window = dialog.getWindow();
            if (window != null) {
                window.setWindowAnimations(style);
            }
        }
        return this;
    }

    /**
     * 展示Dialog
     */
    public void showDiyDialog() {
        if (dialog != null)
            dialog.show();
    }

    /**
     * 关闭Dialog
     */
    public void closeDiyDialog() {
        if (dialog != null) {
            dialog.cancel();
        }
    }

    /**
     * 获取屏幕宽度
     */
    private int getScreenW(Context context) {
        DisplayMetrics dm = context.getResources().getDisplayMetrics();
        return dm.widthPixels;
    }

    /**
     * 获取屏幕的高度
     */
    private int getScreenH(Context context) {
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics outMetrics = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(outMetrics);
        return outMetrics.heightPixels;
    }
}

3、展示DiyDialog,显示布局文件。布局文件dialog_diy_layout.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:minWidth="200dp"
    android:orientation="vertical">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:padding="30dp"
        android:text="@string/app_name"
        android:textColor="#555" />

</LinearLayout>
View diyDialogView = LayoutInflater.from(this).inflate(R.layout.dialog_diy_layout, null);
DiyDialog diyDialog = new DiyDialog(this, diyDialogView);
diyDialog.showDiyDialog();

以上三种方式都可以实现圆角Dialog,但论复用性,推荐使用方式三。方式三中可以任意显示任何布局文件,并且不会对已经设置好的布局样式进行影响。自定义方法采用构建者模式,对外提供链式结构方法调用。

Github地址
阅读原文


微信公众号:书客创作
上一篇 下一篇

猜你喜欢

热点阅读