Android實現(xiàn)微博菜單彈出效果
先上Android仿微博菜單彈出效果圖,這個截圖不是很流暢,大家可以下載apk試一下。

說一下實現(xiàn)思路:
1、截取當前窗口,對圖片做高斯模糊處理,將處理后的圖片做popupwindow的背景圖片;
2、創(chuàng)建popupwindow,完成布局,這兒要注意:View的移動范圍是由parent的大小決定的,就是只能在parent的范圍內(nèi)移動;
3、給買個View添加進入動畫,每個比前一個延期50ms播放動畫,關(guān)閉窗口時相反;
4、為View的動畫添加回彈插值器;
MoreWindow.java窗口
package com.jerome.weibo;
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.os.Handler;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.AnimationSet;
import android.view.animation.TranslateAnimation;
import android.widget.ImageView;
import android.widget.PopupWindow;
import android.widget.RelativeLayout;
import android.widget.RelativeLayout.LayoutParams;
public class MoreWindow extends PopupWindow implements OnClickListener{
private String TAG = MoreWindow.class.getSimpleName();
Activity mContext;
private int mWidth;
private int mHeight;
private int statusBarHeight ;
private Bitmap mBitmap= null;
private Bitmap overlay = null;
private Handler mHandler = new Handler();
public MoreWindow(Activity context) {
mContext = context;
}
public void init() {
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);
}
private Bitmap blur() {
if (null != overlay) {
return overlay;
}
long startMs = System.currentTimeMillis();
View view = mContext.getWindow().getDecorView();
view.setDrawingCacheEnabled(true);
view.buildDrawingCache(true);
mBitmap = view.getDrawingCache();
float scaleFactor = 8;//圖片縮放比例;
float radius = 10;//模糊程度
int width = mBitmap.getWidth();
int height = mBitmap.getHeight();
overlay = Bitmap.createBitmap((int) (width / scaleFactor),(int) (height / scaleFactor),Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(overlay);
canvas.scale(1 / scaleFactor, 1 / scaleFactor);
Paint paint = new Paint();
paint.setFlags(Paint.FILTER_BITMAP_FLAG);
canvas.drawBitmap(mBitmap, 0, 0, paint);
overlay = FastBlur.doBlur(overlay, (int) radius, true);
Log.i(TAG, "blur time is:"+(System.currentTimeMillis() - startMs));
return overlay;
}
private Animation showAnimation1(final View view,int fromY ,int toY) {
AnimationSet set = new AnimationSet(true);
TranslateAnimation go = new TranslateAnimation(0, 0, fromY, toY);
go.setDuration(300);
TranslateAnimation go1 = new TranslateAnimation(0, 0, -10, 2);
go1.setDuration(100);
go1.setStartOffset(250);
set.addAnimation(go1);
set.addAnimation(go);
set.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationEnd(Animation animation) {
}
@Override
public void onAnimationRepeat(Animation animation) {
}
@Override
public void onAnimationStart(Animation animation) {
}
});
return set;
}
public void showMoreWindow(View anchor,int bottomMargin) {
final RelativeLayout layout = (RelativeLayout)LayoutInflater.from(mContext).inflate(R.layout.center_music_more_window, null);
setContentView(layout);
ImageView close= (ImageView)layout.findViewById(R.id.center_music_window_close);
android.widget.RelativeLayout.LayoutParams params =new android.widget.RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
params.bottomMargin = bottomMargin;
params.addRule(RelativeLayout.BELOW, R.id.more_window_auto);
params.addRule(RelativeLayout.RIGHT_OF, R.id.more_window_collect);
params.topMargin = 200;
params.leftMargin = 18;
close.setLayoutParams(params);
close.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (isShowing()) {
closeAnimation(layout);
}
}
});
showAnimation(layout);
setBackgroundDrawable(new BitmapDrawable(mContext.getResources(), blur()));
setOutsideTouchable(true);
setFocusable(true);
showAtLocation(anchor, Gravity.BOTTOM, 0, statusBarHeight);
}
private void showAnimation(ViewGroup layout){
for(int i=0;i<layout.getChildCount();i++){
final View child = layout.getChildAt(i);
if(child.getId() == R.id.center_music_window_close){
continue;
}
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(300);
KickBackAnimator kickAnimator = new KickBackAnimator();
kickAnimator.setDuration(150);
fadeAnim.setEvaluator(kickAnimator);
fadeAnim.start();
}
}, i * 50);
}
}
private void closeAnimation(ViewGroup layout){
for(int i=0;i<layout.getChildCount();i++){
final View child = layout.getChildAt(i);
if(child.getId() == R.id.center_music_window_close){
continue;
}
child.setOnClickListener(this);
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
child.setVisibility(View.VISIBLE);
ValueAnimator fadeAnim = ObjectAnimator.ofFloat(child, "translationY", 0, 600);
fadeAnim.setDuration(200);
KickBackAnimator kickAnimator = new KickBackAnimator();
kickAnimator.setDuration(100);
fadeAnim.setEvaluator(kickAnimator);
fadeAnim.start();
fadeAnim.addListener(new AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationRepeat(Animator animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationEnd(Animator animation) {
child.setVisibility(View.INVISIBLE);
}
@Override
public void onAnimationCancel(Animator animation) {
// TODO Auto-generated method stub
}
});
}
}, (layout.getChildCount()-i-1) * 30);
if(child.getId() == R.id.more_window_local){
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
dismiss();
}
}, (layout.getChildCount()-i) * 30 + 80);
}
}
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.more_window_local:
break;
case R.id.more_window_online:
break;
case R.id.more_window_delete:
break;
case R.id.more_window_collect:
break;
case R.id.more_window_auto:
break;
case R.id.more_window_external:
break;
default:
break;
}
}
public void destroy() {
if (null != overlay) {
overlay.recycle();
overlay = null;
System.gc();
}
if (null != mBitmap) {
mBitmap.recycle();
mBitmap = null;
System.gc();
}
}
}
KickBackAnimator.Java回彈效果:
package com.jerome.weibo;
import android.animation.TypeEvaluator;
public class KickBackAnimator implements TypeEvaluator<Float> {
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;
}
}
代碼見github: https://github.com/gqdy365/WeiboPopupWindow
請大家star一下,我后面會持續(xù)更新;
下面是apk下載地址:WeiboPopupWindow
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
- Android 側(cè)滑抽屜菜單的實現(xiàn)代碼
- Android實現(xiàn)動畫效果的自定義下拉菜單功能
- Android實現(xiàn)上下菜單雙向滑動
- Android如何實現(xiàn)底部菜單固定到底部
- Android實現(xiàn)微信加號菜單模式
- Android實現(xiàn)衛(wèi)星菜單效果
- Android自定義轉(zhuǎn)盤菜單效果
- Android底部菜單欄(RadioGroup+Fragment)美化
- Android recyclerView橫條指示器實現(xiàn)淘寶菜單模塊
- android studio 的下拉菜單Spinner使用詳解
- Android仿新浪微博發(fā)送菜單界面的實現(xiàn)
相關(guān)文章
android用java和c實現(xiàn)查找sd卡掛載路徑(sd卡路徑)的方法
這篇文章主要介紹了android用java和c實現(xiàn)查找sd卡掛載路徑(sd卡路徑)的方法,需要的朋友可以參考下2014-02-02
Android使用Notification實現(xiàn)通知功能
這篇文章主要為大家詳細介紹了Android使用Notification實現(xiàn)通知功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-11-11
Android Compose Column列表不自動刷新問題
這篇文章主要介紹了Android Compose Column列表數(shù)據(jù)更新列表不刷新的問題,總的來說這并不是一道難題,那為什么要拿出這道題介紹?拿出這道題真正想要傳達的是解題的思路,以及不斷優(yōu)化探尋最優(yōu)解的過程。希望通過這道題能給你帶來一種解題優(yōu)化的思路2023-01-01
Android 進階實現(xiàn)性能優(yōu)化之OOM與Leakcanary詳解原理
LeakCanary 是大名鼎鼎的 square 公司開源的內(nèi)存泄漏檢測工具。目前上大部分App在開發(fā)測試階段都會接入此工具用于檢測潛在的內(nèi)存泄漏問題,做的好一點的可能會搭建一個服務器用于保存各個設備上的內(nèi)存泄漏問題再集中處理2021-11-11
關(guān)于OkHttp中response.body().string()的用法解析
這篇文章主要介紹了關(guān)于OkHttp中response.body().string()的用法解析,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-06-06
Android intent之間復雜參數(shù)傳遞方法詳解
這篇文章主要介紹了Android intent之間復雜參數(shù)傳遞方法,較為詳細的分析了Android中intent參數(shù)傳遞的常見方法與使用技巧,需要的朋友可以參考下2016-10-10

