自定义仿IOS的圆角AlertDialog

2024-04-10 08:48

本文主要是介绍自定义仿IOS的圆角AlertDialog,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!


以前都比较经常看别人写的博客,比较少动手写,最近有时间,觉得可以将工作中积累下来的一些知识点,经验什么的记录在博客中,
有助于自己理解,水平有限,希望能够逐渐提升自己的能力。

先上个效果图 ,也可以根据自己需求,添加控件,也可以根据这种思路,自己去修改布局文件。

首先在styles文件里定义样式。

<style name="AlertDialogStyle" parent="@android:style/Theme.Dialog"><item name="android:windowBackground">@android:color/transparent</item><item name="android:windowContentOverlay">@null</item><item name="android:windowIsFloating">true</item><item name="android:windowFrame">@null</item><item name="android:backgroundDimEnabled">true</item><item name="android:windowNoTitle">true</item><item name="android:windowIsTranslucent">true</item>
</style>
接着再drawable文件夹下自定义一个圆角的shape
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<!-- radius 为圆角半径  -->
    <corners android:radius="20dp" ></corners>
    <solid android:color="#ffffff" />
</shape>

然后自定义一个dialog的xml布局, 并且设置背景引用圆角shape android:background="@drawable/bg_course_dialog"


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:tools="http://schemas.android.com/tools"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@drawable/bg_view_dialog_warm_tip"
    ><ImageView
        android:id="@+id/icon"
        android:layout_width="25dp"
        android:layout_height="25dp"
        android:layout_marginTop="28dp"
        android:layout_toLeftOf="@+id/title"
        android:src="@mipmap/ic_launcher_round"
        android:visibility="gone"
        /><TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_marginLeft="5dp"
        android:layout_marginTop="25dp"
        android:textColor="#000000"
        android:textSize="20sp"
        android:textStyle="bold"
        tools:text="titletitletitle"
        /><LinearLayout
        android:id="@+id/ll_content"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/title"
        android:layout_gravity="center_horizontal"
        android:layout_marginBottom="25dp"
        android:layout_marginLeft="15dp"
        android:layout_marginRight="15dp"
        android:layout_marginTop="5dp"
        android:gravity="center"
        android:orientation="vertical"
        ><TextView
            android:id="@+id/message"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="#000000"
            android:textSize="16sp"
            tools:text="message"/></LinearLayout><View
        android:id="@+id/line_horizontal"
        android:layout_width="match_parent"
        android:layout_height="0.5dp"
        android:layout_below="@+id/ll_content"
        android:visibility="gone"
        android:background="#dad6d6"/><LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/line_horizontal"
        android:orientation="horizontal"><TextView
            android:id="@+id/dialog_cancel"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginBottom="8dp"
            android:layout_marginTop="8dp"
            android:layout_weight="1"
            android:clickable="true"
            android:gravity="center"
            android:text="取消"
            android:textColor="#007aff"
            android:textSize="18sp"
            android:visibility="gone"/><View
            android:id="@+id/line_vertical"
            android:layout_width="0.5dp"
            android:layout_height="match_parent"
            android:background="#dad6d6"
            android:visibility="gone"/><TextView
            android:id="@+id/dialog_commit"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginBottom="8dp"
            android:layout_marginTop="8dp"
            android:layout_weight="1"
            android:gravity="center"
            android:text="确认"
            android:textColor="#007aff"
            android:textSize="18sp"
            android:visibility="gone"/></LinearLayout></RelativeLayout>

然后是封装的具体代码,这里使用alertdialog中的建造者模式Builder来建造,这样可以方便我们建造不同需求的dialog。
代码很简单 首先是构造一个Params来管理我们具体要build的属性
public static class Builder implements BuilderInterface {private Context mContext;
    private final ControllerParams mParams;
    private Controller mController;

