首页 » 技术分享 » 仿地图弹窗

仿地图弹窗

 

首先看效果图

当然了这个高度和宽度是可控的。想详细修改的话去代码里面修改吧.

使用方法

    BouncingMenu.makeMenu(findViewById(R.id.rl), R.layout.layout_rv_sweet, adapter).show();

是的,你没看错,就是这么简单。
只需要传入view,布局id,以及adapter(这里使用的是recycleview.Adapter)。想修改其他的话直接去修改代码吧。

具体实现

首先是activity的布局,很简单,就是放了各种ImageView,然后上面放了个searchView。
这里就不写详细布局了
弹出视图

这里把视图分成2部分了。

  1. RecycleView部分。使用的是LayoutAnimation。从下往上

    布局:

    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/transparent"
        android:orientation="vertical">
    
        <RelativeLayout
            android:id="@+id/freeGrowUpParent"
            android:layout_width="match_parent"
            android:layout_height="@dimen/sheet_height"
            android:layout_gravity="bottom"
            android:background="@android:color/transparent">
            <!--自定义控件,就是那个波动view-->
            <com.xie.designpatterns.widget.BouncingView
                android:id="@+id/sv"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="10dp"
                android:layout_marginRight="10dp" />
    
            <android.support.v7.widget.RecyclerView
                android:id="@+id/rv"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_gravity="bottom"
                android:layout_marginLeft="10dp"
                android:layout_marginRight="10dp"
                android:layout_marginTop="30dp"
                android:clipChildren="false"
                android:overScrollMode="never" />
    
        </RelativeLayout>
    </FrameLayout>
    

    BouncingMenu:

    public class BouncingMenu {
    
        private final ViewGroup mParentViewGroup;
        private View rootView;
        private final BouncingView boucingView;
        private final RecyclerView recycleView;
        private RecyclerView.Adapter adapter;
        private int screenWidht;
        private int screenHeight;
    
        /**
         * @param resId   布局资源id
         * @param adapter
         */
        public BouncingMenu(View view, int resId, RecyclerView.Adapter adapter) {
            this.adapter = adapter;
            //不断地往上追溯找到 系统id为content的帧布局,添加进去.这里就是利用了这个。
            // @android:id/content 就是锚点view
            mParentViewGroup = findRootParent(view);
            //渲染
            rootView = LayoutInflater.from(view.getContext()).inflate(resId, null, false);
            //拿到高度,然后把rootview的高度设置为0
            Logger.i("视图的跟布局是" + rootView);
            boucingView = (BouncingView) rootView.findViewById(R.id.sv);
            boucingView.setAnimationListener(new MyAnimationListener());
            recycleView = (RecyclerView) rootView.findViewById(R.id.rv);
            recycleView.setAnimation(AnimationUtils.loadAnimation(view.getContext(), R.anim.rv_layout_animation));
            recycleView.setLayoutManager(new LinearLayoutManager(view.getContext()));
    
            getScreentWight(view.getContext());
        }
    
        private ViewGroup findRootParent(View view) {
            do {
                //判断是帧布局
                if (view instanceof FrameLayout) {
                    if (view.getId() == android.R.id.content) {
                        //判断布局id为content
                        return (ViewGroup) view;
                    }
                }
                //没找到 ,就不断的往上找
                if (view != null) {
                    ViewParent parent = view.getParent();
                    //如果父布局是view的话往上继续找
                    view = parent instanceof View ? (View) parent : null;
                }
            } while (view != null);
            return null;
        }
    
        public static BouncingMenu makeMenu(View view, int resId, RecyclerView.Adapter adapter) {
    
            return new BouncingMenu(view, resId, adapter);
        }
    
        /**
         * 显示
         *
         * @return
         */
        @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
        public BouncingMenu show() {
            //显示,往帧布局里面addView(xxxView)
            if (rootView.getParent() != null) {
                //防止已经show了再次show
                mParentViewGroup.removeView(rootView);
            }
            FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
            rootView.setLayoutParams(params);
            mParentViewGroup.addView(rootView);
            boucingView.show();
            return this;
        }
    
        /**
         * 关闭
         */
        public void dissmiss() {
            //属性动画实现消失
            ObjectAnimator animator = ObjectAnimator.ofFloat(rootView, "translationY", 0, rootView.getHeight());
            animator.setDuration(1000);
            animator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    //动画结束
                    super.onAnimationEnd(animation);
                    mParentViewGroup.removeView(rootView);
                    rootView = null;
                }
            });
            animator.start();
        }
    
        private class MyAnimationListener implements BouncingView.AnimationListener {
            @Override
            public void onShowContent() {
                recycleView.setVisibility(View.VISIBLE);
                recycleView.setAdapter(adapter);
                recycleView.scheduleLayoutAnimation();
            }
        }
    
        private void getScreentWight(Context context) {
            WindowManager wm = (WindowManager) context
                    .getSystemService(Context.WINDOW_SERVICE);
    
            screenWidht = wm.getDefaultDisplay().getWidth();
            screenHeight = wm.getDefaultDisplay().getHeight();
        }
    }
    
  2. BouncingView(弹动部分)

    public class BouncingView extends View {
        private Paint mPaint;
        private int mArcHeight;//当前弧度
        private int mMaxArcHeight;//最高弧度
        private Status mStatus = Status.NONE;
        private Path mPath = new Path();
        private AnimationListener animationListener;
    
        private enum Status {
            NONE,
            STATUS_SMOOTH_UP,
            STATUS_DOWN
        }
    
        public BouncingView(Context context) {
            super(context);
            init();
        }
    
        public BouncingView(Context context, AttributeSet attrs) {
            super(context, attrs);
            init();
        }
    
    
        private void init() {
            mPaint = new Paint();
            mPaint.setAntiAlias(true);
            mPaint.setStyle(Paint.Style.FILL);
            mPaint.setColor(getResources().getColor(android.R.color.white));
            mMaxArcHeight = getResources().getDimensionPixelSize(R.dimen.arc_max_height);
        }
    
    
        //绘制贝塞尔曲线
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
    
            int currentPointY = 0;
            //判断当前状态
            switch (mStatus) {
                case NONE:
                    currentPointY = 0;
                    break;
                case STATUS_SMOOTH_UP://往上走
                    //currentPointY 的值 跟mArcHeight变化率是一样的
                    //getHeight()~0  (自定义控件最上面是0)           跟mArcHeight:0~mMaxArcHeight
                    currentPointY = (int) (getHeight() * (1 - (float) mArcHeight / mMaxArcHeight) + mMaxArcHeight);
                    break;
                case STATUS_DOWN://往下走
                    currentPointY = mMaxArcHeight;
                    break;
    
            }
            mPath.reset();
            //先落笔到左上角
            mPath.moveTo(0, currentPointY);
            //画上面的线二阶贝塞尔曲线  ,需要起始点 终点,跟拐点。起点就是(0,currentPotintY),拐点就是最中间(getWidth()/2,)
            mPath.quadTo(getWidth() / 2, currentPointY - mArcHeight, getWidth(), currentPointY);
            //右边线
            mPath.lineTo(getWidth(), getHeight());
            //最下面的直线
            mPath.lineTo(0, getHeight());
            //自动画最后一条线
            mPath.close();
            canvas.drawPath(mPath, mPaint);
        }
    
        public void show() {
    
            if (animationListener != null) {
                this.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        //延迟显示数据
                        animationListener.onShowContent();
                    }
                }, 600);
            }
    
            //不短的控制mArcHeight的高度
            mStatus = Status.STATUS_SMOOTH_UP;
            ValueAnimator valueAnimator = ValueAnimator.ofInt(0, mMaxArcHeight);
            valueAnimator.setDuration(800);
            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    mArcHeight = (int) animation.getAnimatedValue();
                    if (mArcHeight == mMaxArcHeight) {
                        //出现谈一下动画
                        bounce();
                    }
                    //不断的刷新调用ondraw方法
                    invalidate();
                }
    
    
            });
            valueAnimator.start();
        }
    
        /**
         * 回弹动画
         */
        private void bounce() {
            mStatus = Status.STATUS_DOWN;
            ValueAnimator valueAnimator = ValueAnimator.ofInt(mMaxArcHeight, 0);
            valueAnimator.setDuration(800);
            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    mArcHeight = (int) animation.getAnimatedValue();
                    //不断的刷新调用ondraw方法
                    invalidate();
                }
    
    
            });
            valueAnimator.start();
        }
    
        public void setAnimationListener(AnimationListener listener) {
            this.animationListener = listener;
        }
    
        public interface AnimationListener {
            void onShowContent();
        }
    
    }
    

具体需求自己可以设置进入改

转载自原文链接, 如需删除请联系管理员。

原文链接:仿地图弹窗,转载请注明来源!

0