編輯:Android開發實例
Android 側滑菜單的實現,參考網上的代碼,實現側滑菜單。最重要的是這個動畫類UgcAnimations,如何使用動畫類來側滑的封裝FlipperLayout。
1、實現效果
2、動畫類UgcAnimations
package com.mmsx.base; import android.content.Context; import android.view.View; import android.view.ViewGroup.MarginLayoutParams; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.view.animation.AnimationSet; import android.view.animation.AnticipateInterpolator; import android.view.animation.OvershootInterpolator; import android.view.animation.RotateAnimation; import android.view.animation.ScaleAnimation; import android.view.animation.TranslateAnimation; import android.widget.ImageView; import android.widget.RelativeLayout; /** * Path動畫類 * */ public class UgcAnimations { private static int xOffset = 15; private static int yOffset = -13; public static void initOffset(Context context) { xOffset = (int) (15 * context.getResources().getDisplayMetrics().density); yOffset = -(int) (13 * context.getResources().getDisplayMetrics().density); } public static Animation getRotateAnimation(float fromDegrees, float toDegrees, long durationMillis) { RotateAnimation rotate = new RotateAnimation(fromDegrees, toDegrees, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); rotate.setDuration(durationMillis); rotate.setFillAfter(true); return rotate; } public static Animation getAlphaAnimation(float fromAlpha, float toAlpha, long durationMillis) { AlphaAnimation alpha = new AlphaAnimation(fromAlpha, toAlpha); alpha.setDuration(durationMillis); alpha.setFillAfter(true); return alpha; } public static Animation getScaleAnimation(long durationMillis) { ScaleAnimation scale = new ScaleAnimation(1.0f, 1.5f, 1.0f, 1.5f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); scale.setDuration(durationMillis); return scale; } public static Animation getTranslateAnimation(float fromXDelta, float toXDelta, float fromYDelta, float toYDelta, long durationMillis) { TranslateAnimation translate = new TranslateAnimation(fromXDelta, toXDelta, fromYDelta, toYDelta); translate.setDuration(durationMillis); translate.setFillAfter(true); return translate; } public static void startOpenAnimation(RelativeLayout relativeLayout, ImageView background, ImageView menu, long durationMillis) { background.setVisibility(View.VISIBLE); relativeLayout.setVisibility(View.VISIBLE); background.startAnimation(getAlphaAnimation(0f, 1f, durationMillis)); menu.startAnimation(getRotateAnimation(0, 90, durationMillis)); for (int i = 0; i < relativeLayout.getChildCount(); i++) { ImageView imageView = (ImageView) relativeLayout.getChildAt(i); imageView.setVisibility(View.VISIBLE); MarginLayoutParams params = (MarginLayoutParams) imageView .getLayoutParams(); AnimationSet set = new AnimationSet(true); set.addAnimation(getRotateAnimation(-270, 0, durationMillis)); set.addAnimation(getAlphaAnimation(0.5f, 1.0f, durationMillis)); set.addAnimation(getTranslateAnimation( -params.leftMargin + xOffset, 0f, params.bottomMargin + yOffset, 0f, durationMillis)); set.setFillAfter(true); set.setDuration(durationMillis); set.setStartOffset((i * 100) / (-1 + relativeLayout.getChildCount())); set.setInterpolator(new OvershootInterpolator(1f)); imageView.startAnimation(set); } } public static void startCloseAnimation(final RelativeLayout relativeLayout, final ImageView background, ImageView menu, long durationMillis) { background.startAnimation(getAlphaAnimation(1f, 0f, durationMillis)); menu.startAnimation(getRotateAnimation(90, 0, durationMillis)); for (int i = 0; i < relativeLayout.getChildCount(); i++) { final ImageView imageView = (ImageView) relativeLayout .getChildAt(i); MarginLayoutParams params = (MarginLayoutParams) imageView .getLayoutParams(); AnimationSet set = new AnimationSet(true); set.addAnimation(getRotateAnimation(0, -270, durationMillis)); set.addAnimation(getAlphaAnimation(1.0f, 0.5f, durationMillis)); set.addAnimation(getTranslateAnimation(0f, -params.leftMargin + xOffset, 0f, params.bottomMargin + yOffset, durationMillis)); set.setFillAfter(true); set.setDuration(durationMillis); set.setStartOffset(((relativeLayout.getChildCount() - i) * 100) / (-1 + relativeLayout.getChildCount())); set.setInterpolator(new AnticipateInterpolator(1f)); set.setAnimationListener(new Animation.AnimationListener() { public void onAnimationStart(Animation arg0) { } public void onAnimationRepeat(Animation arg0) { } public void onAnimationEnd(Animation arg0) { relativeLayout.setVisibility(View.GONE); background.setVisibility(View.GONE); } }); imageView.startAnimation(set); } } public static Animation clickAnimation(long durationMillis) { AnimationSet set = new AnimationSet(true); set.addAnimation(getAlphaAnimation(1.0f, 0.3f, durationMillis)); set.addAnimation(getScaleAnimation(durationMillis)); set.setDuration(durationMillis); return set; } }
3、封裝使用動畫類FlipperLayout
package com.mmsx.base; import android.content.Context; import android.util.AttributeSet; import android.util.TypedValue; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; import android.widget.Scroller; /** * 自己重寫的ViewGroup,用與滑動切換界面使用,代碼不詳解,慢點看的話應該能看懂的... */ public class FlipperLayout extends ViewGroup { private Scroller mScroller; private VelocityTracker mVelocityTracker; private int mWidth; public static final int SCREEN_STATE_CLOSE = 0; public static final int SCREEN_STATE_OPEN = 1; public static final int TOUCH_STATE_RESTART = 0; public static final int TOUCH_STATE_SCROLLING = 1; public static final int SCROLL_STATE_NO_ALLOW = 0; public static final int SCROLL_STATE_ALLOW = 1; private int mScreenState = 0; private int mTouchState = 0; private int mScrollState = 0; private int mVelocityValue = 0; private boolean mOnClick = false; private onUgcDismissListener mOnUgcDismissListener; private onUgcShowListener mOnUgcShowListener; public FlipperLayout(Context context) { super(context); mScroller = new Scroller(context); mWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 54, getResources().getDisplayMetrics()); } public FlipperLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public FlipperLayout(Context context, AttributeSet attrs) { super(context, attrs); } protected void onLayout(boolean changed, int l, int t, int r, int b) { for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); int height = child.getMeasuredHeight(); int width = child.getMeasuredWidth(); child.layout(0, 0, width, height); } } protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); setMeasuredDimension(width, height); for (int i = 0; i < getChildCount(); i++) { getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec); } } public boolean dispatchTouchEvent(MotionEvent ev) { obtainVelocityTracker(ev); switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: mTouchState = mScroller.isFinished() ? TOUCH_STATE_RESTART : TOUCH_STATE_SCROLLING; if (mTouchState == TOUCH_STATE_RESTART) { int x = (int) ev.getX(); int screenWidth = getWidth(); if (x <= mWidth && mScreenState == SCREEN_STATE_CLOSE && mTouchState == TOUCH_STATE_RESTART || x >= screenWidth - mWidth && mScreenState == SCREEN_STATE_OPEN && mTouchState == TOUCH_STATE_RESTART) { if (mScreenState == SCREEN_STATE_OPEN) { mOnClick = true; } mScrollState = SCROLL_STATE_ALLOW; } else { mOnClick = false; mScrollState = SCROLL_STATE_NO_ALLOW; } } else { return false; } break; case MotionEvent.ACTION_MOVE: mVelocityTracker.computeCurrentVelocity(1000, ViewConfiguration.getMaximumFlingVelocity()); if (mScrollState == SCROLL_STATE_ALLOW && getWidth() - (int) ev.getX() < mWidth) { return true; } break; case MotionEvent.ACTION_UP: releaseVelocityTracker(); if (mOnClick) { mOnClick = false; mScreenState = SCREEN_STATE_CLOSE; mScroller.startScroll(getChildAt(1).getScrollX(), 0, -getChildAt(1).getScrollX(), 0, 800); invalidate(); } break; } return super.dispatchTouchEvent(ev); } public boolean onInterceptTouchEvent(MotionEvent ev) { obtainVelocityTracker(ev); switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: mTouchState = mScroller.isFinished() ? TOUCH_STATE_RESTART : TOUCH_STATE_SCROLLING; if (mTouchState == TOUCH_STATE_SCROLLING) { return false; } break; case MotionEvent.ACTION_MOVE: mOnClick = false; mVelocityTracker.computeCurrentVelocity(1000, ViewConfiguration.getMaximumFlingVelocity()); if (mScrollState == SCROLL_STATE_ALLOW && Math.abs(mVelocityTracker.getXVelocity()) > 200) { return true; } break; case MotionEvent.ACTION_UP: releaseVelocityTracker(); if (mScrollState == SCROLL_STATE_ALLOW && mScreenState == SCREEN_STATE_OPEN) { return true; } break; } return super.onInterceptTouchEvent(ev); } public boolean onTouchEvent(MotionEvent event) { obtainVelocityTracker(event); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mTouchState = mScroller.isFinished() ? TOUCH_STATE_RESTART : TOUCH_STATE_SCROLLING; if (mTouchState == TOUCH_STATE_SCROLLING) { return false; } break; case MotionEvent.ACTION_MOVE: mVelocityTracker.computeCurrentVelocity(1000, ViewConfiguration.getMaximumFlingVelocity()); mVelocityValue = (int) mVelocityTracker.getXVelocity(); getChildAt(1).scrollTo(-(int) event.getX(), 0); break; case MotionEvent.ACTION_UP: if (mScrollState == SCROLL_STATE_ALLOW) { if (mVelocityValue > 2000) { mScreenState = SCREEN_STATE_OPEN; mScroller .startScroll( getChildAt(1).getScrollX(), 0, -(getWidth() - Math.abs(getChildAt(1) .getScrollX()) - mWidth), 0, 250); invalidate(); } else if (mVelocityValue < -2000) { mScreenState = SCREEN_STATE_CLOSE; mScroller.startScroll(getChildAt(1).getScrollX(), 0, -getChildAt(1).getScrollX(), 0, 250); invalidate(); } else if (event.getX() < getWidth() / 2) { mScreenState = SCREEN_STATE_CLOSE; mScroller.startScroll(getChildAt(1).getScrollX(), 0, -getChildAt(1).getScrollX(), 0, 800); invalidate(); } else { mScreenState = SCREEN_STATE_OPEN; mScroller .startScroll( getChildAt(1).getScrollX(), 0, -(getWidth() - Math.abs(getChildAt(1) .getScrollX()) - mWidth), 0, 800); invalidate(); } } break; } return super.onTouchEvent(event); } public void open() { mTouchState = mScroller.isFinished() ? TOUCH_STATE_RESTART : TOUCH_STATE_SCROLLING; if (mTouchState == TOUCH_STATE_RESTART) { mScreenState = SCREEN_STATE_OPEN; mScroller.startScroll(getChildAt(1).getScrollX(), 0, -(getWidth() - Math.abs(getChildAt(1).getScrollX()) - mWidth), 0, 800); invalidate(); } } //關閉當前的側滑菜單,用view打開點擊事件的頁面 public void close(View view) { mScreenState = SCREEN_STATE_CLOSE; mScroller.startScroll(getChildAt(1).getScrollX(), 0, -getChildAt(1) .getScrollX(), 0, 800); invalidate(); setContentView(view); } public void computeScroll() { super.computeScroll(); if (mScroller.computeScrollOffset()) { getChildAt(1).scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); postInvalidate(); } else { if (mScreenState == SCREEN_STATE_OPEN) { if (mOnUgcDismissListener != null) { mOnUgcDismissListener.dismiss(); } } else if (mScreenState == SCREEN_STATE_CLOSE) { if (mOnUgcShowListener != null) { mOnUgcShowListener.show(); } } } } private void obtainVelocityTracker(MotionEvent event) { if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain(); } mVelocityTracker.addMovement(event); } private void releaseVelocityTracker() { if (mVelocityTracker != null) { mVelocityTracker.recycle(); mVelocityTracker = null; } } public int getScreenState() { return mScreenState; } public void setContentView(View view) { removeViewAt(1); addView(view, 1, getLayoutParams()); } public interface OnOpenListener { public abstract void open(); } public interface OnCloseListener { public abstract void close(); } public interface onUgcDismissListener { public abstract void dismiss(); } public interface onUgcShowListener { public abstract void show(); } public void setOnUgcDismissListener( onUgcDismissListener onUgcDismissListener) { mOnUgcDismissListener = onUgcDismissListener; } public void setOnUgcShowListener(onUgcShowListener onUgcShowListener) { mOnUgcShowListener = onUgcShowListener; } }
4、主界面MainActivity
package com.mmsx.activity; import com.mmsx.activity.SideslipMenu.onChangeViewListener; import com.mmsx.activity.SideslipOther.onDataListener; import com.mmsx.base.FlipperLayout; import com.mmsx.base.FlipperLayout.OnOpenListener; import com.mmsx.base.ViewUtil; import android.os.Bundle; import android.app.Activity; import android.view.ViewGroup.LayoutParams; import android.widget.Toast; public class MainActivity extends Activity implements OnOpenListener{ //側滑主要控制類,設置跟布局 private FlipperLayout mRoot; //側滑的默認界面,主界面 private SideslipHome mHome; //側滑的菜單,進行選擇的 private SideslipMenu mSideslipMenu; //其他菜單列表選擇的效果 private SideslipOther mOther; //退出時間間隔變量 private long mExitTime; //時間間隔2s private static final int INTERVAL = 2000; //側滑菜單選中的item private int mViewPosition; //側滑傳遞的標題 private String mstrTitle; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //創建容器,並設置全屏大小 mRoot = new FlipperLayout(this); //布局的參數 LayoutParams params = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); mRoot.setLayoutParams(params); //創建菜單界面和內容首頁界面,並添加到容器中,用於初始顯示 mHome = new SideslipHome(this, this); mSideslipMenu = new SideslipMenu(this); mRoot.addView(mSideslipMenu.getView(), params); mRoot.addView(mHome.getView(), params); //設置跟布局 setContentView(mRoot); //設置監聽 setListener(); } //設置監聽 private void setListener() { mHome.setOnOpenListener(this); //監聽菜單界面切換顯示內容(onChangeViewListener接口在SideslipMenu中定義) mSideslipMenu.setOnChangeViewListener(new onChangeViewListener() { public void onChangeView(int arg0) { mViewPosition = arg0; mOther = new SideslipOther(MainActivity.this); switch (arg0) { case ViewUtil.HOME: mRoot.close(mHome.getView()); break; case ViewUtil.MESSAGE: mstrTitle = "消息"; //設置數據接口監聽 mOther.setDataTitle(new DataTitle()); mRoot.close(mOther.getView()); break; case ViewUtil.FRIENDS: mstrTitle = "好友"; mOther.setDataTitle(new DataTitle()); mRoot.close(mOther.getView()); break; case ViewUtil.PHOTO: mstrTitle = "照片"; mOther.setDataTitle(new DataTitle()); mRoot.close(mOther.getView()); break; case ViewUtil.VIEWED: mstrTitle = "轉帖"; mOther.setDataTitle(new DataTitle()); mRoot.close(mOther.getView()); break; case ViewUtil.GIFTS: mstrTitle = "禮物"; mOther.setDataTitle(new DataTitle()); mRoot.close(mOther.getView()); break; case ViewUtil.RECOMMEND: mstrTitle = "游戲"; mOther.setDataTitle(new DataTitle()); mRoot.close(mOther.getView()); break; case ViewUtil.LBS: mstrTitle = "附近 "; mOther.setDataTitle(new DataTitle()); mRoot.close(mOther.getView()); break; default: break; } } }); } //傳遞數據到側滑選中的頁面 private class DataTitle implements onDataListener{ @Override public String getDataTitle() { return mstrTitle; } } @Override public void open() { if (mRoot.getScreenState() == FlipperLayout.SCREEN_STATE_CLOSE) { mRoot.open(); } } /** * 返回鍵監聽 */ public void onBackPressed() { /** * 如果界面的path菜單沒有關閉時,先將path菜單關閉,否則則判斷兩次返回時間間隔,小於兩秒則退出程序 */ if (mRoot.getScreenState() == FlipperLayout.SCREEN_STATE_OPEN) { if (mSideslipMenu.getUgcIsShowing()) { mSideslipMenu.closeUgc(); } else { exit(); } } else { switch (mViewPosition) { case ViewUtil.HOME: if (mHome.getUgcIsShowing()) { mHome.closeUgc(); } else { exit(); } break; default: exit(); break; } } } /** * 判斷兩次返回時間間隔,小於兩秒則退出程序 */ private void exit() { if (System.currentTimeMillis() - mExitTime > INTERVAL) { Toast.makeText(this, "再按一次返回鍵,可直接退出程序", Toast.LENGTH_SHORT).show(); mExitTime = System.currentTimeMillis(); } else { finish(); android.os.Process.killProcess(android.os.Process.myPid()); System.exit(0); } } }
5、SideslipHome
package com.mmsx.activity; import com.mmsx.base.FlipperLayout.OnOpenListener; import android.app.Activity; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.widget.TextView; public class SideslipHome { private Context mContext; private Activity mActivity; private View mHomeView; private boolean mUgcIsShowing = false; private OnOpenListener mOnOpenListener; public SideslipHome(Context context, Activity activity) { mContext = context; mActivity = activity; mHomeView = LayoutInflater.from(context).inflate(R.layout.sideslip_home, null); initUI(); } private void initUI() { TextView ivTitleName = (TextView)mHomeView.findViewById(R.id.ivTitleName); ivTitleName.setText("主頁動態"); } public void setOnOpenListener(OnOpenListener onOpenListener) { mOnOpenListener = onOpenListener; } public View getView() { return mHomeView; } /** * 獲取Path菜單顯示狀態 */ public boolean getUgcIsShowing() { return mUgcIsShowing; } /** * 關閉Path菜單 */ public void closeUgc() { mUgcIsShowing = false; } }
好了,以上就是本文的全部敘述,希望大家喜歡。
前文簡單介紹了Android中SurfaceView的基本使用,本文就來介紹一下SurfaceView與多線程的混搭。SurfaceView與多線程混搭,是為了防
Android應用程序可以在許多不同地區的許多設備上運行。為了使應用程序更具交互性,應用程序應該處理以適合應用程序將要使用的語言環境方面的文字,數字,文件等。在本章中,我
Android應用程序可以在許多不同地區的許多設備上運行。為了使應用程序更具交互性,應用程序應該處理以適合應用程序將要使用的語言環境方面的文字,數字,文件等。在本章中,我
最近穿戴設備發展得很火,把相關技術也帶旺了,其中一項是BLE(Bluetooth Low Energy)。BLE是藍牙4.0的核心Profile,主打功能是快速搜