MTPopup,Android一个简单强大的弹框

前言

断断续续地,利用工作之余的不少时间归纳整合了这个MTPopup。虽然没啥高深的技术,但是我认为这个库能给大家在项目上的弹框处理带来些许的方便,使用它,大家就不必频繁的新建class文件,频繁地写重复代码,直接链式调用,提供全面的api,应该能满足项目上绝大多数的业务,并且覆盖了Android所有的弹框类型(DialogBottomSheetDialogDialogFragmentBottomSheetDialogFragmentPopupWindowDialogActivity),总结起来就是调用简单、功能强大。


功能特点

  • 层次结构分明,分工明确
  • 采用链式调用一点到底
  • 支持Android多种弹框:DialogBottomSheetDialogDialogFragmentBottomSheetDialogFragmentPopupWindowDialogActivity
  • 支持设置弹窗的主题样式、宽高(最大宽高及屏幕宽高比等)、背景透明度、圆角、显示位置、显示消失动画
  • 支持设置弹窗ContentView相关控件View的属性,如
  • 支持设置弹窗关闭的逻辑,如返回键、点击外部空白区域
  • 支持设置弹窗的显示及关闭事件监听
  • 支持设置弹窗自动消失

下一步计划添加弹窗的优先级队列和全局弹窗,有什么好的建议和想法也可以提出来!!


设计实现

  • PopupCompat 单例实现的Popup管理类
  • Popup 弹窗实体,所有的弹窗类型对象都可以认为是一个Popup,里面维护了弹窗的Config和Delegate对象
  • PopupInterface Popup的抽象接口类
  • Config 弹窗的配置对象,不同的弹窗类型有不同的Config对象,负责存储弹窗的相关属性,如DialogConfigDialogFragmentConfig
  • Delegate 弹窗的代理对象,不同的弹窗类型有不同的Delegate对象,负责处理弹窗的相关属性,如DialogDelegateDialogFragmentDelegate
  • PopupRootView 弹窗的RoottView
  • PopupViewHolder 处理弹窗ContentView的Holder对象,类似RecyclerView的BaseViewHolder

项目引入该库

在你的 Project build.gradle文件中添加:

allprojects {
		repositories {
			...
			maven { url 'https://jitpack.io' }
		}
	}

在你的 Module build.gradle文件中添加:

dependencies {
	         implementation 'com.github.huangxiaolianghh.MTPopup:popup:1.0.2'
	}

如何使用

我们可以通过PopupCompat asXXX系列的方法来展示不同的弹框类型,如:

  • asDialog
  • asBottomSheetDialog
  • asDialogFragment
  • asBottomSheetDialogFragment
  • asPopupWindow
  • asDialogActivity

下面以展示Dialog进行说明:

            PopupCompat.get().asDialog(DialogDemoActivity.this)
                    .themeStyle(R.style.MTPopup_Dialog)   //主题样式
                    .view(R.layout.popup_test)            //可传View
                    .radius(50)                           //设置四个圆角
//                    //设置弹窗上(下、左、右)方圆角,
//                    .radiusSideTop(50)
                    .animStyle(R.style.PopupEnterExpandExitShrinkAnimation)  //动画
                    //宽高比
//                    .widthInPercent(0.8f)
//                    .heightInPercent(0.8f)
//                    //最大宽高
//                    .maxWidth(800)
//                    .maxHeight(800)
//                    //框架默认是width=ViewGroup.LayoutParams.MATCH_PARENT,height=ViewGroup.LayoutParams.WRAP_CONTENT
//                    .width(ViewGroup.LayoutParams.MATCH_PARENT)
//                    .height(ViewGroup.LayoutParams.WRAP_CONTENT)
//                    .matchHeight()
//                    .matchWidth()
//                    .wrapHeight()
                    .wrapWidth()
                    .dimAmount(0f)                       //不设置背景透明度,默认0.5f
                    .cancelable(false)                   //返回键dismiss
                    .cancelableOutside(false)            //点击外部区域dismiss
                    .autoDismissTime(5000)               //5秒后自动dismiss
                    .gravity(Gravity.CENTER)             //设置显示位置
                    //添加View点击事件,也支持添加多个View的点击事件
                    .clickListener(R.id.btn_left, (popupInterface, view, holder) -> {
                        popupInterface.dismiss();
                        Toast.makeText(
                                DialogDemoActivity.this,
                                "点击了" + ((Button) holder.getView(R.id.btn_left)).getText(),
                                Toast.LENGTH_SHORT)
                                .show();
                    })
                    .clickListener(R.id.btn_right, (popupInterface, view, holder) -> popupInterface.dismiss())
                    //添加多个View长按事件,也支持添加单个View的点击事件
                    .longClickIds(R.id.btn_left, R.id.btn_right)
                    .longClickIdsListener((popupInterface, view, holder) -> {
                        if (view.getId() == R.id.btn_left) {
                            Toast.makeText(
                                    DialogDemoActivity.this,
                                    "长按了" + ((Button) holder.getView(R.id.btn_left)).getText(),
                                    Toast.LENGTH_SHORT)
                                    .show();
                        } else if (view.getId() == R.id.btn_right) {
                            Toast.makeText(
                                    DialogDemoActivity.this,
                                    "长按了" + ((Button) holder.getView(R.id.btn_right)).getText(),
                                    Toast.LENGTH_SHORT)
                                    .show();
                        }
                        return true;
                    })
                    //关闭事件监听
                    .dismissListener(popupInterface ->
                            Toast.makeText(
                                    DialogDemoActivity.this,
                                    "消失监听",
                                    Toast.LENGTH_SHORT)
                                    .show())
                    //显示事件监听
                    .showListener(popupInterface ->
                            Toast.makeText(
                                    DialogDemoActivity.this,
                                    "显示监听",
                                    Toast.LENGTH_SHORT)
                                    .show())
                    //View绑定事件监听
                    .bindViewListener((PopupViewHolder holder) -> {
                        //holder可以对象弹窗所有控件操作,在这里处理弹窗内部相关逻辑
                        holder.setText(R.id.tv_popup_title, "MTPopup");
                    })
                    .create().show();

