动画弹出PopupWindow并使背景变暗

我们在平常的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));
   
   
  • 1

最后通过

mPopupWindow.showAsDropDown(anchor,xoff,yoff);
   
   
  • 1

弹出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        
   
   
  • 1

如果当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>
   
   
  • 1

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;
    }
}

   
   
  • 1

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;
    }
}
   
   
  • 1

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>
   
   
  • 1

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);
    }
}

   
   
  • 1

实现效果如下:

这里写图片描述

注意!!!

onCreate方法中调用PopupWindow的错误:android.view.WindowManager$BadTo

如题:在activity的oncreate方法中使用popupwindow出现以下错误:
android.view.WindowManager$BadTokenException: Unable to add window --
token null is not valid; is your activity running?

错误代码如下 :

   
   
  1. pop = new PopupWindow(pop_view,320,250);
  2. pop.showAtLocation(parent, Gravity.TOP,0, 0);

解决方法:
应把pop.showAtLocation(parent, Gravity.TOP,0, 0)这一句移出oncreate方法,在控件渲染完毕后再使用。

但是移出oncreate方法的话该移到哪里去呢?网友的方法大概是这几种:

1、移到事件中(比如一个button的click事件中);
2、移到子线程中;另起一线程,在线程中不断循环,直到判断控件是否渲染完毕(如长宽大于0),不推荐。。。
3、移到重写的控件(parent)中,在控件ondraw()完后生成pop。
ps:1、2绝对没问题,3没测试过。


后来在网上找到一个绝佳的方法:

   
   
  1. @Override
  2. public void onWindowFocusChanged(boolean hasFocus) {
  3. // TODO Auto-generated method stub
  4. super.onWindowFocusChanged(hasFocus);
  5. if(hasFocus){
  6. showPopupWindow(getApplicationContext());
  7. }
  8. }

其中showPopupWindow(getApplicationContext())是我自己定义的专门显示popupwindow的一个函数。

当activity获得焦点之后,activity是加载完毕的了,这个方法的技巧性比较强,很难想到


源码下载:https://github.com/lololiu/demo4popupwindow.git

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值