利用PopupWindow制作顶部下拉菜单
顶部最常见的筛选下拉菜单,每个菜单view可以自定义,进出动画等都可以自定义。效果如图.
完整的例子demo见GitHub: https://github.com/yinghuihou/PopupWindow
开始撸代码
- 首先我们使用的控件是PopupWindow
- 筛选栏就是一个自定义layout,一个LinearLayout包着三个TextView,很简单没什么可说的,xml如下
- 最外层用标签是因为使用了DataBinding,可以省去findViewById这个操作,Java代码直接用 binding.xxx来获取控件
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:id="@+id/ll_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@color/gray_divider_line_color"
android:gravity="center_vertical"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/ll_bank"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:orientation="horizontal">
<TextView
android:id="@+id/all_bank"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="10dp"
android:paddingTop="10dp"
android:text="全部银行"
android:textColor="@color/load_txt_color_3"
android:textSize="12dp" />
<ImageView
android:id="@+id/bank_img"
android:layout_width="5dp"
android:layout_height="3dp"
android:layout_marginLeft="5dp"
android:src="@drawable/img_small_arrow_down" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_topic"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:orientation="horizontal">
<TextView
android:id="@+id/all_topic"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="10dp"
android:paddingTop="10dp"
android:text="全部主题"
android:textColor="@color/load_txt_color_3"
android:textSize="12dp" />
<ImageView
android:id="@+id/topic_img"
android:layout_width="5dp"
android:layout_height="3dp"
android:layout_marginLeft="5dp"
android:src="@drawable/img_small_arrow_down" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_more"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:clickable="false"
android:gravity="center"
android:orientation="horizontal">
<TextView
android:id="@+id/more"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="10dp"
android:paddingTop="10dp"
android:text="更多"
android:textColor="@color/load_txt_color_3"
android:textSize="12dp" />
<ImageView
android:id="@+id/more_img"
android:layout_width="5dp"
android:layout_height="3dp"
android:layout_marginLeft="5dp"
android:src="@drawable/img_small_arrow_down" />
</LinearLayout>
</LinearLayout>
</layout>
- 开始写Java文件HotCreditCardSelectLayout.java
- 首先就是对三个筛选item设置点击事件
- 在这里有三个筛选项,所以我用了三个PopupWindow来操作,互不影响操作灵活一些
mBinding.allBank.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mBankPopupwindow != null && mBankPopupwindow.isShowing()) {
dismissPopWindow(mBankPopupwindow);
} else {
if (mBankPopupwindow == null) {
mBankPopupwindow = initmPopupWindowView(mData.bank, TYPE_BANK);
}
showPopWindow(TYPE_BANK, v);
}
}
});
mBinding.allTopic.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mTopicPopupwindow != null && mTopicPopupwindow.isShowing()) {
dismissPopWindow(mTopicPopupwindow);
} else {
if (mTopicPopupwindow == null) {
mTopicPopupwindow = initmPopupWindowView(mData.topic, TYPE_TOPIC);
}
showPopWindow(TYPE_TOPIC, v);
}
}
});
mBinding.more.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
if (mMorePopupwindow != null && mMorePopupwindow.isShowing()) {
dismissPopWindow(mMorePopupwindow);
} else {
if (mMorePopupwindow == null) {
mMorePopupwindow = initmPopupWindowView(mData);
}
showPopWindow(TYPE_MORE, v);
}
}
});
- 这里主要就是三个方法,dismissPopWindow,initmPopupWindowView,showPopWindow。这三个都是我封装过后的方法,很简单也很好理解
- showPopWindow方法中的常量参数是为了根据不同的筛选项做不同的操作的,因为每个筛选项下拉出来的菜单view可能不一样
1. 生成下拉菜单 initmPopupWindowView
这里我写了两个一样的方法,因为前两个菜单是listview下拉菜单,最后一个是自定义RadioButton单选菜单
- 先看生成listview的下拉菜单方法
private PopupWindow initmPopupWindowView(final List<HotCreditCardPageData.SelectItem> list, final int type) {
// 获取popwindow布局文件的视图
View customView = LayoutInflater.from(getContext()).inflate(R.layout.layout_popwindow_list_view,
null, false);
MaxHeightListView listView = customView.findViewById(R.id.list_view);
//填充数据
if (type == TYPE_BANK) {
mBankAdapter = new CardSelectAdapter(getContext());
mBankAdapter.setList(list);
listView.setAdapter(mBankAdapter);
} else if (type == TYPE_TOPIC) {
mTopicAdapter = new CardSelectAdapter(getContext());
mTopicAdapter.setList(list);
listView.setAdapter(mTopicAdapter);
}
final PopupWindow popupwindow = generatePopupWindow(customView);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (mListener == null) {
return;
}
if (type == TYPE_BANK) {
mParams.put("bank_id", String.valueOf(list.get(position).id));
mBinding.allBank.setText(list.get(position).value);
mListener.onItemClick(mParams);
} else if (type == TYPE_TOPIC) {
mParams.put("topic_id", String.valueOf(list.get(position).id));
mBinding.allTopic.setText(list.get(position).value);
mListener.onItemClick(mParams);
}
if (popupwindow != null && popupwindow.isShowing()) {
dismissPopWindow(popupwindow);
}
}
});
return popupwindow;
}
这里向listview中填充数据就不用多说,最基本的。listview的点击事件,选中时将对应选中的id加入map,请求页面数据使用
2.生成更多页面的popupWindow方法
这里的view可以自己定义,数据填充方法都不相同,页面效果图是这样的
代码如下
//生成更多页面的Window
private PopupWindow initmPopupWindowView(HotCreditCardPageData.Select data) {
// 获取自定义布局文件pop.xml的视图
moreItemBinding = DataBindingUtil.inflate(LayoutInflater.from(getContext()), R.layout.layout_popwindow_custom_view,
null, false);
//填充数据
moreItemBinding.cardLevel.setText(data.level_title);
moreItemBinding.cardAnnualFee.setText(data.annual_fee_title);
setMoreViewData(data.level, moreItemBinding.cardLevelContent, TYPE_LEVEL);
setMoreViewData(data.annual_fee, moreItemBinding.cardAnnualFeeContent, TYPE_FEE);
final PopupWindow popupwindow = generatePopupWindow(moreItemBinding.getRoot());
moreItemBinding.confirm.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
int levelId = moreItemBinding.cardLevelContent.getCheckedRadioButtonId();
int annualFeeId = moreItemBinding.cardAnnualFeeContent.getCheckedRadioButtonId();
if (levelId == -1) {
mParams.put("level_id", "0");
} else {
mParams.put("level_id", String.valueOf(levelId));
}
if (annualFeeId == -1) {
mParams.put("annual_fee", "0");
} else {
mParams.put("annual_fee", String.valueOf(annualFeeId));
}
if (mListener != null) {
mListener.onItemClick(mParams);
}
if (popupwindow != null && popupwindow.isShowing()) {
dismissPopWindow(popupwindow);
}
}
});
return popupwindow;
}
这里不要在乎填充数据的方法,可以自行扩展。这里和上个一样都有一个共同的方法generatePopupWindow。这个方法是生成Window的核心方法
代码如下
//根据view初始化popupWindow
public PopupWindow generatePopupWindow(View customView) {
final PopupWindow popupwindow = new PopupWindow(customView,
LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
popupwindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
popupwindow.setOutsideTouchable(false);
popupwindow.setAnimationStyle(R.style.popup_animation);
popupwindow.setFocusable(false);
//弹出框消失,筛选条颜色和箭头归位
popupwindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
@Override
public void onDismiss() {
resetSelectView();
}
});
return popupwindow;
}
- 这里一定要注意,setOutsideTouchable一定要置为false,是为了点击Window外部区域自身不消失,因为这样我们可以很灵活的控制Window的消失时机
- 同时,setFocusable(false)也很重要,因为如果设置为true,在三个item之间切换时候,Window会点击一下先消失,再次点击才弹出
- resetSelectView()这个方法是让Window消失时候标题颜色设置为黑色,并且小箭头归位用的,可以无视
3.showPopWindow方法
在点击筛选item时候,如果当前对应的Window在显示,则收起自己的Window,如果别的item对应的Window在显示,则先收起所有Window,在显示自己的Window
public void showPopWindow(int type, View view) {
//取消所有在显示的Window
dismissAllPopWindow();
String selectItemText = "";
switch (type) {
case TYPE_BANK:
selectItemText = mBinding.allBank.getText().toString();
mBankPopupwindow.showAsDropDown(view);
setOpenState(mBinding.allBank, mBinding.bankImg);
mBankAdapter.setSelectItem(selectItemText);
break;
case TYPE_TOPIC:
selectItemText = mBinding.allTopic.getText().toString();
mTopicPopupwindow.showAsDropDown(view);
setOpenState(mBinding.allTopic, mBinding.topicImg);
mTopicAdapter.setSelectItem(selectItemText);
break;
case TYPE_MORE:
setOpenState(mBinding.more, mBinding.moreImg);
mMorePopupwindow.showAsDropDown(view);
break;
default:
break;
}
if (mListener != null) {
mListener.onSelectTitleClick();
}
}
- setOpenState方法就是对应的Window展开时候筛选item颜色变为蓝色,箭头变换方向的动作
4.dismissPopWindow这个就很简单了
//关闭单个popWindow
public void dismissPopWindow(PopupWindow popupWindow) {
popupWindow.dismiss();
if (mListener != null) {
mListener.closeBackground();
}
}
public void dismissAllPopWindow() {
if (mBankPopupwindow != null && mBankPopupwindow.isShowing()) {
mBankPopupwindow.dismiss();
}
if (mTopicPopupwindow != null && mTopicPopupwindow.isShowing()) {
mTopicPopupwindow.dismiss();
}
if (mMorePopupwindow != null && mMorePopupwindow.isShowing()) {
mMorePopupwindow.dismiss();
}
}
最后附加上下拉菜单进出的动画,需要的直接复制即可
设置展开收起动画是在初始化PopupWindow时候直接设置的xml文件,这样设置setAnimationStyle:
popupwindow.setOutsideTouchable(false);
popupwindow.setAnimationStyle(R.style.popup_animation);
popupwindow.setFocusable(false);
然后在style.xml里定义进出动画:
<style name="popup_animation" mce_bogus="1" parent="android:Animation">
<item name="android:windowEnterAnimation">@anim/dialog_in</item>
<item name="android:windowExitAnimation">@anim/dialog_out</item>
</style>
最后在res下的anim文件夹里自定义你的进出动画文件即可:
dialog_in.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true"
android:fillEnabled="true" >
<scale
android:duration="200"
android:fromXScale="1.0"
android:fromYScale="0.0"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:pivotX="50%"
android:pivotY="0%"
android:toXScale="1.0"
android:toYScale="1.0" >
</scale>
<alpha
android:duration="180"
android:fromAlpha="0.0"
android:toAlpha="1.0" />
</set>
dialog_out.xml:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillEnabled="true"
android:fillAfter="true">
<scale
android:duration="200"
android:fromXScale="1.0"
android:fromYScale="1.0"
android:interpolator="@android:anim/accelerate_interpolator"
android:pivotX="50%"
android:pivotY="0%"
android:toXScale="1.0"
android:toYScale="0.0" >
</scale>
<alpha
android:duration="180"
android:fromAlpha="1.0"
android:toAlpha="0.0" />
</set>
完整的demo例子在GitHub
https://github.com/yinghuihou/PopupWindow
刚开始写博客写的不好大家将就着看看吧,有疑问或者意见可留言