原文连接:https://github.com/li-xiaojun/XPopupgit
这是一个开源弹窗库的推荐,它真的很实用很漂亮,若是不实,请打我!github
几个星期前,我搜遍了Github都没有找到一个在功能和外观上让我满意的弹窗库,因而花了几天时间写了这个库!这个库从实用的角度出发,解决项目弹窗痛点,兼顾优雅的动画交互和漂亮的外观,能够替代Dialog,PopupWindow,PopupMenu,BottomSheet,DrawerLayout效果等组件,自带十几种效果良好的动画,支持彻底的UI和动画自定义!数组
Github地址:https://github.com/li-xiaojun/XPopupide
它有这样几个特色:布局
功能强大,内部封装了经常使用的弹窗,内置十几种良好的动画,将弹窗和动画的自定义设计的极其简单动画
UI和动画简洁,遵循Material Design,在设计动画的时候考虑了不少细节,过渡,层级的变化;或者说是模拟系统组件的动画this
交互优雅,实现了优雅的手势交互以及智能的嵌套滚动,具体看Demo设计
适配全面屏,目前适配了小米,华为,谷歌,OPPO,VIVO,三星,魅族,一加全系全面屏手机code
编写本库的初衷有如下几点:blog
项目有这样常见需求:中间和底部弹出甚至可拖拽的对话框,指定位置的PopupMenu或者PopupWindow,指定区域阴影的弹出层效果
市面上已有的类库要么功能不足够,要么交互效果不完美,有着广泛的缺点,就像BottomSheet存在的问题同样。好比:窗体消失的动画和背景渐变更画不一致,窗体消失后半透明背景仍然停留一下子
设计思路:
综合常见的弹窗场景,我将其分为几类:
Center类型,就是在中间弹出的弹窗,好比确认和取消弹窗,Loading弹窗
Bottom类型,就是从页面底部弹出,好比从底部弹出的分享窗体,知乎的从底部弹出的评论列表,我内部会处理好手势拖拽和嵌套滚动
Attach类型,就是弹窗的位置须要依附于某个View或者某个触摸点,就像系统的PopupMenu效果同样,但PopupMenu的自定义性不好
DrawerLayout类型,就是从窗体的坐边或者右边弹出,并支持手势拖拽;好处是与界面解耦,能够在任何界面显示DrawerLayout
尽管我已经内置了几种常见弹窗的实现,但不可能知足全部的需求,你极可能须要自定义;你自定义的弹窗类型应该属于这几种之一。
动画设计:
为了增长交互的趣味性,遵循Material Design,在设计动画的时候考虑了不少细节,过渡,层级的变化。具体能够从Demo中感觉。
体验Demo
下载安装,快速体验:https://fir.im/2q63
首先须要添加Gradle依赖:
implementation 'com.lxj:xpopup:latest release'
为了方便使用,已经内置了几种常见弹窗的实现:
显示确认和取消对话框
XPopup.get(getContext()).asConfirm("我是标题", "我是内容", new OnConfirmListener() { @Override public void onConfirm() { toast("click confirm"); } }).show();
显示带输入框的确认和取消对话框
XPopup.get(getContext()).asInputConfirm("我是标题", "请输入内容。", new OnInputConfirmListener() { @Override public void onConfirm(String text) { toast("input text: " + text); } }) .show();
显示中间弹出的列表弹窗
XPopup.get(getActivity()).asCenterList("请选择一项",new String[]{"条目1", "条目2", "条目3", "条目4"}, // null, /** 图标Id数组,可无 **/ // 1, /** 选中的position,默认没有选中效果 **/ new OnSelectListener() { @Override public void onSelect(int position, String text) { toast("click "+text); } }) .show();
显示中间弹出的加载框
XPopup.get(getActivity()).asLoading().show();
显示从底部弹出的列表弹窗
// 这种弹窗从 1.0.0版本开始实现了优雅的手势交互和智能嵌套滚动 XPopup.get(getActivity()).asBottomList("请选择一项",new String[]{"条目1", "条目2", "条目3", "条目4","条目5"}, // null, /** 图标Id数组,可无 **/ // 1, /** 选中的position,默认没有选中效果 **/ new OnSelectListener() { @Override public void onSelect(int position, String text) { toast("click "+text); } }) .show();
显示依附于某个View或者某个点的弹窗
XPopup.get(getActivity()).asAttachList(new String[]{"分享", "编辑", "不带icon"}, new int[]{R.mipmap.ic_launcher, R.mipmap.ic_launcher}, new OnSelectListener() { @Override public void onSelect(int position, String text) { toast("click "+text); } }) .atView(v) // 若是是要依附某个View,必须设置 .show();
若是是想依附于某个View的触摸点,则须要先watch该View,而后当单击或长按触发的时候去显示:
// 必须在事件发生前,调用这个方法来监视View的触摸 XPopup.get(getActivity()).watch(view); view.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { XPopup.get(getActivity()).asAttachList(new String[]{"置顶", "复制", "删除"},null, new OnSelectListener() { @Override public void onSelect(int position, String text) { toast("click "+text); } }) // 注意:已经监视了View的触摸点,无需调用atView()方法 .show(); return false; } });
关闭弹窗
XPopup.get(getContext()).dismiss();
自定义弹窗
当你自定义弹窗的时候,须要选择继承CenterPopupView
,BottomPopupView
,AttachPopupView
,DrawerPopupView
,PartShadowPopupView
其中之一。假设须要自定义Center类型的弹窗:
class CustomPopup extends CenterPopupView{ public CustomPopup(@NonNull Context context) { super(context); } // 返回自定义弹窗的布局 @Override protected int getImplLayoutId() { return R.layout.custom_popup; } // 执行初始化操做,好比:findView,设置点击,或者任何你弹窗内的业务逻辑 @Override protected void initPopupContent() { super.initPopupContent(); findViewById(R.id.tv_close).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { dismiss(); // 关闭弹窗 } }); } // 设置最大宽度,看须要而定 @Override protected int getMaxWidth() { return super.getMaxWidth(); } // 设置最大高度,看须要而定 @Override protected int getMaxHeight() { return super.getMaxHeight(); } // 设置自定义动画器,看须要而定 @Override protected PopupAnimator getPopupAnimator() { return super.getPopupAnimator(); } }
使用自定义弹窗:
XPopup.get(getContext()) .asCustom(new CustomPopup(getContext())) .show();
自定义动画
自定义动画已经被设计得很是简单,动画和弹窗是无关的;这意味着你能够将动画设置给内置弹窗或者自定义弹窗。继承PopupAnimator
,实现3个方法:
- 如何初始化动画
- 动画如何开始
- 动画如何结束
好比:自定义一个旋转的动画:
class RotateAnimator extends PopupAnimator{ @Override public void initAnimator() { targetView.setScaleX(0); targetView.setScaleY(0); targetView.setAlpha(0); targetView.setRotation(360); } @Override public void animateShow() { targetView.animate().rotation(0).scaleX(1).scaleY(1).alpha(1).setInterpolator(new FastOutSlowInInterpolator()).setDuration(animateDuration).start(); } @Override public void animateDismiss() { targetView.animate().rotation(360).scaleX(0).scaleY(0).alpha(0).setInterpolator(new FastOutSlowInInterpolator()).setDuration(animateDuration).start(); } }
使用自定义动画:
XPopup.get(getContext()) .asConfirm(...) .customAnimator(new RotateAnimator()) .show();
显示DrawerLayout类型弹窗
对于DrawerLayout类型的弹窗,我只能帮你作好弹窗效果和手势交互。里面的UI和逻辑是没法帮你完成的,因此须要自定义一个弹窗,继承DrawerPopupView
。代码很是简单,以下:
public class CustomDrawerPopupView extends DrawerPopupView { public CustomDrawerPopupView(@NonNull Context context) { super(context); } @Override protected int getImplLayoutId() { return R.layout.custom_drawer_popup; } @Override protected void initPopupContent() { super.initPopupContent(); findViewById(R.id.btn).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Toast.makeText(getContext(), "nothing!!!", Toast.LENGTH_SHORT).show(); } }); } }
使用自定义的DrawerLayout弹窗:
XPopup.get(getActivity()) .asCustom( new CustomDrawerPopupView(getContext()) //.setDrawerPosition(PopupDrawerLayout.Position.Right) // 添加状态栏Shadow,默认是false;若是你的Drawer背景是白色,会致使状态栏的白色文字看不清, // 此时建议设置该标志为true; //.hasStatusBarShadow(true) ) .show();
自定义局部阴影弹窗
这种效果从分类上看仍然是Attach类型,由于要依附于某个View,在其上方或者下方显示。常见于列表条件筛选弹窗,好比京东或者淘宝的商品列表筛选。一样我只能帮你把复杂的交互效果作了,弹窗里面的UI和逻辑须要你本身继承PartShadowPopupView
来作,这固然很是简单。
最简单的示例以下:
public class CustomPartShadowPopupView extends PartShadowPopupView { public CustomPartShadowPopupView(@NonNull Context context) { super(context); } @Override protected int getImplLayoutId() { return R.layout.custom_part_shadow_popup; // 编写你本身的布局 } @Override protected void initPopupContent() { super.initPopupContent(); // 实现一些UI的初始和逻辑处理 } }
显示的时候仍然须要指定atView显示,内部会智能判断应该如何展现以及使用最佳的动画器:
XPopup.get(getActivity()) .asCustom(new CustomPartShadowPopupView(getContext())) .atView(ll_container) .show();
其余
设置主色调:
默认状况下,XPopup的主色为灰色,主色做用于Button文字,EditText边框和光标,Check文字的颜色上。由于XPopup是单例,因此主色调只须要设置一次便可,能够放在Application中设置。
XPopup.get(this).setPrimaryColor(getResources().getColor(R.color.colorPrimary));
经常使用设置:
XPopup.get(this) .hasShadowBg(true) // 是否有半透明的背景,默认为true .dismissOnBackPressed(true) // 按返回键是否关闭弹窗,默认为true .dismissOnTouchOutside(true) // 点击外部是否关闭弹窗,默认为true .popupAnimation(PopupAnimation.ScaleAlphaFromCenter) // 设置内置的动画 .customAnimator(null) // 设置自定义的动画器 .setPopupCallback(new XPopupCallback() { //设置显示和隐藏的回调 @Override public void onShow() { // 彻底显示的时候执行 } @Override public void onDismiss() { // 彻底隐藏的时候执行 } }) .setWidthAndHeight(0, 300) // 设置弹窗的宽高,只对Center和Bottom类型弹窗生效
做者联系方式 Gmail: lxj16167479@gmail.com QQ: 16167479