    public Builder(Context context) {mContext = context;
        mParams = new ControllerParams();
        mController = new Controller(mContext);
    }public Builder setContentView(int layoutId) {mParams.setLayoutId(layoutId);
        return this;
    }public Builder setContentView(View view) {mParams.setContentView(view);
        return this;
    }public Builder setTitle(String title) {mParams.setTitle(title);
        return this;
    }public Builder reSetTitle(String title) {mParams.setTitle(title);
        mController.setTitle(title);
        return this;
    }public Builder reSetMessage(String message) {mParams.setMessage(message);
        mController.setMessage(message);
        return this;
    }public Builder reSetIcon(int iconId) {mParams.setIconId(iconId);
        mController.setIcon(iconId);
        return this;
    }public Builder setMessage(String message) {mParams.setMessage(message);
        return this;
    }public Builder setIcon(int iconId) {mParams.setIconId(iconId);
        return this;
    }public Builder setCancelable(boolean cancelable) {mParams.setCancelable(cancelable);
        return this;
    }public Builder setNegativeButton(String text, OnNegativeListener listener) {mParams.setNegativeListener(listener);
        mParams.setNegativeText(text);

        return this;
    }public Builder setPositiveButton(String text,  OnPositiveListener listener)  {mParams.setPositiveListener(listener);
        mParams.setPositiveText(text);
        return this;
    }/**
     * 建造dialog
     * @return dialog
     */
    public Dialog create() {Dialog dialog = new Dialog(mContext, R.style.AlertDialogStyle);
        //属性交给controller去应用到dialog        mParams.apply(mController, dialog);
        return dialog;
    }/**
     * 建造一个默认的dialog
     * @param onPositiveListener 确认按键监听
     * @param onNegativeListener 取消按键监听
     * @return dialog
     */
    public Dialog createDefault(OnPositiveListener onPositiveListener, OnNegativeListener onNegativeListener) {Dialog dialog = new Dialog(mContext, R.style.AlertDialogStyle);
        build(onPositiveListener, onNegativeListener);
        mParams.apply(mController, dialog);
        return dialog;
    }private void build(OnPositiveListener onPositiveListener, OnNegativeListener onNegativeListener) {setTitle("温馨提示").setMessage("确认提交吗").setCancelable(false).setPositiveButton("确认", onPositiveListener).setNegativeButton("取消", onNegativeListener);
    }
}

管理属性的类核心方法就是apply,在这里判断是否缓存了属性,有的话就交给controller去设置给dialog
/**
 * 管理dialog所有属性的类
 */
private static class ControllerParams {private String mTitle;
    private String mMessage;
    private int mIconId = -1;
    private int mLayoutId = -1;
    private boolean mCancelable;
    private String mPositiveText;
    private String mNegativeText;
    private OnPositiveListener mPositiveListener;
    private OnNegativeListener mNegativeListener;
    private View mContentView;


    private void apply(Controller controller, Dialog dialog) {if (mContentView != null) {controller.setContentView(mContentView, dialog);
        }else {controller.setContentView(mLayoutId, dialog);
        }dialog.setCancelable(mCancelable);
        if (mCancelable) {dialog.setCanceledOnTouchOutside(true);
        }if (mTitle != null) {controller.setTitle(mTitle);
        }if (mMessage != null) {controller.setMessage(mMessage);
        }if (mPositiveText != null && mPositiveListener != null) {controller.setPositiveButton(mPositiveText, mPositiveListener);
        }if (mNegativeText != null && mNegativeListener != null) {controller.setNegativeButton(mNegativeText, mNegativeListener);
        }if (mIconId != -1) {controller.setIcon(mIconId);
        }}public int getLayoutId() {return mLayoutId;
    }private void setLayoutId(int layoutId) {mLayoutId = layoutId;
    }public String getTitle() {return mTitle;
    }private void setTitle(String title) {mTitle = title;
    }public String getMessage() {return mMessage;
    }private void setMessage(String message) {mMessage = message;
    }public int getIconId() {return mIconId;
    }private void setIconId(int iconId) {mIconId = iconId;
    }public boolean isCancelable() {return mCancelable;
    }private void setCancelable(boolean cancelable) {mCancelable = cancelable;
    }public String getPositiveText() {return mPositiveText;
    }private void setPositiveText(String positiveText) {mPositiveText = positiveText;
    }public String getNegativeText() {return mNegativeText;
    }private void setNegativeText(String negativeText) {mNegativeText = negativeText;
    }public OnPositiveListener getPositiveListener() {return mPositiveListener;
    }private void setPositiveListener(OnPositiveListener positiveListener) {mPositiveListener = positiveListener;
    }public OnNegativeListener getNegativeListener() {return mNegativeListener;
    }private void setNegativeListener(OnNegativeListener negativeListener) {mNegativeListener = negativeListener;
    }private void setContentView(View contentView) {mContentView = contentView;
    }
}

