先上效果图
并没有像酷安那样扩展到导航栏,以后有机会可以再研究吧。
使用的PopupWindow实现的,主要部分有
背景揭露动画;+ 旋转动画;菜单项弹出动画;背景模糊效果(点击进入该效果github项目)。
参考项目https://blog.csdn.net/SilenceOO/article/details/78976477
先看pop的布局文件
java代码实现
public class MoreWindow extends PopupWindow implements OnClickListener {
private Activity mContext;
private RelativeLayout layout;
private ImageView close;
private View bgView;
private BlurringView blurringView;
private int mWidth;
private int mHeight;
private int statusBarHeight;
private Handler mHandler = new Handler();
public MoreWindow(Activity context) {
mContext = context;
}
/**
* 初始化
* @param view 要显示的模糊背景View,一般选择跟布局layout
*/
public void init(View view) {
Rect frame = new Rect();
mContext.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
statusBarHeight = frame.top;
DisplayMetrics metrics = new DisplayMetrics();
mContext.getWindowManager().getDefaultDisplay()
.getMetrics(metrics);
mWidth = metrics.widthPixels;
mHeight = metrics.heightPixels;
setWidth(mWidth);
setHeight(mHeight);
layout = (RelativeLayout) LayoutInflater.from(mContext).inflate(R.layout.center_music_more_window, null);
setContentView(layout);
close = (ImageView) layout.findViewById(R.id.iv_close);
close.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (isShowing()) {
closeAnimation();
}
}
});
blurringView = (BlurringView) layout.findViewById(R.id.blurring_view);
blurringView.blurredView(view);//模糊背景
bgView = layout.findViewById(R.id.rel);
setOutsideTouchable(true);
setFocusable(true);
setClippingEnabled(false);//使popupwindow全屏显示
}
public int getNavigationBarHeight(Activity activity) {
Resources resources = activity.getResources();
int resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android");
//获取NavigationBar的高度
int height = resources.getDimensionPixelSize(resourceId);
return height;
}
/**
* 显示window动画
* @param anchor
*/
public void showMoreWindow(View anchor) {
showAtLocation(anchor, Gravity.TOP | Gravity.START, 0, 0);
mHandler.post(new Runnable() {
@Override
public void run() {
try {
//圆形扩展的动画
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
int x = mWidth / 2;
int y = (int) (mHeight - DensityUtils.fromDpToPx(25));
Animator animator = ViewAnimationUtils.createCircularReveal(bgView, x,
y, 0, bgView.getHeight());
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
// bgView.setVisibility(View.VISIBLE);
}
@Override
public void onAnimationEnd(Animator animation) {
// layout.setVisibility(View.VISIBLE);
}
});
animator.setDuration(300);
animator.start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
showAnimation(layout);
}
private void showAnimation(ViewGroup layout) {
try {
LinearLayout linearLayout = layout.findViewById(R.id.lin);
mHandler.post(new Runnable() {
@Override
public void run() {
//+ 旋转动画
close.animate().rotation(90).setDuration(400);
}
});
//菜单项弹出动画
for (int i = 0; i < linearLayout.getChildCount(); i++) {
final View child = linearLayout.getChildAt(i);
child.setOnClickListener(this);
child.setVisibility(View.INVISIBLE);
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
child.setVisibility(View.VISIBLE);
ValueAnimator fadeAnim = ObjectAnimator.ofFloat(child, "translationY", 600, 0);
fadeAnim.setDuration(200);
KickBackAnimator kickAnimator = new KickBackAnimator();
kickAnimator.setDuration(150);
fadeAnim.setEvaluator(kickAnimator);
fadeAnim.start();
}
}, i * 50 + 100);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 关闭window动画
*/
private void closeAnimation() {
mHandler.post(new Runnable() {
@Override
public void run() {
close.animate().rotation(-90).setDuration(400);
}
});
try {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
int x = mWidth / 2;
int y = (int) (mHeight - DensityUtils.fromDpToPx(25));
Animator animator = ViewAnimationUtils.createCircularReveal(bgView, x,
y, bgView.getHeight(), 0);
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
// layout.setVisibility(View.GONE);
}
@Override
public void onAnimationEnd(Animator animation) {
// bgView.setVisibility(View.GONE);
dismiss();
}
});
animator.setDuration(300);
animator.start();
}
} catch (Exception e) {
}
}
/**
* 点击事件处理
* @param v
*/
@Override
public void onClick(View v) {
if (isShowing()) {
closeAnimation();
}
switch (v.getId()) {
case R.id.tv_sbs:
break;
case R.id.tv_search:
break;
case R.id.tv_course:
break;
case R.id.tv_task:
break;
}
}
}
还有一个菜单项回弹的插值器
import android.animation.TypeEvaluator;
public class KickBackAnimator implements TypeEvaluator {
private final float s = 1.70158f;
float mDuration = 0f;
public void setDuration(float duration) {
mDuration = duration;
}
public Float evaluate(float fraction, Float startValue, Float endValue) {
float t = mDuration * fraction;
float b = startValue.floatValue();
float c = endValue.floatValue() - startValue.floatValue();
float d = mDuration;
float result = calculate(t, b, c, d);
return result;
}
public Float calculate(float t, float b, float c, float d) {
return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
}
}
使用:
初始化
mMoreWindow = new MoreWindow(this);
mMoreWindow.init(idContainer);
点击+按钮时弹出
private void showMoreWindow() {
if (null == mMoreWindow) {
mMoreWindow = new MoreWindow(this);
mMoreWindow.init(idContainer);
}
mMoreWindow.showMoreWindow(idContainer );
}
其中的idContainer为当前Activity的跟布局layout。
GitHub 传送门