Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

亲,还在为PopupWindow烦恼吗?不如试试BasePopup,你会爱上他的~

License

Notifications You must be signed in to change notification settings

yangpeixing/BasePopup

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

526 Commits

Repository files navigation

1.x版本 | 2.x版本 | English

Logo图片似乎加载不出来

BasePopup - Android下打造通用便捷的PopupWindow

Release Candy License Api Author


Compat组件 support lifecycle androidx
Release
Candy

apk体验下载

导航



特性

  • 更简单更精准的控制显示位置,通过Gravityoffset来控制您的PopupWindow
  • 本库为抽象类,对子类几乎没有约束,您完全可以像定制Activity一样来定制您的PopupWindow
  • 支持AnimationAnimator,随意控制您的PopupWindow的动画,再也不用去写蛋疼的xml了
  • 背景变暗、背景换色甚至背景给个Drawable都是一句话的事情
  • 背景模糊亦或是局部模糊也仅仅需要您一句话的配置
  • 返回键控制点击外部Dismiss控制,外部事件响应控制三者分离,再也不用担心我的PopupWindow各种按键响应问题
    • 如果不满足默认的事件,没问题,我们还提供了事件传递,您的事件您来把握
  • PopupWindow跟随AnchorView位置不准?屏幕外不消失?在这里,Link方法为您排忧解难
  • 支持链式调用,还在为简单的PopupWindow使用不得不继承库的抽象类而感到烦躁?不妨来试试QuickPopupBuilder,想必您会爱上它的


注意事项

WARN

  • 请务必仔细阅读本README,每个版本升级请务必查阅更新日志,这可以为您减少不必要弯路
  • 请注意引用版本的问题,Release版本是稳定版,Candy是预览版。
    • Release版本:一般在Candy版本反复验证修复后发布到Release,如果您对稳定性要求较高,请使用Release版本。
    • Candy版本:一般新功能、issue修复都会发布到Candy版本,Candy版本发布比较频繁,但通常会拥有新的功能,如果您喜欢试验新功能同时对稳定性要求不高,请使用Candy版本。
    • Release和Candy两个版本互相切换可能会导致Build失败,这时候您Clean一下Project即可
  • 如果您是以前1.x版本的用户,现在想更新到2.x,请在更新前查阅:1.x迁移到2.x帮助文档
  • 从16年第一次提交到现在,本人技术也一直在进步,BasePopup也会一直迭代更新,所以,请谨慎选择版本哦~一不小心就颠覆了之前的实现。

Android P已经适配,感谢@Guolei1130收集的方法。

文章地址:android_p_no_sdkapi_support

本库一开始采用360的方法,但不得不走Native,为了个Popup不得不引入so感觉很不值得,在看到这篇文章后,才想起UnSafe类,因此本库采用方法5。

如果以后UnSafe类移除掉的话,再考虑Native方法。

最后再一次感谢大牛提供的方法~



声明

BasePopup并非一个 "一句话完成需求" 的库,从起名带有 【Base】 也应该可以知道这是一个高度抽象的类。

这也意味着本库所提供的api是基于通用抽象层面的。

因此,具体的需求比如点击事件,比如列表弹窗等等都需要您自行完成。

因为众口难调,你的需求并不适用于别人的需求,而作为一个通用库,就如ListAdapter一样,最大程度的开放给用户完成是最好的方案。

因此,如果您期望使用BasePopup可以一句话完成所有事情,很抱歉~可能本库不能满足您的需求。



快速入门


更多使用方法请查看Wiki#使用方法

依赖

Release Candy
Download Download

添加依赖到Gradle(请把{$latestVersion}替换成上面的Jcenter标签所示版本)

请注意,如果您依赖了androidX支持组件,请不要依赖另外两个支持组件,否则会冲突

	dependencies {
	 //BasePopup主体库
	 implementation 'com.github.razerdp:BasePopup:{$latestVersion}'
 //以下可选
	 //BasePopup support支持库(如支持DialogFragment里弹Popup时的层序支持)
	 implementation 'com.github.razerdp:BasePopup-compat-support:{$latestVersion}'
	 //BasePopup lifecycle支持库(如自动适配Activity/Fragment生命期dismiss/回收等)
	 implementation 'com.github.razerdp:BasePopup-compat-lifecycle:{$latestVersion}'
	 //BasePopup androidx支持库(针对以上两个支持的androidX版本)
	 implementation 'com.github.razerdp:BasePopup-compat-androidx:{$latestVersion}'
	 
	 //candy渠道
		//implementation 'com.github.razerdp:BasePopup_Candy:{$latestVersion}'
		//implementation 'com.github.razerdp:BasePopup_Candy-compat-support:{$latestVersion}'
		//implementation 'com.github.razerdp:BasePopup_Candy-compat-lifecycle:{$latestVersion}'
		//implementation 'com.github.razerdp:BasePopup_Candy-compat-androidx:{$latestVersion}'
	}

