安卓开发:自定义PopupWindow,实现模仿iOS底部弹出菜单
先贴上效果图
如图,从下面弹出菜单,菜单上面的item是可以扩展的。
先说一下思路,具体布局没啥难点,上面是一个可以扩展的布局,使用ListView和 RecyclerView都可以,我就用RecyclerView做例子了,下面的“取消”就是一个可以点击的按钮或者文字。。。
菜单的子项都是其中的一个item,当然我写的比较简单,满足项目需求,使用的时候还可以加上小图标。。。
先写item的布局,就一个文字,还有一条横线,最下面的item没有横线,所以也需要命名,最后一条要隐藏掉,代码贴上:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="46dp"
android:background="@drawable/selector_btn">
<TextView
android:id="@+id/item_popup_tv"
android:layout_width="match_parent"
android:layout_height="46dp"
android:gravity="center"
android:textColor="@color/blue"
android:textSize="16dp" />
<View
android:id="@+id/item_popup_line"
android:layout_width="match_parent"
android:layout_height="1px"
android:background="#c8c8c8"
android:layout_alignParentBottom="true" />
</RelativeLayout>
很简单,就一个textview,一条线。
接下来开始写自定义PopupWindow的布局文件:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="bottom">
<View
android:id="@+id/popup_btm_bg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/popup_btm_rv"
android:background="#60000000" />
<android.support.v7.widget.RecyclerView
android:id="@+id/popup_btm_rv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/popup_btm_line"
android:background="@color/white" />
<View
android:id="@+id/popup_btm_line"
android:layout_width="match_parent"
android:layout_height="6dp"
android:layout_above="@+id/popup_btm_cancel_tv"
android:background="@color/tm_huise" />
<TextView
android:id="@+id/popup_btm_cancel_tv"
android:layout_width="match_parent"
android:layout_height="46dp"
android:layout_alignParentBottom="true"
android:background="@drawable/tm_selector_btn_anxia"
android:gravity="center"
android:text="取消"
android:textColor="@color/tm_blue"
android:textSize="16dp" />
</RelativeLayout>
也很简单,上面半透明的view是为了实现半透明效果,点击此处也可以实现关闭PopupWindow,中间是一个RecyclerView,用来放我们定义的菜单项,下面的就是一条分割线和取消按钮了,点击“取消”就可以关闭PopupWindow了;
然后再来写RecyclerView的Adapter;自从用了RecyclerView,就迷上他了,不知道是不是心里作用,感觉RecyclerView比ListView效率高一些(好多大牛也这么说),话不多说,贴上Adapter代码
private class RvAdapter extends RecyclerView.Adapter<RvAdapter.ViewHolder> {
@Override
public int getItemCount() {
return datas.size();
}
@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
holder.itemPopupTv.setText(datas.get(position));
//最后一条要隐藏分割线
holder.itemPopupLine.setVisibility(position + 1 == datas.size() ? View.GONE : View.VISIBLE);
//实现item的点击事件
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
itemClickListener.onItemClick(v, position);
}
});
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.item_custom_popup, parent, false);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView itemPopupTv;
private View itemPopupLine;
public ViewHolder(View itemView) {
super(itemView);
itemPopupTv = (TextView) itemView.findViewById(R.id.item_popup_tv);
itemPopupLine = itemView.findViewById(R.id.item_popup_line);
}
}
}
最后,重头戏来了,万事俱备,就差PopupWindow代码了:
public class BottomPopupWindow extends PopupWindow {
private String TAG = "BottomPopupWindow";
private FragmentActivity context;
//RecyclerView的数据源
private List<String> datas;
//RecyclerView的item点击回调
private OnItemClickListener itemClickListener;
public BottomPopupWindow(FragmentActivity context, List<String> datas, OnItemClickListener itemClickListener) {
this.context = context;
this.datas = datas;
this.itemClickListener = itemClickListener;
foundPopup();
}
private void foundPopup() {
View contentView = View.inflate(context, R.layout.popup_custom_btm, null);
View popupBtmBg = contentView.findViewById(R.id.popup_btm_bg);
RecyclerView popupBtmRv = (RecyclerView) contentView.findViewById(R.id.popup_btm_rv);
TextView popupBtmCancelTv = (TextView) contentView.findViewById(R.id.popup_btm_cancel_tv);
LinearLayoutManager layoutManager = new LinearLayoutManager(context);
layoutManager.setAutoMeasureEnabled(true);
popupBtmRv.setLayoutManager(layoutManager);
setContentView(contentView);
setWidth(ViewGroup.LayoutParams.MATCH_PARENT);
setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
//设置弹出动画
setAnimationStyle(R.style.popWindow_animation_anim);
//使其聚集 ,要想监听菜单里控件的事件就必须要调用此方法
setFocusable(true);
//设置允许在外点击消失
setOutsideTouchable(true);
//设置背景,点击back可消失
setBackgroundDrawable(new BitmapDrawable());
//PopupWindow的显示及位置设置
showAtLocation(contentView, Gravity.BOTTOM, 0, 0);
popupBtmRv.setAdapter(new RvAdapter());
//取消按钮-点击关闭
popupBtmCancelTv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
}
});
//上部半透明背景-点击关闭
popupBtmBg.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
}
});
}
}
RecyclerView的点击回调
public interface OnItemClickListener {
void onItemClick(View view, int position);
}
这样,我们的可扩展的PopupWindow已经完工了,接下来说一下使用方法;
相信各位大牛已经看懂怎么是用了吧,初始化的时候把需要显示的item数据传递过来就可以了,然后做RecyclerView的Item点击事件就ok了。
使用如下:
首先需要初始化数据:
List<String> items = new ArrayList<>();
items.add("拍摄照片/视频");
items.add("从手机相册选择");
items.add("网页分享");
然后就可以调用了,因为我们在BottomPopupWindow里已经实现了各种情况下的关闭事件,所以,就不需要写show(),dismiss()方法了,
new BottomPopupWindow(context, items, new OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
//position是从0开始的
if (position == 0) {
//这里处理点击第一个item的事件
} else if (position == 1) {
//这里处理点击第二个item的事件
} else {
//这里处理点击第n个item的事件,可以继续往下写,items有几个就可以实现几个
}
finish();
}
});
就这样,拜拜,等会把代码传上去