Android實(shí)現(xiàn)微博菜單彈出效果
先上Android仿微博菜單彈出效果圖,這個(gè)截圖不是很流暢,大家可以下載apk試一下。
說一下實(shí)現(xiàn)思路:
1、截取當(dāng)前窗口,對(duì)圖片做高斯模糊處理,將處理后的圖片做popupwindow的背景圖片;
2、創(chuàng)建popupwindow,完成布局,這兒要注意:View的移動(dòng)范圍是由parent的大小決定的,就是只能在parent的范圍內(nèi)移動(dòng);
3、給買個(gè)View添加進(jìn)入動(dòng)畫,每個(gè)比前一個(gè)延期50ms播放動(dòng)畫,關(guān)閉窗口時(shí)相反;
4、為View的動(dòng)畫添加回彈插值器;
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
請(qǐng)大家star一下,我后面會(huì)持續(xù)更新;
下面是apk下載地址:WeiboPopupWindow
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android 側(cè)滑抽屜菜單的實(shí)現(xiàn)代碼
- Android實(shí)現(xiàn)動(dòng)畫效果的自定義下拉菜單功能
- Android實(shí)現(xiàn)上下菜單雙向滑動(dòng)
- Android如何實(shí)現(xiàn)底部菜單固定到底部
- Android實(shí)現(xiàn)微信加號(hào)菜單模式
- Android實(shí)現(xiàn)衛(wèi)星菜單效果
- Android自定義轉(zhuǎn)盤菜單效果
- Android底部菜單欄(RadioGroup+Fragment)美化
- Android recyclerView橫條指示器實(shí)現(xiàn)淘寶菜單模塊
- android studio 的下拉菜單Spinner使用詳解
- Android仿新浪微博發(fā)送菜單界面的實(shí)現(xiàn)
相關(guān)文章
android用java和c實(shí)現(xiàn)查找sd卡掛載路徑(sd卡路徑)的方法
這篇文章主要介紹了android用java和c實(shí)現(xiàn)查找sd卡掛載路徑(sd卡路徑)的方法,需要的朋友可以參考下2014-02-02Android編程實(shí)現(xiàn)自定義進(jìn)度條顏色的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)自定義進(jìn)度條顏色的方法,涉及Android進(jìn)度條的樣式布局及功能實(shí)現(xiàn)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-11-11Android使用Notification實(shí)現(xiàn)通知功能
這篇文章主要為大家詳細(xì)介紹了Android使用Notification實(shí)現(xiàn)通知功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-11-11Android Compose Column列表不自動(dòng)刷新問題
這篇文章主要介紹了Android Compose Column列表數(shù)據(jù)更新列表不刷新的問題,總的來說這并不是一道難題,那為什么要拿出這道題介紹?拿出這道題真正想要傳達(dá)的是解題的思路,以及不斷優(yōu)化探尋最優(yōu)解的過程。希望通過這道題能給你帶來一種解題優(yōu)化的思路2023-01-01Android 進(jìn)階實(shí)現(xiàn)性能優(yōu)化之OOM與Leakcanary詳解原理
LeakCanary 是大名鼎鼎的 square 公司開源的內(nèi)存泄漏檢測工具。目前上大部分App在開發(fā)測試階段都會(huì)接入此工具用于檢測潛在的內(nèi)存泄漏問題,做的好一點(diǎn)的可能會(huì)搭建一個(gè)服務(wù)器用于保存各個(gè)設(shè)備上的內(nèi)存泄漏問題再集中處理2021-11-11關(guān)于OkHttp中response.body().string()的用法解析
這篇文章主要介紹了關(guān)于OkHttp中response.body().string()的用法解析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06Android intent之間復(fù)雜參數(shù)傳遞方法詳解
這篇文章主要介紹了Android intent之間復(fù)雜參數(shù)傳遞方法,較為詳細(xì)的分析了Android中intent參數(shù)傳遞的常見方法與使用技巧,需要的朋友可以參考下2016-10-10Android自定義星星可滑動(dòng)評(píng)分控件
這篇文章主要介紹了Android自定義星星可滑動(dòng)評(píng)分控件,通過線性布局結(jié)合ImageView實(shí)現(xiàn)評(píng)分控件,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-03-03