配置

模糊配置

从1.9.0-alpha开始支持背景模糊(只需要一个方法:setBlurBackgroundEnable(boolean))

RenderScript最低支持api 18(更低的情况将会使用fastblur),您需要在gradle配置一下代码

我们建议你设置renderscriptTargetApi为能够提供你正在使用的所有功能的最低API级别

defaultConfig {
 renderscriptTargetApi 18
 renderscriptSupportModeEnabled true
 }

普通使用

1.编写您的xml文件

像您平时定制View布局文件一样定制您的PopupWindow布局

<?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="@android:color/holo_blue_dark"
 android:orientation="vertical"
 >
 <TextView
 android:id="@+id/tx_1"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:gravity="center"
 android:padding="16dp"
 android:text="test1"
 android:textColor="@color/color_black1"/>
</LinearLayout>

2.创建您的Popup类并继承BasePopupWindow

public class DemoPopup extends BasePopupWindow {
 public DemoPopup(Context context) {
 super(context);
 }
 @Override
 public View onCreateContentView() {
 return null;
 }
}

3.补充对应方法

强烈建议在onCreateContentView()里使用createPopupById()来进行inflate,这样本库才能正确的做出对应的解析和适配

public class DemoPopup extends BasePopupWindow {
 public DemoPopup(Context context) {
 super(context);
 }
 // 必须实现,这里返回您的contentView
 // 为了让库更加准确的做出适配,强烈建议使用createPopupById()进行inflate
 @Override
 public View onCreateContentView() {
 return createPopupById(R.layout.popup_normal);
 }
 
 // 以下为可选代码(非必须实现)
 // 返回作用于PopupWindow的show和dismiss动画,本库提供了默认的几款动画,这里可以自由实现
 @Override
 protected Animation onCreateShowAnimation() {
 return getDefaultScaleAnimation(true);
 }
 @Override
 protected Animation onCreateDismissAnimation() {
 return getDefaultScaleAnimation(false);
 }
}

4.show!

展示PopupWindow的方法有三种,分别是showPopupWindow()showPopupWindow(View anchor)showPopupWindow(int x, int y):

new DemoPopup(getContext()).showPopupWindow();
//new DemoPopup(getContext()).showPopupWindow(v);
//new DemoPopup(getContext()).showPopupWindow(x,y);

这三个方法有不同的含义:

  • showPopupWindow():无参传入,此时PopupWindow参考对象为屏幕(或者说整个DecorView),Gravity的表现就像在FrameLayout里面的Gravity表现一样,表示其处于屏幕的哪个方位
  • showPopupWindow(View anchor):传入AnchorView,此时PopupWindow参考对象为传入的anchorView,Gravity的表现则意味着这个PopupWindow应该处于目标AnchorView的哪个方位
  • showPopupWindow(int x, int y):传入位置信息,此时PopupWindow将会在指定位置弹出。

建议:如果PopupWindow需要重复展示或者保留状态,建议作为成员变量使用,而不要作为局部变量每次都创建

关于Gravity的更多api,请查看:Wiki-Api:Gravity

例子展示:

  • showPopupWindow()无参传入
gravity = CENTER
上述例子中xml写明了layout_gravity=center
gravity = RIGHT | CENTER_VERTICAL

  • showPopupWindow(View v)传入anchorView
gravity = CENTER
上述例子中xml写明了layout_gravity=center
gravity = RIGHT | CENTER_VERTICAL

  • showPopupWindow(int x, int y)传入位置x,y坐标
gravity = CENTER
上述例子中xml写明了layout_gravity=center


QuickPopupBuilder链式调用

