Android PopupWindow实现带背景阴影的下滑选择框

来源:互联网 发布:基金投资组合 知乎 编辑:程序博客网 时间:2024/05/18 00:29

先上图:

这里写图片描述

效果还是很丝滑的,这里动画主要用到了属性动画。实现逻辑很简单,动画都是在popupwindow调用showAsDropDown()dismiss()时执行。这里主要是注意退出动画的实现,在dismiss()中执行动画是无效的,需要在动画执行完毕后再执行super.dismiss(); 可拓展能力强,可以结合自身需求实现不同的效果。

以下是源码:

PopupWindow :

public class TypeSelectWindow extends PopupWindow {    private Activity activity;    private BDBaseAdapter bdBaseAdapter = null;    View contentView;//弹出框的根布局,可以监听其点击事件,达到点击阴影消失弹框的效果    GridView gridView;    public TypeSelectWindow(Activity activity){        this.activity = activity;        initDatas();        initView();    }    private void initView(){        this.setWidth(ViewGroup.LayoutParams.MATCH_PARENT);        this.setHeight(ViewGroup.LayoutParams.MATCH_PARENT);        contentView = LayoutInflater.from(activity).inflate(R.layout.join_popup_layout,null);        gridView =  contentView.findViewById(R.id.gridView);        bdBaseAdapter = new BDBaseAdapter<String>(activity,listDatas,R.layout.join_select_item) {            @Override            public void convert(BDViewHolder helper, String item, int position) {                ((TextView)helper.getView(R.id.text)).setText(item);            }        };        gridView.setAdapter(bdBaseAdapter);        this.setContentView(contentView);//设置布局        this.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));        this.setAnimationStyle(R.style.SelectPopupWindow);        this.setOutsideTouchable(true);        this.setFocusable(true);    }    /**     * 模拟数据     */    List<String> listDatas = new ArrayList<>();    private void initDatas(){        listDatas.clear();        for (int i = 0;i<10;i++){            listDatas.add("menu"+i);        }    }    //显示    public void showPopupWindow(View parent) {        if (!this.isShowing()) {            this.showAsDropDown(parent,0,0);            //执行进入动画,这里主要是执行列表下滑,背景变半透明在setAnimationStyle(R.style.SelectPopupWindow);中实现            AnimationUtil.createAnimation(true,contentView,gridView,null);        } else {            dismissPopup();        }    }    //消失    public void dismissPopup(){        super.dismiss();// 调用super.dismiss(),如果直接dismiss()会一直会调用下面的dismiss()    }    @Override    public void dismiss() {        //执行推出动画,列表上滑退出,同时背景变透明        AnimationUtil.createAnimation(false,contentView,gridView , new AnimationUtil.AnimInterface() {            @Override            public void animEnd() {                dismissPopup();//动画执行完毕后消失            }        });    }}

AnimationUtil:

public class AnimationUtil {    //动画持续时间    public final static int ANIMATION_IN_TIME=500;    public final static int ANIMATION_OUT_TIME=500;    /**     * @param isIn  动画类型,进入或消失     * @param rootView  根布局,主要用来设置半透明背景     * @param target    要移动的view     * @param animInterface  动画执行完毕后的回调     */    public static void createAnimation(final boolean isIn, final View rootView, final View target,                                       final AnimInterface animInterface){        final int toYDelta = ViewUtils.getViewMeasuredHeight(target);//测量布局高度        ValueAnimator valueAnimator = ValueAnimator.ofFloat(isIn?-toYDelta:0,isIn?0:-toYDelta);        valueAnimator.setDuration(isIn?ANIMATION_IN_TIME:ANIMATION_OUT_TIME);        valueAnimator.setRepeatCount(0);        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {            @Override            public void onAnimationUpdate(ValueAnimator animation) {                float currentValue = (Float) animation.getAnimatedValue();                target.setY(currentValue);                if (!isIn){//因为在setAnimationStyle(R.style.SelectPopupWindow);设置了进入动画,所以执行进入动画时不再设置                    rootView.setAlpha(1-Math.abs(currentValue)/animation.getDuration());                }            }        });        valueAnimator.addListener(new AnimatorListenerAdapter() {            @Override            public void onAnimationEnd(Animator animation) {                super.onAnimationEnd(animation);                if (animInterface!=null){                    animInterface.animEnd();                }            }        });        valueAnimator.start();    }    public interface AnimInterface{        void animEnd();    }}

ViewUtils

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

style.xml
这里我只设置了进入的背景渐变的动画,列表的滑动动画我在AnimationUtil中实现了,在上面的AnimationUtil中也可以实现进入动画,这样也更统一,看个人喜好。

  <style name="SelectPopupWindow">        <item name="android:windowEnterAnimation">@anim/p_in</item>    </style>

p_in.xml

<?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android">    <alpha        android:duration="500"        android:fromAlpha="0"        android:toAlpha="1"/></set>

布局部分就是简单的gridview,布局可以有多种方式来实现。可以直接用View标签来实现阴影效果。

<?xml version="1.0" encoding="utf-8"?><RelativeLayout    xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:orientation="vertical"    android:background="#88000000"    android:layout_height="match_parent">    <GridView        android:id="@+id/gridView"        android:scrollbars="none"        android:numColumns="3"        android:background="@color/white"        android:layout_width="match_parent"        android:layout_height="wrap_content"/></RelativeLayout>

执行:

JoinTypeSelectWindow joinTypeSelectWindow = new JoinTypeSelectWindow(getActivity());                joinTypeSelectWindow.showPopupWindow(targetView);

————— 完 ——————

一个小小的源码链接

原创粉丝点击