这里定义2个点击监听,用来回调dialog中确认和取消的点击。
/**
 * 确认按键监听
 */
public interface OnPositiveListener {void onPositive(Dialog dialog);

}/**
 * 取消按键监听
 */
public interface OnNegativeListener {void onNegative(Dialog dialog);
}

这里controller中封装了最主要的代码,代码很简单,就是将上面写的dialog的 xml布局文件inflate出来设置给dialog,这也是封装好的默认的dialog 就跟一开始的效果图一样。但是我们说了,我们有可能有其他需求,这时候就需要用builder.setcontentview将我们需要的具体的view或者layoutid传进来,
这时候看代码,我们布局文件中的ll_content就会将默认的message的textview remove掉,然后再把穿件来的view添加进来。


private static class Controller implements View.OnClickListener,BuilderInterface {private Context mContext;
    private TextView mTvTitle;
    private TextView mTvMessage;
    private TextView mTvPositive;
    private TextView mTvNegative;
    private ImageView mIvIcon;
    private View mHorizontalLine;
    private View mVerticalLine;
    private View mRootView;
    private OnNegativeListener mOnNegativeListener;
    private OnPositiveListener mOnPositiveListener;
    private Dialog mDialog;
    private View mContentView;
    private final LinearLayout mLlContent;