如果我们需要在弹窗展示期间改变ContentView一些控件的属性,这时我们可以经过Config配置对象的create()方法获取Popup对象实例,通过其就可以拿到ContentView的PopupViewHolder对象,进而改变相关控件的属性,如:

            Popup<DialogDelegate> popup = PopupCompat.get().asDialog(DialogDemoActivity.this)
                    .view(R.layout.popup_test)
                    .gravity(Gravity.CENTER)
                    .clickListener(R.id.btn_right, (popupInterface, view, holder) -> popupInterface.dismiss())
                    .cancelableOutside(true)
                    .create();
            popup.show();
            new Handler(Looper.getMainLooper()).postDelayed(() ->
                    popup.getPopupViewHolder().setText(R.id.tv_popup_title, "获取Popup对象,更新标题"), 5000);

框架的普通Dialog和DialogActivity默认实现的主题样式:R.style.MTPopup_Dialog


    <!-- 普通Dialog主题样式 -->
    <style name="MTPopup.Dialog" parent="Theme.MaterialComponents.DayNight.Dialog">
        <item name="android:windowNoTitle">true</item>
        <!-- 是否不显示title 继承AppCompat样式-->
        <item name="windowNoTitle">true</item>
        <!-- 设置dialog显示区域外部的背景(透明),有圆角,圆角外部区域显示这个颜色 -->
        <item name="android:windowBackground">@android:color/transparent</item>
        <!-- 设置dialog的背景(透明),此颜色值会覆盖掉windowBackground的值 -->
        <item name="android:background">@android:color/transparent</item>
        <item name="android:colorBackground">@android:color/transparent</item>
        <!-- 设置灰度的值,为1时,除Dialog内容布局高亮其它全黑,系统的默认值是0.6 -->
        <item name="android:backgroundDimAmount">0.5</item>
        <!-- 是否允许背景灰暗,即是否让显示区域以外使用上面设置的黑色半透明背景,设为false时,等价于backgroundDimAmount=0 -->
        <item name="android:backgroundDimEnabled">true</item>
        <!-- 是否有遮盖 -->
        <item name="android:windowContentOverlay">@null</item>
        <!-- 设置Dialog的windowFrame框(无) -->
        <item name="android:windowFrame">@null</item>
        <!-- 是否浮现在activity之上,必须设为true,否则自己独立占一个界面,这根本就不像是一个对话框了 -->
        <item name="android:windowIsFloating">true</item>
        <!-- 是否半透明,貌似没什么卵用 -->
        <item name="android:windowIsTranslucent">true</item>
    </style>

BottomSheetDialog默认实现的主题样式:R.style.MTPopup_BottomSheetDialog

  
    <!--  BottomSheetDialog样式  -->
    <style name="MTPopup.BottomSheetDialog" parent="Theme.Design.BottomSheetDialog">
        <item name="android:windowNoTitle">true</item>
        <!-- 是否不显示title 继承AppCompat样式-->
        <item name="windowNoTitle">true</item>
        <!-- 设置dialog显示区域外部的背景(透明),有圆角,圆角外部区域显示这个颜色 -->
        <item name="android:windowBackground">@android:color/transparent</item>
        <!-- 设置dialog的背景(透明),此颜色值会覆盖掉windowBackground的值 -->
        <item name="android:background">@android:color/transparent</item>
        <item name="android:colorBackground">@android:color/transparent</item>
        <!-- 设置灰度的值,为1时,除Dialog内容布局高亮其它全黑,系统的默认值是0.6 -->
        <item name="android:backgroundDimAmount">0.5</item>
        <!-- 是否允许背景灰暗,即是否让显示区域以外使用上面设置的黑色半透明背景,设为false时,等价于backgroundDimAmount=0 -->
        <item name="android:backgroundDimEnabled">true</item>
        <!-- 是否有遮盖 -->
        <item name="android:windowContentOverlay">@null</item>
        <!-- 设置Dialog的windowFrame框(无) -->
        <item name="android:windowFrame">@null</item>
        <!-- 是否浮现在activity之上,必须设为true,否则自己独立占一个界面,这根本就不像是一个对话框了 -->
        <item name="android:windowIsFloating">true</item>
        <!-- 是否半透明,貌似没什么卵用 -->
        <item name="android:windowIsTranslucent">true</item>
    </style>

