Android-自定义滑动菜单(抽屉效果)
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了Android-自定义滑动菜单(抽屉效果),小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含15855字,纯文字阅读大概需要23分钟。
内容图文
在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;
publicclassMainActivityextendsActivity {public MyLog log = new MyLog(this, true);
@OverrideprotectedvoidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
log.e("欢迎你加入测试项目.");
link();
}
public MainController mainController;
public MainView mainView;
privatevoidlink() {
this.mainController = new MainController(this);
this.mainView = new MainView(this);
this.mainController.thisView = this.mainView;
this.mainView.thisController = this.mainController;
this.mainView.initViews();
}
@OverridepublicbooleanonTouchEvent(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;
publicclassMainController {public MyLog log = new MyLog(this, true);
public MainActivity mainActivity;
public MainController thisController;
public MainView thisView;
public GestureDetector mGesture;
publicMainController(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;
}
publicclassTouchStatus {publicint None = 4, Down = 1, Horizontal = 2, Vertical = 3, Up = 4;// LongPress = 5publicint state = None;
}
public TouchStatus touchStatus = new TouchStatus();
publicclassBodyStatus {publicint Fixed = 0, Dragging = 1, Homing = 2, FlingHoming = 3, BoundaryHoming = 4;
publicint state = Fixed;
}
public BodyStatus bodyStatus = new BodyStatus();
publicclassDrawStatus {publicint Closed = 0, Open = 1, GoClosing = 2, GoOpening = 3;
publicint state = Closed;
}
public DrawStatus drawStatus = new DrawStatus();
publicclassAreaStatus {publicint A = 0, B = 1;
publicint state = A;
}
public AreaStatus areaStatus = new AreaStatus();
publicfloat touch_pre_x;
publicfloat touch_pre_y;
publicfloat currentTranslateX;
publicbooleanonTouchEvent(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;
} elseif (x <= thisView.maxTranslateX) {
areaStatus.state = areaStatus.A;
}
}
} elseif (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 ");
}
} elseif (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;
} elseif (touchStatus.state == touchStatus.Vertical) {
log.e("Vertical");
bodyStatus.state = bodyStatus.Dragging;
}
} elseif (action == MotionEvent.ACTION_UP) {
log.e("ACTION_UP");
if (bodyStatus.state == bodyStatus.Dragging) {
if (touchStatus.state == touchStatus.Horizontal) {
bodyStatus.state = bodyStatus.Homing;
openLooper.start();
} elseif (touchStatus.state == touchStatus.Vertical) {
if (drawStatus.state == drawStatus.Open && areaStatus.state == areaStatus.B) {
bodyStatus.state = bodyStatus.Homing;
drawStatus.state = drawStatus.GoClosing;
openLooper.start();
}
}
} elseif (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);
returntrue;
}
class GestureListener extends SimpleOnGestureListener {
@OverridepublicbooleanonFling(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) {
} elseif (drawStatus.state == drawStatus.Open && velocityX > 0) {
} else {
dxSpeed = velocityX;
bodyStatus.state = bodyStatus.FlingHoming;
openLooper.start();
}
} else {
log.e("velocityY");
}
}
returntrue;
}
publicvoidonLongPress(MotionEvent event) {
}
publicbooleanonDoubleTap(MotionEvent event) {
returnfalse;
}
publicbooleanonDoubleTapEvent(MotionEvent event) {
returnfalse;
}
publicbooleanonSingleTapUp(MotionEvent event) {
returnfalse;
}
@OverridepublicbooleanonSingleTapConfirmed(MotionEvent event) {
returnfalse;
}
publicbooleanonScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
returnfalse;
}
}
publicvoidsetPosition() {
thisView.v1.setTranslationX(currentTranslateX - thisView.maxTranslateX);
thisView.v2.setTranslationX(Math.abs(currentTranslateX));
}
float transleteSpeed = 3f;
OpenLooper openLooper = null;
LoopCallback loopCallback = null;
publicclassListLoopCallbackextendsLoopCallback {publicListLoopCallback(OpenLooper openLooper) {
openLooper.super();
}
@Overridepublicvoidloop(double ellapsedMillis) {
if (bodyStatus.state == bodyStatus.Homing) {
hommingView((float) ellapsedMillis);
} elseif (bodyStatus.state == bodyStatus.FlingHoming) {
flingHomingView((float) ellapsedMillis);
}
}
}
publicfloat ratio = 0.0008f;
publicvoidflingHomingView(float ellapsedMillis) {
float distance = (float) ellapsedMillis * transleteSpeed;
boolean isStop = false;
if (drawStatus.state == drawStatus.Closed) {
drawStatus.state = drawStatus.GoOpening;
} elseif (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");
}
} elseif (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();
}
}
publicfloat dxSpeed;
publicvoiddampenSpeed(long deltaMillis) {
if (this.dxSpeed != 0.0f) {
this.dxSpeed *= (1.0f - 0.002f * deltaMillis);
if (Math.abs(this.dxSpeed) < 50f)
this.dxSpeed = 0.0f;
}
}
publicvoidhommingView(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;
}
} elseif (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;
}
} elseif (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;
}
} elseif (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;
}
} elseif (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;
publicclassMyLog {publicstaticboolean isGlobalTurnOn = true;
publicboolean isTurnOn = true;
public String tag = null;
publicMyLog(String tag, boolean isTurnOn) {
this.tag = tag;
this.isTurnOn = isTurnOn;
}
publicMyLog(Object clazz, boolean isTurnOn) {
this.tag = clazz.getClass().getSimpleName();
this.isTurnOn = isTurnOn;
}
publicvoidv(String message) {
this.v(this.tag, message);
}
publicvoidd(String message) {
this.d(this.tag, message);
}
publicvoidi(String message) {
this.i(this.tag, message);
}
publicvoidw(String message) {
this.w(this.tag, message);
}
publicvoide(String message) {
this.e(this.tag, message);
}
publicvoidv(String tag, String message) {
if (isTurnOn && isGlobalTurnOn) {
Log.v(tag, message);
}
}
publicvoidd(String tag, String message) {
if (isTurnOn && isGlobalTurnOn) {
Log.d(tag, message);
}
}
publicvoidi(String tag, String message) {
if (isTurnOn && isGlobalTurnOn) {
Log.i(tag, message);
}
}
publicvoidw(String tag, String message) {
if (isTurnOn && isGlobalTurnOn) {
Log.w(tag, message);
}
}
publicvoide(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;
publicclassOpenLooper {public LegacyAndroidSpringLooper legacyAndroidSpringLooper = null;
public ChoreographerAndroidSpringLooper choreographerAndroidSpringLooper = null;
public LoopCallback loopCallback = null;
publicvoidcreateOpenLooper() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
choreographerAndroidSpringLooper = new ChoreographerAndroidSpringLooper();
} else {
legacyAndroidSpringLooper = new LegacyAndroidSpringLooper();
}
}
publicvoidstart() {
if (choreographerAndroidSpringLooper != null) {
choreographerAndroidSpringLooper.start();
} elseif (legacyAndroidSpringLooper != null) {
legacyAndroidSpringLooper.start();
}
}
publicvoidstop() {
if (choreographerAndroidSpringLooper != null) {
choreographerAndroidSpringLooper.stop();
} elseif (legacyAndroidSpringLooper != null) {
legacyAndroidSpringLooper.stop();
}
}
publicclassLoopCallback {publicvoidloop(double ellapsedMillis) {
}
}
publicvoidloop(double ellapsedMillis) {
if (this.loopCallback != null) {
this.loopCallback.loop(ellapsedMillis);
}
}
publicclassLegacyAndroidSpringLooper {public Handler mHandler;
public Runnable mLooperRunnable;
publicboolean mStarted;
publiclong mLastTime;
publicLegacyAndroidSpringLooper() {
initialize(new Handler());
}
publicvoidinitialize(Handler handler) {
mHandler = handler;
mLooperRunnable = new Runnable() {
@Overridepublicvoidrun() {
if (!mStarted) {
return;
}
long currentTime = SystemClock.uptimeMillis();
loop(currentTime - mLastTime);
mHandler.post(mLooperRunnable);
}
};
}
publicvoidstart() {
if (mStarted) {
return;
}
mStarted = true;
mLastTime = SystemClock.uptimeMillis();
mHandler.removeCallbacks(mLooperRunnable);
mHandler.post(mLooperRunnable);
}
publicvoidstop() {
mStarted = false;
mHandler.removeCallbacks(mLooperRunnable);
}
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
publicclassChoreographerAndroidSpringLooper {public Choreographer mChoreographer;
public Choreographer.FrameCallback mFrameCallback;
publicboolean mStarted;
publiclong mLastTime;
publicChoreographerAndroidSpringLooper() {
initialize(Choreographer.getInstance());
}
publicvoidinitialize(Choreographer choreographer) {
mChoreographer = choreographer;
mFrameCallback = new Choreographer.FrameCallback() {
@OverridepublicvoiddoFrame(long frameTimeNanos) {
if (!mStarted) {
return;
}
long currentTime = SystemClock.uptimeMillis();
loop(currentTime - mLastTime);
mLastTime = currentTime;
mChoreographer.postFrameCallback(mFrameCallback);
}
};
}
publicvoidstart() {
if (mStarted) {
return;
}
mStarted = true;
mLastTime = SystemClock.uptimeMillis();
mChoreographer.removeFrameCallback(mFrameCallback);
mChoreographer.postFrameCallback(mFrameCallback);
}
publicvoidstop() {
mStarted = false;
mChoreographer.removeFrameCallback(mFrameCallback);
}
}
}
如有转载请著名来自http://blog.csdn.net/qxs965266509
源代码下载链接:http://download.csdn.net/detail/qxs965266509/8621503
原文:http://blog.csdn.net/qxs965266509/article/details/45200289
内容总结
以上是互联网集市为您收集整理的Android-自定义滑动菜单(抽屉效果)全部内容,希望文章能够帮你解决Android-自定义滑动菜单(抽屉效果)所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。