QuickPopupBuilder支持链式调用生成一个基于QuickPopup的PopupWindow,该Builder旨在快速建立一个简单的不包含复杂逻辑的PopupWindow,如上述案例,避免过于简单的PopupWindow也要继承BasePopupWindow,导致存在过多的类。

示例代码


如果您并不需要很详细的定义一个PopupWindow,您也可以选择QuickPopupBuilder采取链式写法快速编写出一个Popup以使用。

注意:默认QuickPopupBuilder.QuickPopupConfig配置中PopupWindow动画为缩放弹出和消失

 QuickPopupBuilder.with(getContext())
 .contentView(R.layout.popup_normal)
 .config(new QuickPopupConfig()
 .gravity(Gravity.RIGHT | Gravity.CENTER_VERTICAL)
 .withClick(R.id.tx_1, new View.OnClickListener() {
 @Override
 public void onClick(View v) {
 Toast.makeText(getContext(), "clicked", Toast.LENGTH_LONG).show();
 }
 }))
 .show();
		//.show(anchorView);
show() show(anchorView)


混淆


如果您需要LifeCycle的支持,请添加LifeCycle的混淆

## Android architecture components: Lifecycle
# LifecycleObserver's empty constructor is considered to be unused by proguard
-dontnote android.arch.lifecycle.**
-keepclassmembers class * implements android.arch.lifecycle.LifecycleObserver {
 <init>(...);
}
# ViewModel's empty constructor is considered to be unused by proguard
-keepclassmembers class * extends android.arch.lifecycle.ViewModel {
 <init>(...);
}
# keep Lifecycle State and Event enums values
-keepclassmembers class android.arch.lifecycle.Lifecycle$State { *; }
-keepclassmembers class android.arch.lifecycle.Lifecycle$Event { *; }
# keep methods annotated with @OnLifecycleEvent even if they seem to be unused
# (Mostly for LiveData.LifecycleBoundObserver.onStateChange(), but who knows)
-keepclassmembers class * {
 @android.arch.lifecycle.OnLifecycleEvent *;
}
-keep class * implements android.arch.lifecycle.GeneratedAdapter {
 <init>(...);
}

Api(请看Wiki)

请看wiki(陆续完善中)

Link👉WIKI


更新日志 (历史更新)

  • 【Candy】2.2.2

    • 【Candy】190704
      • 修复AnimatorSet的时间问题 fix #203
    • 【Candy】190722
      • 回滚#188修复
      • 经检查,#188修复带来的问题比较严重,建议升级到该版本
    • 【Candy】190816
      • 考虑到很多用户提出全面屏会有蒙层无法填充的问题,因此增加setMaskLayoutWidthsetMaskLayoutHeight方法,该方法允许您自定义蒙层的高度
      • 开始重构BasePopupWindow,本次重构将会解决遗留问题同时缩减冗余代码,并提高代码可读性
  • 【Release】2.2.1(2019年06月24日)

    • 支持Service或者非ActivityContext里弹窗
    • 优化PopupUiUtils,优化获取屏幕宽高算法
    • 修改并优化键盘判断逻辑
    • 优化全屏状态下点击范围的判定,fixed #200
  • 【Release】2.2.0(2019年05月15日)

    • 正式版2.2.0隆重归来,这次正式版又是一个重构版本哦~
    • 优化输入法对齐逻辑
    • 重构模糊逻辑:
      • 经测试,720p的手机在默认参数下全屏模糊时间平均在6ms~16ms之间
      • 增大默认参数的模糊程度
      • 模糊淡入淡出时间跟随Popup的动画时间
      • 修复模糊偶尔失效的情况
    • 测量/布局相关:
      • 重构测量逻辑:
        • 现在在clipToScreen的情况下,会根据剩余空间对PopupDecor进行重新测量,以保证Popup完整的显示,如果您需要保持原始的测量值,请调用keepSize(true)
        • 重构layout逻辑,针对outSideTouch优化
        • 适配屏幕旋转,fix #180
        • 采取flag代替各种boolean,清爽更简洁
        • 减少冗余代码
    • 优化相关:
      • 增加GravityMode值,现在允许您配置PopupGravity的参考模式啦~
        • RELATIVE_TO_ANCHOR:默认模式,以Anchor为参考点,指定PopupWindow显示在Anchor的方位
        • ALIGN_TO_ANCHOR_SIDE:对齐模式,以Anchor的边为参考点,指定PopupWindow的边与Anchor的哪条边对齐
      • 增加minWidth/minHeight 方法,增加maxWidth/maxHeight 方法,让他们相互对应~
      • 修复高度为match_parent和wrap_content的测量差异,现在可以安心地玩耍啦
      • 部分Api标记过时:
        • (削除) setAllowDismissWhenTouchOutside (削除ここまで) -> setOutSideDismiss
        • (削除) setAllowInterceptTouchEvent (削除ここまで) -> setOutSideTouchable
      • 增加setBackgroundView(View)方法,现在BasePopup的背景控件可以随意由你定制啦~当然PopupWindow的背景动画控制方法依旧生效
    • 包拆分:
      • 现在BasePopup将会进行包的拆分,源工程仅针对没有任何依赖的原生Android进行适配,如果您需要别的适配,请分别依赖以下模块或多个模块:
        • 如果您需要support库的支持,比如DialogFragment支持,请依赖
          • implementation 'com.github.razerdp:BasePopup-compat-support:{$latestVersion}'
        • 如果您需要lifecycle库的支持,比如destroy里自动释放或者关闭等,请依赖
          • implementation 'com.github.razerdp:BasePopup-compat-lifecycle:{$latestVersion}'
        • 如果您需要androidX库的支持,请依赖
          • implementation 'com.github.razerdp:BasePopup-compat-androidx:{$latestVersion}'
        • 请注意,如果您依赖了androidX支持组件,请不要依赖另外两个支持组件,否则会冲突
    • Bug fixed:
    • Other:
      • add 996 license

