首先看效果图
当然了这个高度和宽度是可控的。想详细修改的话去代码里面修改吧.
使用方法
BouncingMenu.makeMenu(findViewById(R.id.rl), R.layout.layout_rv_sweet, adapter).show();
是的,你没看错,就是这么简单。
只需要传入view,布局id,以及adapter(这里使用的是recycleview.Adapter)。想修改其他的话直接去修改代码吧。
具体实现
首先是activity的布局,很简单,就是放了各种ImageView,然后上面放了个searchView。
这里就不写详细布局了
弹出视图
这里把视图分成2部分了。
-
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(); } }
-
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(); } }
具体需求自己可以设置进入改
转载自原文链接, 如需删除请联系管理员。
原文链接:仿地图弹窗,转载请注明来源!