DialogActivity动画设置:

    <!-- 自定义DialogActivity动画 -->
    <style name="ActivityEnterRightExitLeftAnimation">
        <item name="android:activityOpenEnterAnimation">@anim/in_from_right</item>
        <item name="android:activityOpenExitAnimation">@null</item>
        <item name="android:activityCloseEnterAnimation">@null</item>
        <item name="android:activityCloseExitAnimation">@anim/out_to_left</item>
    </style>

其它弹窗的动画设置:

    <style name="PopupEnterExpandExitShrinkAnimation">
        <item name="android:windowEnterAnimation">@anim/enter_folds_expand</item>
        <item name="android:windowExitAnimation">@anim/exit_folds_shrink</item>
    </style>

具体的设置可参考项目demo,这里就不细说了。

MTPopup属性配置说明

基本公共属性

属性设置方法说明
mContext构造函数BaseConfig(Context context)上下文
mThemeStylethemeStyle(@StyleRes int themeStyle)主题样式,PopupWindow不支持此属性
mAnimStyleanimStyle(@StyleRes int animStyle)动画
mContentViewview(View contentView)
view(@LayoutRes int contentViewResId)
内容View
mOnBindViewListenerbindViewListener(PopupInterface.OnBindViewListener listener)View绑定到Popup前的监听器
mOnShowListenershowListener(PopupInterface.OnShowListener onShowListener)Popup显示监听器
mOnDismissListenerdismissListener(PopupInterface.OnDismissListener onDismissListener)Popup关闭监听器
mClickIdsclickIds(@IdRes int… clickIds)点击控件id集合
mOnClickListenerclickIdsListener(@NonNull PopupInterface.OnClickListener onClickListener)控件点击事件监听器
mLongClickIdslongClickIds(@IdRes int… longClickIds)长按控件id集合
mOnLongClickListenerlongClickIdsListener(@NonNull PopupInterface.OnLongClickListener onLongClickListener)控件长按事件监听器
mWidthwidth(int width)
matchWidth()
wrapWidth()
宽,默认ViewGroup.LayoutParams.MATCH_PARENT
mHeightheight(int height)
matchHeight()
wrapHeight()
高,默认ViewGroup.LayoutParams.WRAP_CONTENT
mMaxWidthmaxWidth(int maxWidth)最大宽
mMaxHeightmaxHeight(int maxHeight)最大高
mWidthInPercentwidthInPercent(float widthInPercent)屏幕宽度比
mHeightInPercentheightInPercent(float heightInPercent)屏幕高度比
mGravitygravity(int gravity)弹窗位置,BottomSheet系列弹窗的位置恒为Gravity.BOTTOM
mBackgroundDrawablebackgroundDrawable(Drawable backgroundDrawable)弹窗window的背景
mDimAmountdimAmount(float dimAmount)弹窗周围的亮度
mAutoDismissTimeautoDismissTime(long autoDismissTime)x秒后自动消失
mCancelablecancelable(boolean cancelable)返回键事件关闭弹窗,默认true,对于PopupWindow无效,调用者自行处理其此事件
mCancelableOutsidecancelableOutside(boolean cancelableOutside)点击外部区域关闭弹窗,默认true
mRadius
mRadiusSideLeft
mRadiusSideTop
mRadiusSideRight
mRadiusSideBottom
radius(int radius)
radiusSideLeft(int radiusSideLeft)
radiusSideTop(int radiusSideTop)
radiusSideRight(int radiusSideRight)
radiusSideBottom(int radiusSideBottom)
圆角
左边圆角
上边圆角
右边圆角
下边圆角

这里只列举MTPopup的公共属性,至于不同的弹窗类型,其对应的Config定义了特有的属性,这里就不列举出来了,详细的属性可以去看XXXConfig系列源码。


总结

MTPopup是一个弹窗处理框架,整合了Android几乎所有的弹窗类型,主要是为了简化弹窗的处理方式,直接链式调用,发布这个初版基本能满足大多数业务场景。接下来自己也会继续完善这个库,将弹窗优先级和全局弹窗功能加进来,当然DialogActivity也可以实现不依赖Activity的全局弹窗,自己一个人的力量有限,MTPopup可能有些功能设计考虑的不是很充分,难免会有些错误,希望大家在使用中能多多提点意见,自己也会努力去改进和完善。

最后欢迎大家start

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

黄小梁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值