我们在平常的android应用开发过程中,当应用数据太多太繁杂时,通常都会通过分类筛选让用户更好的找到自己想要的信息。因此利用PopupWindow或Dialog让用户快速选择定位是一个很好的选择。如我们想在美团上查找附近有什么电影院时:
点击按钮弹出popupwindow,popupwindow是很好实现的,只需要使用PopupWindow的构造方法再将自己写的布局引入进去即可:
View popupView = getLayoutInflater().inflate(R.layout.layout_popupwindow, null);
mPopupWindow = new PopupWindow(popupView, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT, true);
//设置点击空白处消失
mPopupWindow.setTouchable(true);
mPopupWindow.setOutsideTouchable(true);
mPopupWindow.setBackgroundDrawable(new BitmapDrawable(getResources(), (Bitmap) null));
最后通过
mPopupWindow.showAsDropDown(anchor,xoff,yoff);
弹出popupwindow。
但是这样实现出来的效果只是在原来某个view旁弹出一个选项框,其他地方没有发生任何变化。如果想要在界面上实现一层黑色半透明遮罩将弹出框与主界面区分开来给用户更好的体验,这黑色透明背景又如何实现呢?
通过网上翻看资料,有各种各样的实现方法。其中有一种是在popupwindow弹出时改变window的透明度的属性,而监听到popupwindow dismiss的事件时再将其改回来。主要代码实现如下:
// 设置背景颜色变暗
WindowManager.LayoutParams lp = getWindow().getAttributes();
lp.alpha = 0.7f;
getWindow().setAttributes(lp);
mPopupWindow.setOnDismissListener(new OnDismissListener() {
@Override
public void onDismiss() {
WindowManager.LayoutParams lp = getWindow().getAttributes();
lp.alpha = 1f;
getWindow().setAttributes(lp);
}
});
//摘自:http://blog.csdn.net/harryweasley/article/details/46914121
如果当PopupWindow是在屏幕中间或者从下方弹出时,这是一种很好的实现方式,但是如果我想要它从ActionBar正下方弹出,就会发现ActionBar的背景也变暗了,这样会显得界面很不协调。
由上面联想到,如果我在界面最上层自己放一个黑色半透明的View,平常让它隐藏掉,当PopupWindow显示的时候让它也显示出来就OK了,PopupWindow可以使用动画让其从ActionBar后面慢慢滑出来!
具体代码实现如下:
content_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:showIn="@layout/activity_main" tools:context=".MainActivity">
<!--黑色背景遮罩层,平时隐藏 -->
<View
android:id="@+id/gray_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
android:background="#66000000"/>
</RelativeLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity {
private final static String TAG="MainActivity";
private PopupWindow mPopupWindow;
private Toolbar toolbar;
private View mGrayLayout;
private boolean isPopWindowShowing=false;
int fromYDelta;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = (Toolbar) findViewById(R.id.toolbar);
mGrayLayout=findViewById(R.id.gray_layout);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
//对黑色半透明背景做监听,点击时开始退出动画并将popupwindow dismiss掉
mGrayLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(isPopWindowShowing){
mPopupWindow.getContentView().startAnimation(AnimationUtil.createOutAnimation(MainActivity.this, fromYDelta));
mPopupWindow.getContentView().postDelayed(new Runnable() {
@Override
public void run() {
mPopupWindow.dismiss();
}
},AnimationUtil.ANIMATION_OUT_TIME);
}
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
if(isPopWindowShowing){
mPopupWindow.getContentView().startAnimation(AnimationUtil.createOutAnimation(MainActivity.this, fromYDelta));
mPopupWindow.getContentView().postDelayed(new Runnable() {
@Override
public void run() {
mPopupWindow.dismiss();
}
},AnimationUtil.ANIMATION_OUT_TIME);
}else{
showPopupWindow();
}
// return true;
}
return super.onOptionsItemSelected(item);
}
private void showPopupWindow(){
final View contentView= LayoutInflater.from(this).inflate(R.layout.selectlist,null);
TextView t1= (TextView) contentView.findViewById(R.id.text1);
mPopupWindow=new PopupWindow(contentView, LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.WRAP_CONTENT);
mPopupWindow.setBackgroundDrawable(new BitmapDrawable());
//将这两个属性设置为false,使点击popupwindow外面其他地方不会消失
mPopupWindow.setOutsideTouchable(false);
mPopupWindow.setFocusable(false);
mGrayLayout.setVisibility(View.VISIBLE);
//获取popupwindow高度确定动画开始位置
int contentHeight=ViewUtils.getViewMeasuredHeight(contentView);
Log.i(TAG,"contentview height="+contentHeight);
mPopupWindow.showAsDropDown(toolbar, 0, 0);
fromYDelta=-contentHeight-50;
Log.i(TAG,"fromYDelta="+fromYDelta);
mPopupWindow.getContentView().startAnimation(AnimationUtil.createInAnimation(this, fromYDelta));
mPopupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
@Override
public void onDismiss() {
isPopWindowShowing=false;
mGrayLayout.setVisibility(View.GONE);
}
});
t1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Snackbar.make(findViewById(R.id.gray_layout), "click 1", Snackbar.LENGTH_SHORT)
.setAction("Action", null).show();
}
});
isPopWindowShowing=true;
}
}
AnimationUtil.java
public class AnimationUtil {
//动画持续时间
public final static int ANIMATION_IN_TIME=500;
public final static int ANIMATION_OUT_TIME=500;
public static Animation createInAnimation(Context context,int fromYDelta){
AnimationSet set=new AnimationSet(context,null);
set.setFillAfter(true);
TranslateAnimation animation=new TranslateAnimation(0,0,fromYDelta,0);
animation.setDuration(ANIMATION_IN_TIME);
set.addAnimation(animation);
AlphaAnimation alphaAnimation=new AlphaAnimation(0,1);
alphaAnimation.setDuration(ANIMATION_IN_TIME);
set.addAnimation(alphaAnimation);
return set;
}
public static Animation createOutAnimation(Context context,int toYDelta){
AnimationSet set=new AnimationSet(context,null);
set.setFillAfter(true);
TranslateAnimation animation=new TranslateAnimation(0,0,0,toYDelta);
animation.setDuration(ANIMATION_OUT_TIME);
set.addAnimation(animation);
AlphaAnimation alphaAnimation=new AlphaAnimation(1,0);
alphaAnimation.setDuration(ANIMATION_OUT_TIME);
set.addAnimation(alphaAnimation);
return set;
}
}
selectlist.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:background="#ffffff"
android:orientation="vertical">
<TextView
android:id="@+id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="@string/select_1"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="@string/select_2"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="@string/select_3"/>
</LinearLayout>
ViewUtils.java
public class ViewUtils {
/**
* 获取控件的高度
*/
public static int getViewMeasuredHeight(View view) {
calculateViewMeasure(view);
return view.getMeasuredHeight();
}
/**
* 获取控件的宽度
*/
public static int getViewMeasuredWidth(View view) {
calculateViewMeasure(view);
return view.getMeasuredWidth();
}
/**
* 测量控件的尺寸
*/
private static void calculateViewMeasure(View view) {
int w = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
int h = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
view.measure(w, h);
}
}
实现效果如下: