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

先上图:

Android PopupWindow实现带背景阴影的下滑选择框_第1张图片

效果还是很丝滑的,这里动画主要用到了属性动画。实现逻辑很简单,动画都是在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(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 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
    style>

p_in.xml


<set xmlns:android="http://schemas.android.com/apk/res/android">
    <alpha
        android:duration="500"
        android:fromAlpha="0"
        android:toAlpha="1"/>
set>

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


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

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

一个小小的源码链接

你可能感兴趣的:(技术篇)