一 、 Gradle
implementation 'com.github.li-xiaojun:XPopup:2.6.6'
jitpack还要求在工程根目录的build.gradle中添加如下:
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
其中编译版本必须 >= 29:
compileSdkVersion 29
必须添加的依赖库,版本不用和我一致:
implementation 'androidx.appcompat:appcompat:1.3.1'
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.recyclerview:recyclerview:1.2.1'
混淆
-dontwarn com.lxj.xpopup.widget.**
-keep class com.lxj.xpopup.widget.**{*;}
功能很强大,涵盖市面上几乎所有的弹窗UI
带确认和取消按钮的弹窗
BasePopupView popupView;
...
case R.id.btnShowConfirm: //带确认和取消按钮的弹窗
/*if(popupView==null)*/
popupView = new XPopup.Builder(getContext())
.hasNavigationBar(false) //设置是否显示导航栏,默认是显示的。如果你希望弹窗隐藏导航栏,就设置为true
/*
* XPopup的弹窗默认是Dialog实现,该方法设置为true则切换为View实现,两者区别如下:
* 1. Dialog实现,独立Window渲染,性能是View实现的2倍以上,但部分与输入法交互效果无法做到,
* 比如根据输入进行联想搜索的场景,因为输入法也是一个Dialog,Android中无法实现2个Dialog同时获取焦点,
* 而设置为View模式即可轻松实现;
* 但是Dialog实现有个缺陷是弹窗内部无法使用Fragment,这是Android的限制;
* Dialog的层级高,会覆盖View层
* 2. View实现本质是把弹窗挂载到Activity的decorView上面,由于还是View,所以很多与输入法的交互都能实现;
* View实现内部完全可以使用Fragment;
* 缺点是和Activity相同渲染线程,性能比Dialog低
*
* @param viewMode 是否是View实现,默认是false
*/
.isViewMode(true)
/*
* 是否在弹窗消失后就立即释放资源,杜绝内存泄漏,仅仅适用于弹窗只用一次的场景,默认为false。
* 如果你的弹窗对象需是复用的,千万不要开启这个设置
*/
.isDestroyOnDismiss(true)
.hasBlurBg(true)//是否设置背景为高斯模糊背景。默认为false
.dismissOnTouchOutside(false)//设置点击弹窗外面是否关闭弹窗,默认为true
.autoDismiss(false)//设置当操作完毕后是否自动关闭弹窗,默认为true。比如:点击Confirm弹窗的确认按钮默认是关闭弹窗,如果为false,则不关闭
.popupAnimation(PopupAnimation.NoAnimation)// 为弹窗设置内置的动画器,默认情况下,已经为每种弹窗设置了效果最佳的动画器;如果你不喜欢,仍然可以修改。
.setPopupCallback(new DemoXPopupListener())// 设置弹窗显示和隐藏的回调监听
//.asCustom(new LoginPopup(getContext())); // 登陆弹窗样式
/*
* title:标题
* content:内容
* cancelBtnText:取消按钮文本(左边按钮文本)
* confirmBtnText:确定按钮文本(右边按钮文本)
* confirmListener:确定按钮点击事件(右边按钮点击事件)
* cancelListener:取消按钮点击事件(左边按钮点击事件)
* isHideCancel:是否隐藏左侧按钮(设置单个点击按钮使用)
*/
.asConfirm("哈哈", "床前明月光,疑是地上霜;举头望明月,低头思故乡。",
"取消", "确定",
new OnConfirmListener() {
@Override
public void onConfirm() {
popupView.dismiss();
}
}, null, true);
popupView.show();
break;
在中间弹出的List列表弹窗,带选中效果
case R.id.btnShowCenterListWithCheck: //在中间弹出的List列表弹窗,带选中效果
new XPopup.Builder(getContext())
.isDestroyOnDismiss(true) //对于只使用一次的弹窗,推荐设置这个
.asCenterList("请选择一项", new String[]{"条目1", "条目2", "条目3", "条目4"},
null, 1,
new OnSelectListener() {
@Override
public void onSelect(int position, String text) {
toast("click " + text);
}
})
.show();
break;
case R.id.btnShowCenterListWithCheck: //在中间弹出的List列表弹窗,带选中效果
new XPopup.Builder(getContext())
.isDestroyOnDismiss(true) //对于只使用一次的弹窗,推荐设置这个
/*
* title:标题
* data:数据列表
* iconIds :图片列表
* checkedPosition:选中的位置
* selectListener:选中回调事件
*/
.asCenterList("请选择一项", new String[]{"条目1", "条目2", "条目3", "条目4"},
new int[]{R.drawable.ic_launcher_background}, 1,
new OnSelectListener() {
@Override
public void onSelect(int position, String text) {
toast("click " + text);
}![02.png](https://upload-images.jianshu.io/upload_images/22679253-94481b7fc95879df.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
})
.show();
break;
从底部弹出,带手势拖拽的列表弹窗,带选中效果
case R.id.btnShowBottomListWithCheck: //从底部弹出,带手势拖拽的列表弹窗,带选中效果
new XPopup.Builder(getContext())
.isDestroyOnDismiss(true) //对于只使用一次的弹窗,推荐设置这个
.asBottomList("标题可以没有", new String[]{"条目1", "条目2", "条目3", "条目4", "条目5"},
null, 2,
new OnSelectListener() {
@Override
public void onSelect(int position, String text) {
toast("click " + text);
}
})
.show();
break;
在中间弹出的Loading加载框
LoadingPopupView loadingPopup;
case R.id.btnShowLoading: //在中间弹出的Loading加载框
if (loadingPopup == null) {
loadingPopup = (LoadingPopupView) new XPopup.Builder(getContext())
.dismissOnBackPressed(false)
.isLightNavigationBar(true)
.isViewMode(true)
.asLoading("加载中")
.show();
} else {
loadingPopup.show();
}
loadingPopup.postDelayed(new Runnable() {
@Override
public void run() {
loadingPopup.setTitle("加载中长度变化啊");
loadingPopup.postDelayed(new Runnable() {
@Override
public void run() {
loadingPopup.setTitle("");
}
}, 2000);
}
}, 2000);
// loadingPopup.smartDismiss();
// loadingPopup.dismiss();
loadingPopup.delayDismissWith(6000, new Runnable() {
@Override
public void run() {
toast("我消失了!!!");
}
});
break;
显示自定义Bottom弹窗(自带拖拽交互)
case R.id.btnCustomBottomPopup: //自定义的底部弹窗
new XPopup.Builder(getContext())
.moveUpToKeyboard(false) //如果不加这个,评论弹窗会移动到软键盘上面
.enableDrag(true)
.isViewMode(true)
.isDestroyOnDismiss(true) //对于只使用一次的弹窗,推荐设置这个
// .isThreeDrag(true) //是否开启三阶拖拽,如果设置enableDrag(false)则无效
.asCustom(new ZhihuCommentPopup(getContext())/*.enableDrag(false)*/)
.show();
break;
-----------------------------------------------------------------------------------------------------------------
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.lxj.easyadapter.EasyAdapter;
import com.lxj.easyadapter.MultiItemTypeAdapter;
import com.lxj.easyadapter.ViewHolder;
import com.lxj.xpopup.XPopup;
import com.lxj.xpopup.core.BasePopupView;
import com.lxj.xpopup.core.BottomPopupView;
import com.lxj.xpopup.interfaces.SimpleCallback;
import com.lxj.xpopup.util.XPopupUtils;
import com.lxj.xpopup.widget.VerticalRecyclerView;
import com.lxj.xpopupdemo.DemoActivity;
import com.lxj.xpopupdemo.R;
import java.util.ArrayList;
/**
* Description: 仿知乎底部评论弹窗
* Create by dance, at 2018/12/25
*/
public class ZhihuCommentPopup extends BottomPopupView {
VerticalRecyclerView recyclerView;
private ArrayList data;
private EasyAdapter commonAdapter;
public ZhihuCommentPopup(@NonNull Context context) {
super(context);
}
@Override
protected int getImplLayoutId() {
return R.layout.custom_bottom_popup;
}
@Override
protected void onCreate() {
super.onCreate();
recyclerView = findViewById(R.id.recyclerView);
findViewById(R.id.tv_temp).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//弹出新的弹窗用来输入
final CustomEditTextBottomPopup textBottomPopup = new CustomEditTextBottomPopup(getContext());
new XPopup.Builder(getContext())
.autoOpenSoftInput(true)
.autoFocusEditText(true)
.setPopupCallback(new SimpleCallback() {
@Override
public void onShow(BasePopupView popupView) {
}
@Override
public void onDismiss(BasePopupView popupView) {
String comment = textBottomPopup.getComment();
if (!comment.isEmpty()) {
data.add(0, comment);
commonAdapter.notifyDataSetChanged();
}
}
})
.asCustom(textBottomPopup)
.show();
}
});
data = new ArrayList<>();
for (int i = 0; i < 15; i++) {
data.add("这是一个自定义Bottom类型的弹窗!你可以在里面添加任何滚动的View,我已经智能处理好嵌套滚动,你只需编写UI和逻辑即可!");
}
commonAdapter = new EasyAdapter(data, R.layout.adapter_zhihu_comment) {
@Override
protected void bind(@NonNull ViewHolder holder, @NonNull String s, final int position) {
holder.setText(R.id.name, "知乎大神 - " + position)
.setText(R.id.comment, s);
holder.getView(R.id.btnDel).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
data.remove(position);
commonAdapter.notifyItemRemoved(position);
commonAdapter.notifyItemRangeChanged(position, data.size());
}
});
}
};
commonAdapter.setOnItemClickListener(new MultiItemTypeAdapter.SimpleOnItemClickListener() {
@Override
public void onItemClick(View view, RecyclerView.ViewHolder holder, int position) {
//不要直接这样做,会导致消失动画未执行完就跳转界面,不流畅。
// dismiss();
// getContext().startActivity(new Intent(getContext(), DemoActivity.class))
//可以等消失动画执行完毕再开启新界面
dismissWith(new Runnable() {
@Override
public void run() {
getContext().startActivity(new Intent(getContext(), DemoActivity.class));
}
});
}
});
recyclerView.setAdapter(commonAdapter);
}
//完全可见执行
@Override
protected void onShow() {
super.onShow();
Log.e("tag", "知乎评论 onShow");
}
//完全消失执行
@Override
protected void onDismiss() {
Log.e("tag", "知乎评论 onDismiss");
}
@Override
protected int getMaxHeight() {
return (int) (XPopupUtils.getScreenHeight(getContext()) * .7f);
}
}
依附于某个View的Attach类型弹窗
AttachPopupView attachPopupView = new XPopup.Builder(getContext())
.hasShadowBg(false)
.isViewMode(true)
.isClickThrough(true)
// .isDestroyOnDismiss(true) //对于只使用一次的弹窗,推荐设置这个
// .isDarkTheme(true)
// .popupAnimation(PopupAnimation.ScrollAlphaFromTop) //NoAnimation表示禁用动画
// .isCenterHorizontal(true) //是否与目标水平居中对齐
// .offsetY(60)
// .offsetX(80)
// .popupPosition(PopupPosition.Top) //手动指定弹窗的位置
// .popupWidth(500)
.atView(v) // 依附于所点击的View,内部会自动判断在上方或者下方显示
.asAttachList(new String[]{"分享", "编辑", "不带icon", "分享分享分享",},
new int[]{R.mipmap.ic_launcher_round, R.mipmap.ic_launcher_round},
new OnSelectListener() {
@Override
public void onSelect(int position, String text) {
toast("click " + text);
}
}, 0, 0/*, Gravity.LEFT*/);
attachPopupView.show();
点击显示
// 必须在事件发生前,调用这个方法来监视View的触摸
final XPopup.Builder builder = new XPopup.Builder(getContext())
// .isCenterHorizontal(true)
.watchView(view.findViewById(R.id.btnShowAttachPoint));
view.findViewById(R.id.btnShowAttachPoint).setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
XPopup.fixLongClick(v);//能保证弹窗弹出后,下层的View无法滑动
builder.asAttachList(new String[]{"置顶11", "复制", "删除", "编辑编辑编辑编辑"
}, null,
new OnSelectListener() {
@Override
public void onSelect(int position, String text) {
toast("click " + text);
}
})
.show();
return true;
}
});
drawerPopupView = new CustomDrawerPopupView(getContext());
水平方向的Attach弹窗,就像微信朋友圈的点赞弹窗那样
case R.id.btnAttachPopup1: //水平方向的Attach弹窗,就像微信朋友圈的点赞弹窗那样
new XPopup.Builder(getContext())
.isDestroyOnDismiss(true) //对于只使用一次的弹窗,推荐设置这个
// .offsetX(50) //偏移10
// .offsetY(10) //往下偏移10
// .popupPosition(PopupPosition.Right) //手动指定位置,有可能被遮盖
.hasShadowBg(false) // 去掉半透明背景
.isViewMode(true)
.atView(v)
.asCustom(new CustomAttachPopup(getContext()))
.show();
break;
-----------------------------------------------
import android.content.Context;
import androidx.annotation.NonNull;
import android.view.View;
import android.widget.Toast;
import com.lxj.xpopup.core.HorizontalAttachPopupView;
import com.lxj.xpopupdemo.R;
import com.lxj.xpopupdemo.XPopupApp;
/**
* Description: 自定义Attach弹窗,水平方向的
* Create by lxj, at 2019/3/13
*/
public class CustomAttachPopup extends HorizontalAttachPopupView {
public CustomAttachPopup(@NonNull Context context) {
super(context);
}
@Override
protected int getImplLayoutId() {
return R.layout.custom_attach_popup;
}
@Override
protected void onCreate() {
super.onCreate();
findViewById(R.id.tv_zan).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(XPopupApp.context, "赞", Toast.LENGTH_LONG).show();
dismiss();
}
});
findViewById(R.id.tv_comment).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(XPopupApp.context, "评论", Toast.LENGTH_LONG).show();
dismiss();
}
});
}
------------------------
水平方向带气泡弹窗
case R.id.btnBubbleAttachPopup1: //水平方向带气泡弹窗
new XPopup.Builder(getContext())
.isDestroyOnDismiss(true) //对于只使用一次的弹窗,推荐设置这个
.atView(v)
.hasShadowBg(false) // 去掉半透明背景
.asCustom(new CustomHorizontalBubbleAttachPopup(getContext()))
.show();
break;
-----------------------------
import android.content.Context;
import android.graphics.Color;
import android.view.View;
import android.widget.Toast;
import androidx.annotation.NonNull;
import com.lxj.xpopup.core.BubbleHorizontalAttachPopupView;
import com.lxj.xpopup.util.XPopupUtils;
import com.lxj.xpopupdemo.R;
import com.lxj.xpopupdemo.XPopupApp;
/**
* Description: 自定义Attach弹窗,水平方向的带气泡的弹窗
* Create by lxj, at 2019/3/13
*/
public class CustomHorizontalBubbleAttachPopup extends BubbleHorizontalAttachPopupView {
public CustomHorizontalBubbleAttachPopup(@NonNull Context context) {
super(context);
}
@Override
protected int getImplLayoutId() {
return R.layout.custom_attach_popup;
}
@Override
protected void onCreate() {
super.onCreate();
setBubbleBgColor(Color.parseColor("#4D5063"));
setBubbleShadowSize(XPopupUtils.dp2px(getContext(), 10));
setBubbleShadowColor(Color.BLACK);
getPopupImplView().setBackgroundResource(0);
findViewById(R.id.tv_zan).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(XPopupApp.context, "赞", Toast.LENGTH_LONG).show();
dismiss();
}
});
findViewById(R.id.tv_comment).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(XPopupApp.context, "评论", Toast.LENGTH_LONG).show();
dismiss();
}
});
}
}