    private   Controller(Context context) {mContext = context;
        mRootView = View.inflate(mContext, R.layout.view_dialog_warm_tip, null);
        mLlContent = (LinearLayout) mRootView.findViewById(R.id.ll_content);
        mHorizontalLine = mRootView.findViewById(R.id.line_horizontal);
    }private void setContentView(int layoutResID, Dialog dialog) {if (layoutResID == -1) {} else {mContentView = View.inflate(mContext, layoutResID, null);
            mLlContent.removeAllViews();
            mLlContent.addView(mContentView);
        }mDialog = dialog;
        dialog.setContentView(mRootView, getPrams(mContext));
    }private void setContentView(View view, Dialog dialog) {mLlContent.removeAllViews();
        mLlContent.addView(view);
        mDialog = dialog;
        dialog.setContentView(mRootView, getPrams(mContext));
    }private FrameLayout.LayoutParams getPrams(Context context) {WindowManager windowManager = (WindowManager) context
                .getSystemService(Context.WINDOW_SERVICE);
        Display sDefaultDisplay = windowManager.getDefaultDisplay();

        return new FrameLayout.LayoutParams((int) (sDefaultDisplay.getWidth() * 0.80f),
                ViewGroup.LayoutParams.WRAP_CONTENT);

    }public Controller setTitle(String title) {mTvTitle = (TextView) mRootView.findViewById(R.id.title);
        if (mTvTitle != null) {mTvTitle.setText(title);
        }return this;
    }public Controller setMessage(String message) {mTvMessage = (TextView) mRootView.findViewById(R.id.message);
        if (mTvMessage != null) {mTvMessage.setText(message);
        }return this;
    }public Controller setIcon(int iconId) {mIvIcon = (ImageView) mRootView.findViewById(R.id.icon);
        if (mIvIcon != null) {mIvIcon.setImageResource(iconId);
            mIvIcon.setVisibility(View.VISIBLE);
        }return this;
    }@Override
    public BuilderInterface setCancelable(boolean cancelable) {return null;
    }public Controller setNegativeButton(String negativeText, OnNegativeListener listener) {mTvNegative = (TextView) mRootView.findViewById(R.id.dialog_cancel);
        mVerticalLine = mRootView.findViewById(R.id.line_vertical);
        if (mTvNegative != null) {mTvNegative.setVisibility(View.VISIBLE);
            mTvNegative.setText(negativeText);
            setOnNegativeListener(listener);
            mHorizontalLine.setVisibility(View.VISIBLE);
            if (mTvPositive != null) {mVerticalLine.setVisibility(View.VISIBLE);
            }}return this;
    }public Controller setPositiveButton(String positiveText, OnPositiveListener listener) {mTvPositive = (TextView) mRootView.findViewById(R.id.dialog_commit);

        if (mTvPositive != null) {mTvPositive.setVisibility(View.VISIBLE);
            mTvPositive.setText(positiveText);
            setOnPositiveListener(listener);
            mHorizontalLine.setVisibility(View.VISIBLE);
        }return this;
    }private Controller setOnNegativeListener(OnNegativeListener onNegativeListener) {mOnNegativeListener = onNegativeListener;
        mTvNegative.setOnClickListener(this);
        return this;
    }private Controller setOnPositiveListener(OnPositiveListener onPositiveListener) {mOnPositiveListener = onPositiveListener;
        mTvPositive.setOnClickListener(this);
        return this;
    }@Override
    public void onClick(View v) {switch (v.getId()) {case R.id.dialog_cancel:
                if (mOnNegativeListener != null) {mOnNegativeListener.onNegative(mDialog);
                }break;
            case R.id.dialog_commit:
                if (mOnPositiveListener != null) {mOnPositiveListener.onPositive(mDialog);
                }break;
        }}
}


然后是在activity中的代码,使用方法就跟alerdialog一样,具体的可以看源码。
 
    private void initDefaultDialog() {SherlockDialog.Builder builder = new SherlockDialog.Builder(this);
        mDialog = builder.createDefault(this, this);
//        builder.reSetTitle("重新设置Tiltle");
    }private void initEditDialog() {SherlockDialog.Builder builder = new SherlockDialog.Builder(this);

        EditText editText = new EditText(this);
        builder.setContentView(editText);
        mDialog = builder.createDefault(this, this);

    }private void initDialog() {SherlockDialog.Builder builder = new SherlockDialog.Builder(this);
        mDialog = builder.setTitle("温馨提示").setMessage("确认提交吗?").setPositiveButton("确认", new SherlockDialog.OnPositiveListener() {@Override
                    public void onPositive(Dialog dialog) {Toast.makeText(DialogActivity.this, "确认提交", Toast.LENGTH_SHORT).show();
                        dialog.dismiss();
                    }}).setNegativeButton("取消", new SherlockDialog.OnNegativeListener() {@Override
                    public void onNegative(Dialog dialog) {Toast.makeText(DialogActivity.this, "取消提交", Toast.LENGTH_SHORT).show();
                        dialog.dismiss();
                    }}).setIcon(R.mipmap.ic_launcher_round).create();
    }public void button1(View view) {initDialog();
        mDialog.show();
    }public void button2(View view) {initEditDialog();
        mDialog.show();
    }public void button3(View view) {initDefaultDialog();
        mDialog.show();
    }@Override
    public void onPositive(Dialog dialog) {dialog.dismiss();
    }@Override
    public void onNegative(Dialog dialog) {dialog.dismiss();
    }


githup源码地址:
https://github.com/DarkSherlock/DialogBuilder

