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

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

    • 前言
    • 功能特点
    • 设计实现
    • 项目引入该库
    • 如何使用
    • MTPopup属性配置说明
    • 总结

前言

断断续续地,利用工作之余的不少时间归纳整合了这个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) 上下文
mThemeStyle themeStyle(@StyleRes int themeStyle) 主题样式,PopupWindow不支持此属性
mAnimStyle animStyle(@StyleRes int animStyle) 动画
mContentView view(View contentView)
view(@LayoutRes int contentViewResId)
内容View
mOnBindViewListener bindViewListener(PopupInterface.OnBindViewListener listener) View绑定到Popup前的监听器
mOnShowListener showListener(PopupInterface.OnShowListener onShowListener) Popup显示监听器
mOnDismissListener dismissListener(PopupInterface.OnDismissListener onDismissListener) Popup关闭监听器
mClickIds clickIds(@IdRes int… clickIds) 点击控件id集合
mOnClickListener clickIdsListener(@NonNull PopupInterface.OnClickListener onClickListener) 控件点击事件监听器
mLongClickIds longClickIds(@IdRes int… longClickIds) 长按控件id集合
mOnLongClickListener longClickIdsListener(@NonNull PopupInterface.OnLongClickListener onLongClickListener) 控件长按事件监听器
mWidth width(int width)
matchWidth()
wrapWidth()
宽,默认ViewGroup.LayoutParams.MATCH_PARENT
mHeight height(int height)
matchHeight()
wrapHeight()
高,默认ViewGroup.LayoutParams.WRAP_CONTENT
mMaxWidth maxWidth(int maxWidth) 最大宽
mMaxHeight maxHeight(int maxHeight) 最大高
mWidthInPercent widthInPercent(float widthInPercent) 屏幕宽度比
mHeightInPercent heightInPercent(float heightInPercent) 屏幕高度比
mGravity gravity(int gravity) 弹窗位置,BottomSheet系列弹窗的位置恒为Gravity.BOTTOM
mBackgroundDrawable backgroundDrawable(Drawable backgroundDrawable) 弹窗window的背景
mDimAmount dimAmount(float dimAmount) 弹窗周围的亮度
mAutoDismissTime autoDismissTime(long autoDismissTime) x秒后自动消失
mCancelable cancelable(boolean cancelable) 返回键事件关闭弹窗,默认true,对于PopupWindow无效,调用者自行处理其此事件
mCancelableOutside cancelableOutside(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!

你可能感兴趣的:(#,Android进阶,android,android,studio,android-studio,安卓)