例子预览

GravityPopupFrag LocatePopupFrag
AnyPosPopupFrag UpdatePopupFrag
BlurSlideFromBottomPopupFrag CommentPopup
SlideFromBottomPopup InputPopup
ListPopup MenuPopup

打赏(看在我那么努力维护的份上。。。给个零食呗~)

微信 支付宝

交流群:590777418

因为目前还有朋友圈项目,建立了一个交流群,出于懒得管理那么多,所以如果有想法或者优化建议或者其他问题,欢迎加入"朋友圈交流群"


常见问题

更多常见问题请看WIKI#常见问题

Q:如何取消默认的背景颜色

A:调用setBackgroundColor(Color.TRANSPARENT)或者setBackground(0)




Q:如何在dismiss()时不执行退出动画

A:调用dismiss(false)或者dismissWithOutAnimate()




Q:点击popupwindow背景部分不想让popupwindow隐藏怎么办

A:设置setOutSideDismiss(false)




(削除) Q:Service里无法弹出 (削除ここまで)【自2.2.1版本开始支持非ActivityContext里弹出】

(削除) A:PopupWindow需要windowToken,因此ApplicationContext或者Service里面是无法弹出的,建议通过发出事件通知栈顶Activity来弹出 (削除ここまで)




Q:为什么PopupWindow里面的EditText无法粘贴

ISSUE REF:#140

Google Issue Tracker:#36984016

A:PopupWindow内的View是无法获取WindowToken的,而粘贴功能也是一个PopupWindow,它的显示必定需要WindowToken,因此无法粘贴。




Q:如何不让PopupWindow的蒙层覆盖状态栏

A:设置setPopupWindowFullScreen(false)




Q:如何点击back键不关闭pop

A:设置setBackPressEnable(false)




Q:如何在BasePopup里使用ButterKnife

A:您可以在构造器中进行绑定:

 public DemoPopup(Context context) {
 super(context);
 ButterKnife.bind(this,getContentView());
 }



Q:为什么BasePopup的宽度不对或者留有一条缝隙

A:请务必留意您是否使用了头条类等修改Density的适配方案,BasePopup只遵循官方的测量方法并没有额外的添加别的测量方式,因此如果因为第三方修改导致的适配问题,本库概不负责

如果您用的是AndroidAutoSize,请尝试issue#13的解决方案:

在任何情况下本来适配正常的布局突然出现适配失效,适配异常等问题,只要重写 Activity 的 getResources() 方法即可,如果是 Dialog、PopupWindow 等控件出现适配失效或适配异常,同样在每次 show() 之前调用 AutoSize#autoConvertDensity() 即可




License

Apache-2.0

About

亲,还在为PopupWindow烦恼吗?不如试试BasePopup,你会爱上他的~

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Java 100.0%

AltStyle によって変換されたページ (->オリジナル) /