这篇关于自定义仿IOS的圆角AlertDialog的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/890593

相关文章

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

安卓链接正常显示,ios#符被转义%23导致链接访问404

原因分析: url中含有特殊字符 中文未编码 都有可能导致URL转换失败,所以需要对url编码处理  如下: guard let allowUrl = webUrl.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {return} 后面发现当url中有#号时,会被误伤转义为%23,导致链接无法访问

自定义类型:结构体(续)

目录 一. 结构体的内存对齐 1.1 为什么存在内存对齐? 1.2 修改默认对齐数 二. 结构体传参 三. 结构体实现位段 一. 结构体的内存对齐 在前面的文章里我们已经讲过一部分的内存对齐的知识,并举出了两个例子,我们再举出两个例子继续说明: struct S3{double a;int b;char c;};int mian(){printf("%zd\n",s

Spring 源码解读:自定义实现Bean定义的注册与解析

引言 在Spring框架中,Bean的注册与解析是整个依赖注入流程的核心步骤。通过Bean定义,Spring容器知道如何创建、配置和管理每个Bean实例。本篇文章将通过实现一个简化版的Bean定义注册与解析机制,帮助你理解Spring框架背后的设计逻辑。我们还将对比Spring中的BeanDefinition和BeanDefinitionRegistry,以全面掌握Bean注册和解析的核心原理。

【iOS】MVC模式

MVC模式 MVC模式MVC模式demo MVC模式 MVC模式全称为model(模型)view(视图)controller(控制器),他分为三个不同的层分别负责不同的职责。 View:该层用于存放视图,该层中我们可以对页面及控件进行布局。Model:模型一般都拥有很好的可复用性,在该层中,我们可以统一管理一些数据。Controlller:该层充当一个CPU的功能,即该应用程序

Oracle type (自定义类型的使用)

oracle - type   type定义: oracle中自定义数据类型 oracle中有基本的数据类型,如number,varchar2,date,numeric,float....但有时候我们需要特殊的格式, 如将name定义为(firstname,lastname)的形式,我们想把这个作为一个表的一列看待,这时候就要我们自己定义一个数据类型 格式 :create or repla

HTML5自定义属性对象Dataset

原文转自HTML5自定义属性对象Dataset简介 一、html5 自定义属性介绍 之前翻译的“你必须知道的28个HTML5特征、窍门和技术”一文中对于HTML5中自定义合法属性data-已经做过些介绍,就是在HTML5中我们可以使用data-前缀设置我们需要的自定义属性,来进行一些数据的存放,例如我们要在一个文字按钮上存放相对应的id: <a href="javascript:" d

一步一步将PlantUML类图导出为自定义格式的XMI文件

一步一步将PlantUML类图导出为自定义格式的XMI文件 说明: 首次发表日期:2024-09-08PlantUML官网: https://plantuml.com/zh/PlantUML命令行文档: https://plantuml.com/zh/command-line#6a26f548831e6a8cPlantUML XMI文档: https://plantuml.com/zh/xmi

argodb自定义函数读取hdfs文件的注意点,避免FileSystem已关闭异常

一、问题描述 一位同学反馈,他写的argo存过中调用了一个自定义函数,函数会加载hdfs上的一个文件,但有些节点会报FileSystem closed异常,同时有时任务会成功,有时会失败。 二、问题分析 argodb的计算引擎是基于spark的定制化引擎,对于自定义函数的调用跟hive on spark的是一致的。udf要通过反射生成实例,然后迭代调用evaluate。通过代码分析,udf在

鸿蒙开发中实现自定义弹窗 (CustomDialog)

效果图 #思路 创建带有 @CustomDialog 修饰的组件 ,并且在组件内部定义controller: CustomDialogController 实例化CustomDialogController,加载组件,open()-> 打开对话框 , close() -> 关闭对话框 #定义弹窗 (CustomDialog)是什么? CustomDialog是自定义弹窗,可用于广告、中