首页 > 系统 > Android > 正文

Android实现自定义滑动式抽屉效果菜单

2019-12-12 06:25:14
字体:
来源:转载
供稿:网友

在Andoird使用Android自带的那些组件,像SlidingDrawer和DrawerLayout都是抽屉效果的菜单,但是在项目很多要实现的功能都收到Android这些自带组件的限制,导致很难完成项目的需求,自定义的组件,各方面都在自己的控制之下,从而根据需求做出调整。想要实现好的效果,基本上都的基于Android的OnTouch事件自己实现响应的功能。
首先,给大家先看一下整体的效果:

滑动的加速度效果都是有的,具体的体验,只能安装后才能查看。
接下来,看代码:
代码从MainActivity延伸出了2个类:MainController和MainView,MainController来处理控制层、MainView来操作展示层。
主要代码:
MainActivity的代码:

package com.example.wz;import com.example.wz.controller.MainController;import com.example.wz.util.MyLog;import com.example.wz.view.MainView;import android.app.Activity;import android.os.Bundle;import android.view.MotionEvent;public class MainActivity extends Activity { public MyLog log = new MyLog(this, true); @Override protected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  log.e("欢迎你加入测试项目.");  link(); } public MainController mainController; public MainView mainView; private void link() {  this.mainController = new MainController(this);  this.mainView = new MainView(this);  this.mainController.thisView = this.mainView;  this.mainView.thisController = this.mainController;  this.mainView.initViews(); } @Override public boolean onTouchEvent(MotionEvent event) {  super.onTouchEvent(event);  return mainController.onTouchEvent(event); }}

MainController的代码:

package com.example.wz.controller;import android.view.GestureDetector;import android.view.GestureDetector.SimpleOnGestureListener;import android.view.MotionEvent;import com.example.wz.MainActivity;import com.example.wz.util.MyLog;import com.example.wz.util.OpenLooper;import com.example.wz.util.OpenLooper.LoopCallback;import com.example.wz.view.MainView;public class MainController { public MyLog log = new MyLog(this, true); public MainActivity mainActivity; public MainController thisController; public MainView thisView; public GestureDetector mGesture; public MainController(MainActivity mainActivity) {  this.mainActivity = mainActivity;  this.thisController = this;  mGesture = new GestureDetector(mainActivity, new GestureListener());  openLooper = new OpenLooper();  openLooper.createOpenLooper();  loopCallback = new ListLoopCallback(openLooper);  openLooper.loopCallback = loopCallback; } public class TouchStatus {  public int None = 4, Down = 1, Horizontal = 2, Vertical = 3, Up = 4;// LongPress = 5  public int state = None; } public TouchStatus touchStatus = new TouchStatus(); public class BodyStatus {  public int Fixed = 0, Dragging = 1, Homing = 2, FlingHoming = 3, BoundaryHoming = 4;  public int state = Fixed; } public BodyStatus bodyStatus = new BodyStatus(); public class DrawStatus {  public int Closed = 0, Open = 1, GoClosing = 2, GoOpening = 3;  public int state = Closed; } public DrawStatus drawStatus = new DrawStatus(); public class AreaStatus {  public int A = 0, B = 1;  public int state = A; } public AreaStatus areaStatus = new AreaStatus(); public float touch_pre_x; public float touch_pre_y; public float currentTranslateX; public boolean onTouchEvent(MotionEvent event) {  int action = event.getAction();  float x = event.getX();  float y = event.getY();  if (action == MotionEvent.ACTION_DOWN) {   this.touch_pre_x = x;   this.touch_pre_y = y;   if (touchStatus.state == touchStatus.None) {    touchStatus.state = touchStatus.Down;    log.e("Down ");    if (x > thisView.maxTranslateX) {     areaStatus.state = areaStatus.B;    } else if (x <= thisView.maxTranslateX) {     areaStatus.state = areaStatus.A;    }   }  } else if (action == MotionEvent.ACTION_MOVE) {   float Δy = (y - touch_pre_y);   float Δx = (x - touch_pre_x);   if (touchStatus.state == touchStatus.Down) {    if (Δx * Δx + Δy * Δy > 400) {     if (Δx * Δx > Δy * Δy) {      touchStatus.state = touchStatus.Horizontal;     } else {      touchStatus.state = touchStatus.Vertical;     }     touch_pre_x = x;     touch_pre_y = y;     log.e("ACTION_MOVE ");    }   } else if (touchStatus.state == touchStatus.Horizontal) {    currentTranslateX += Δx;    this.touch_pre_x = x;    this.touch_pre_y = y;    if (currentTranslateX - thisView.maxTranslateX <= 0 && currentTranslateX >= 0) {     setPosition();    }    log.e("Horizontal");    bodyStatus.state = bodyStatus.Dragging;   } else if (touchStatus.state == touchStatus.Vertical) {    log.e("Vertical");    bodyStatus.state = bodyStatus.Dragging;   }  } else if (action == MotionEvent.ACTION_UP) {   log.e("ACTION_UP");   if (bodyStatus.state == bodyStatus.Dragging) {    if (touchStatus.state == touchStatus.Horizontal) {     bodyStatus.state = bodyStatus.Homing;     openLooper.start();    } else if (touchStatus.state == touchStatus.Vertical) {     if (drawStatus.state == drawStatus.Open && areaStatus.state == areaStatus.B) {      bodyStatus.state = bodyStatus.Homing;      drawStatus.state = drawStatus.GoClosing;      openLooper.start();     }    }   } else if (touchStatus.state == touchStatus.Down && areaStatus.state == areaStatus.B) {    bodyStatus.state = bodyStatus.Homing;    drawStatus.state = drawStatus.GoClosing;    openLooper.start();   }   touchStatus.state = touchStatus.Up;  }  mGesture.onTouchEvent(event);  return true; } class GestureListener extends SimpleOnGestureListener {  @Override  public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {   if (velocityX * velocityX + velocityY * velocityY > 250000) {    if (velocityX * velocityX > velocityY * velocityY) {     log.e("velocityX--" + velocityX);     if (drawStatus.state == drawStatus.Closed && velocityX < 0) {     } else if (drawStatus.state == drawStatus.Open && velocityX > 0) {     } else {      dxSpeed = velocityX;      bodyStatus.state = bodyStatus.FlingHoming;      openLooper.start();     }    } else {     log.e("velocityY");    }   }   return true;  }  public void onLongPress(MotionEvent event) {  }  public boolean onDoubleTap(MotionEvent event) {   return false;  }  public boolean onDoubleTapEvent(MotionEvent event) {   return false;  }  public boolean onSingleTapUp(MotionEvent event) {   return false;  }  @Override  public boolean onSingleTapConfirmed(MotionEvent event) {   return false;  }  public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {   return false;  } } public void setPosition() {  thisView.v1.setTranslationX(currentTranslateX - thisView.maxTranslateX);  thisView.v2.setTranslationX(Math.abs(currentTranslateX)); } float transleteSpeed = 3f; OpenLooper openLooper = null; LoopCallback loopCallback = null; public class ListLoopCallback extends LoopCallback {  public ListLoopCallback(OpenLooper openLooper) {   openLooper.super();  }  @Override  public void loop(double ellapsedMillis) {   if (bodyStatus.state == bodyStatus.Homing) {    hommingView((float) ellapsedMillis);   } else if (bodyStatus.state == bodyStatus.FlingHoming) {    flingHomingView((float) ellapsedMillis);   }  } } public float ratio = 0.0008f; public void flingHomingView(float ellapsedMillis) {  float distance = (float) ellapsedMillis * transleteSpeed;  boolean isStop = false;  if (drawStatus.state == drawStatus.Closed) {   drawStatus.state = drawStatus.GoOpening;  } else if (drawStatus.state == drawStatus.Open) {   drawStatus.state = drawStatus.GoClosing;  }  if (drawStatus.state == drawStatus.GoClosing) {   this.currentTranslateX -= distance;   if (this.currentTranslateX <= 0) {    this.currentTranslateX = 0;    drawStatus.state = drawStatus.Closed;    isStop = true;    log.e("-------------1");   }  } else if (drawStatus.state == drawStatus.GoOpening) {   this.currentTranslateX += distance;   if (this.currentTranslateX >= thisView.maxTranslateX) {    this.currentTranslateX = thisView.maxTranslateX;    drawStatus.state = drawStatus.Open;    isStop = true;    log.e("-------------2");   }  }  setPosition();  if (isStop) {   openLooper.stop();  } } public float dxSpeed; public void dampenSpeed(long deltaMillis) {  if (this.dxSpeed != 0.0f) {   this.dxSpeed *= (1.0f - 0.002f * deltaMillis);   if (Math.abs(this.dxSpeed) < 50f)    this.dxSpeed = 0.0f;  } } public void hommingView(float ellapsedMillis) {  float distance = (float) ellapsedMillis * transleteSpeed;  boolean isStop = false;  if (drawStatus.state == drawStatus.Closed && this.currentTranslateX < thisView.maxTranslateX / 5) {   this.currentTranslateX -= distance;   if (this.currentTranslateX <= 0) {    this.currentTranslateX = 0;    drawStatus.state = drawStatus.Closed;    isStop = true;   }  } else if (drawStatus.state == drawStatus.Closed && this.currentTranslateX >= thisView.maxTranslateX / 5) {   this.currentTranslateX += distance;   if (this.currentTranslateX >= thisView.maxTranslateX) {    this.currentTranslateX = thisView.maxTranslateX;    drawStatus.state = drawStatus.Open;    isStop = true;   }  } else if (drawStatus.state == drawStatus.Open && this.currentTranslateX < thisView.maxTranslateX / 5 * 4) {   this.currentTranslateX -= distance;   if (this.currentTranslateX <= 0) {    this.currentTranslateX = 0;    drawStatus.state = drawStatus.Closed;    isStop = true;   }  } else if (drawStatus.state == drawStatus.Open && this.currentTranslateX >= thisView.maxTranslateX / 5 * 4) {   this.currentTranslateX += distance;   if (this.currentTranslateX >= thisView.maxTranslateX) {    this.currentTranslateX = thisView.maxTranslateX;    drawStatus.state = drawStatus.Open;    isStop = true;   }  } else if (drawStatus.state == drawStatus.GoClosing) {   this.currentTranslateX -= distance;   if (this.currentTranslateX <= 0) {    this.currentTranslateX = 0;    drawStatus.state = drawStatus.Closed;    isStop = true;   }  }  setPosition();  if (isStop) {   openLooper.stop();   log.e("looper stop...");  } }}

MainView的代码:

package com.example.wz.view;import android.graphics.Color;import android.util.DisplayMetrics;import android.view.ViewGroup.LayoutParams;import android.widget.RelativeLayout;import android.widget.TextView;import com.example.wz.MainActivity;import com.example.wz.R;import com.example.wz.controller.MainController;import com.example.wz.util.MyLog;public class MainView { public MyLog log = new MyLog(this, true); public MainActivity mainActivity; public MainController thisController; public MainView thisView; public MainView(MainActivity mainActivity) {  this.mainActivity = mainActivity;  this.thisView = this; } public DisplayMetrics displayMetrics; public float screenWidth; public float screenHeight; public float density; public float maxTranslateX; public RelativeLayout maxView; public RelativeLayout v1; public RelativeLayout v2; public void initViews() {  this.displayMetrics = new DisplayMetrics();  this.mainActivity.getWindowManager().getDefaultDisplay().getMetrics(this.displayMetrics);  this.screenHeight = this.displayMetrics.heightPixels;  this.screenWidth = this.displayMetrics.widthPixels;  this.density = this.displayMetrics.density;  this.maxTranslateX = this.screenWidth * 0.8f;  this.mainActivity.setContentView(R.layout.activity_main);  this.maxView = (RelativeLayout) this.mainActivity.findViewById(R.id.maxView);  v1 = new RelativeLayout(mainActivity);  v1.setBackgroundColor(Color.RED);  RelativeLayout.LayoutParams params1 = new RelativeLayout.LayoutParams((int) this.maxTranslateX, LayoutParams.MATCH_PARENT);  this.maxView.addView(v1, params1);  TextView t1 = new TextView(mainActivity);  t1.setText("left menu bar");  t1.setTextColor(Color.WHITE);  v1.addView(t1);  v1.setTranslationX(0 - this.maxTranslateX);  v2 = new RelativeLayout(mainActivity);  v2.setBackgroundColor(Color.parseColor("#0099cd"));  RelativeLayout.LayoutParams params2 = new RelativeLayout.LayoutParams((int) this.screenWidth, LayoutParams.MATCH_PARENT);  this.maxView.addView(v2, params2);  v2.setTranslationX(0);  TextView t2 = new TextView(mainActivity);  t2.setText("body content");  t2.setTextColor(Color.WHITE);  v2.addView(t2); }}

日志管理类MyLog:

package com.example.wz.util;import android.util.Log;public class MyLog { public static boolean isGlobalTurnOn = true; public boolean isTurnOn = true; public String tag = null; public MyLog(String tag, boolean isTurnOn) {  this.tag = tag;  this.isTurnOn = isTurnOn; } public MyLog(Object clazz, boolean isTurnOn) {  this.tag = clazz.getClass().getSimpleName();  this.isTurnOn = isTurnOn; } public void v(String message) {  this.v(this.tag, message); } public void d(String message) {  this.d(this.tag, message); } public void i(String message) {  this.i(this.tag, message); } public void w(String message) {  this.w(this.tag, message); } public void e(String message) {  this.e(this.tag, message); } public void v(String tag, String message) {  if (isTurnOn && isGlobalTurnOn) {   Log.v(tag, message);  } } public void d(String tag, String message) {  if (isTurnOn && isGlobalTurnOn) {   Log.d(tag, message);  } } public void i(String tag, String message) {  if (isTurnOn && isGlobalTurnOn) {   Log.i(tag, message);  } } public void w(String tag, String message) {  if (isTurnOn && isGlobalTurnOn) {   Log.w(tag, message);  } } public void e(String tag, String message) {  if (isTurnOn && isGlobalTurnOn) {   Log.e(tag, message);  } }}

实现动画效果的核心类OpenLooper:

package com.example.wz.util;import android.annotation.TargetApi;import android.os.Build;import android.os.Handler;import android.os.SystemClock;import android.view.Choreographer;public class OpenLooper { public LegacyAndroidSpringLooper legacyAndroidSpringLooper = null; public ChoreographerAndroidSpringLooper choreographerAndroidSpringLooper = null; public LoopCallback loopCallback = null; public void createOpenLooper() {  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {   choreographerAndroidSpringLooper = new ChoreographerAndroidSpringLooper();  } else {   legacyAndroidSpringLooper = new LegacyAndroidSpringLooper();  } } public void start() {  if (choreographerAndroidSpringLooper != null) {   choreographerAndroidSpringLooper.start();  } else if (legacyAndroidSpringLooper != null) {   legacyAndroidSpringLooper.start();  } } public void stop() {  if (choreographerAndroidSpringLooper != null) {   choreographerAndroidSpringLooper.stop();  } else if (legacyAndroidSpringLooper != null) {   legacyAndroidSpringLooper.stop();  } } public class LoopCallback {  public void loop(double ellapsedMillis) {  } } public void loop(double ellapsedMillis) {  if (this.loopCallback != null) {   this.loopCallback.loop(ellapsedMillis);  } } public class LegacyAndroidSpringLooper {  public Handler mHandler;  public Runnable mLooperRunnable;  public boolean mStarted;  public long mLastTime;  public LegacyAndroidSpringLooper() {   initialize(new Handler());  }  public void initialize(Handler handler) {   mHandler = handler;   mLooperRunnable = new Runnable() {    @Override    public void run() {     if (!mStarted) {      return;     }     long currentTime = SystemClock.uptimeMillis();     loop(currentTime - mLastTime);     mHandler.post(mLooperRunnable);    }   };  }  public void start() {   if (mStarted) {    return;   }   mStarted = true;   mLastTime = SystemClock.uptimeMillis();   mHandler.removeCallbacks(mLooperRunnable);   mHandler.post(mLooperRunnable);  }  public void stop() {   mStarted = false;   mHandler.removeCallbacks(mLooperRunnable);  } } @TargetApi(Build.VERSION_CODES.JELLY_BEAN) public class ChoreographerAndroidSpringLooper {  public Choreographer mChoreographer;  public Choreographer.FrameCallback mFrameCallback;  public boolean mStarted;  public long mLastTime;  public ChoreographerAndroidSpringLooper() {   initialize(Choreographer.getInstance());  }  public void initialize(Choreographer choreographer) {   mChoreographer = choreographer;   mFrameCallback = new Choreographer.FrameCallback() {    @Override    public void doFrame(long frameTimeNanos) {     if (!mStarted) {      return;     }     long currentTime = SystemClock.uptimeMillis();     loop(currentTime - mLastTime);     mLastTime = currentTime;     mChoreographer.postFrameCallback(mFrameCallback);    }   };  }  public void start() {   if (mStarted) {    return;   }   mStarted = true;   mLastTime = SystemClock.uptimeMillis();   mChoreographer.removeFrameCallback(mFrameCallback);   mChoreographer.postFrameCallback(mFrameCallback);  }  public void stop() {   mStarted = false;   mChoreographer.removeFrameCallback(mFrameCallback);  } }}

转载来自:http://blog.csdn.net/qxs965266509

源码下载:抽屉效果

以上就是本文的全部内容,希望对大家的学习有所帮助。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表