年前就想写左右滑动菜单,苦于没有时间,一直拖到现在,这篇代码实现参考了网上流行的SlidingMenu,使用的FrameLayout布局,不是扩展的HorizontalScrollView。

程序中自定义了菜单view:SlidingView,继承自ViewGroup,使用FrameLayout布局。重写了onInterceptTouchEvent(MotionEvent ev)方法实现ontouch的分发拦截,重写了onTouchEvent(MotionEvent ev)方法,实现左右滑动。

public class SlidingView extends ViewGroup {

	private FrameLayout mContainer;
private Scroller mScroller;
private VelocityTracker mVelocityTracker;
private int mTouchSlop;
private float mLastMotionX;
private float mLastMotionY;
private static final int SNAP_VELOCITY = 1000;
private View mLeftView;
private View mRightView; public SlidingView(Context context) {
super(context);
init();
} public SlidingView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
} public SlidingView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mContainer.measure(widthMeasureSpec, heightMeasureSpec);
} @Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int width = r - l;
final int height = b - t;
mContainer.layout(0, 0, width, height);
} private void init() {
mContainer = new FrameLayout(getContext());
mContainer.setBackgroundColor(0xff000000);
mScroller = new Scroller(getContext());
mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
super.addView(mContainer);
} public void setView(View v) {
if (mContainer.getChildCount() > 0) {
mContainer.removeAllViews();
}
mContainer.addView(v);
} @Override
public void scrollTo(int x, int y) {
super.scrollTo(x, y);
postInvalidate();
} @Override
public void computeScroll() {
if (!mScroller.isFinished()) {
if (mScroller.computeScrollOffset()) {
int oldX = getScrollX();
int oldY = getScrollY();
int x = mScroller.getCurrX();
int y = mScroller.getCurrY();
if (oldX != x || oldY != y) {
scrollTo(x, y);
}
// Keep on drawing until the animation has finished.
invalidate();
} else {
clearChildrenCache();
}
} else {
clearChildrenCache();
}
} private boolean mIsBeingDragged; /**
* 实现了ontouch的分发拦截
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) { final int action = ev.getAction();
final float x = ev.getX();
final float y = ev.getY(); switch (action) {
case MotionEvent.ACTION_DOWN:
mLastMotionX = x;
mLastMotionY = y;
mIsBeingDragged = false;
break; case MotionEvent.ACTION_MOVE:
final float dx = x - mLastMotionX;
final float xDiff = Math.abs(dx);
final float yDiff = Math.abs(y - mLastMotionY);
if (xDiff > mTouchSlop && xDiff > yDiff) {
mIsBeingDragged = true;
mLastMotionX = x;
}
Log.d("Sliding", "SlidingView_Touch:"+x+"|"+y);
Log.d("Sliding", "SlidingView_Touch:"+xDiff+"|"+mTouchSlop+"|"+yDiff+"|"+mLastMotionY);
Log.d("Sliding", "SlidingView_Touch:"+mIsBeingDragged);
break; }
return mIsBeingDragged;
} @Override
public boolean onTouchEvent(MotionEvent ev) { if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
mVelocityTracker.addMovement(ev); final int action = ev.getAction();
final float x = ev.getX();
final float y = ev.getY(); switch (action) {
case MotionEvent.ACTION_DOWN:
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
mLastMotionX = x;
mLastMotionY = y;
if (getScrollX() == -getLeftMenuWidth()
&& mLastMotionX < getLeftMenuWidth()) {
return false;
} if (getScrollX() == getRightMenuWidth()
&& mLastMotionX > getLeftMenuWidth()) {
return false;
} break;
case MotionEvent.ACTION_MOVE:
if (mIsBeingDragged) {
enableChildrenCache();
final float deltaX = mLastMotionX - x;
mLastMotionX = x;
float oldScrollX = getScrollX();
float scrollX = oldScrollX + deltaX; if (deltaX < 0 && oldScrollX < 0) { // left view
final float leftBound = 0;
final float rightBound = -getLeftMenuWidth();
if (scrollX > leftBound) {
scrollX = leftBound;
} else if (scrollX < rightBound) {
scrollX = rightBound;
}
} else if (deltaX > 0 && oldScrollX > 0) { // right view
final float rightBound = getRightMenuWidth();
final float leftBound = 0;
if (scrollX < leftBound) {
scrollX = leftBound;
} else if (scrollX > rightBound) {
scrollX = rightBound;
}
} scrollTo((int) scrollX, getScrollY());
if (scrollX > 0) {
mLeftView.setVisibility(View.GONE);
mLeftView.clearFocus();
mRightView.setVisibility(View.VISIBLE);
mRightView.requestFocus();
} else {
mLeftView.setVisibility(View.VISIBLE);
mLeftView.requestFocus();
mRightView.setVisibility(View.GONE);
mRightView.clearFocus();
}
}
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
if (mIsBeingDragged) {
final VelocityTracker velocityTracker = mVelocityTracker;
velocityTracker.computeCurrentVelocity(1000);
int velocityX = (int) velocityTracker.getXVelocity();
velocityX = 0;
int oldScrollX = getScrollX();
int dx = 0;
if (oldScrollX < 0) {
// 左边
if (oldScrollX < -getLeftMenuWidth() / 2
|| velocityX > SNAP_VELOCITY) {
// 左侧页面划出
dx = -getLeftMenuWidth() - oldScrollX; } else if (oldScrollX >= -getLeftMenuWidth() / 2
|| velocityX < -SNAP_VELOCITY) {
// 左侧页面关闭
dx = -oldScrollX;
}
} else {
// 右边
if (oldScrollX > getRightMenuWidth() / 2
|| velocityX < -SNAP_VELOCITY) {
// 右侧页面划出
dx = getRightMenuWidth() - oldScrollX; } else if (oldScrollX <= getRightMenuWidth() / 2
|| velocityX > SNAP_VELOCITY) {
// 右侧页面关闭
dx = -oldScrollX;
}
} smoothScrollTo(dx);
clearChildrenCache(); } break; }
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
return true;
} private int getLeftMenuWidth() {
if (mLeftView == null) {
return 0;
}
return mLeftView.getWidth();
} private int getRightMenuWidth() {
if (mRightView == null) {
return 0;
}
return mRightView.getWidth();
} @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
} public View getRightView() {
return mRightView;
} public void setRightView(View mRightView) {
this.mRightView = mRightView;
} public View getMenuView() {
return mLeftView;
} public void setLeftView(View mLeftView) {
this.mLeftView = mLeftView;
} void toggle() {
int menuWidth = mLeftView.getWidth();
int oldScrollX = getScrollX();
if (oldScrollX == 0) {
smoothScrollTo(-menuWidth);
} else if (oldScrollX == -menuWidth) {
smoothScrollTo(menuWidth);
}
} /**
* 打开(关闭)左侧页面
*/
public void showLeftView() {
mLeftView.setVisibility(View.VISIBLE);
mRightView.setVisibility(View.GONE);
int menuWidth = mLeftView.getWidth();
int oldScrollX = getScrollX();
if (oldScrollX == 0) {
smoothScrollTo(-menuWidth);
} else if (oldScrollX == -menuWidth) {
smoothScrollTo(menuWidth);
}
} /**
* 打开(关闭)右侧页面
*/
public void showRightView() {
mLeftView.setVisibility(View.GONE);
mLeftView.clearFocus();
mRightView.setVisibility(View.VISIBLE);
mRightView.requestFocus();
int menuWidth = mRightView.getWidth();
int oldScrollX = getScrollX();
if (oldScrollX == 0) {
smoothScrollTo(menuWidth);
} else if (oldScrollX == menuWidth) {
smoothScrollTo(-menuWidth);
}
} /**
* 显示中间页面
*/
public void showCenterView() {
int menuWidth = mRightView.getWidth();
int oldScrollX = getScrollX();
if (oldScrollX == menuWidth) {
showRightView();
} else if (oldScrollX == -menuWidth) {
showLeftView();
}
} void smoothScrollTo(int dx) {
int duration = 500;
int oldScrollX = getScrollX();
mScroller.startScroll(oldScrollX, getScrollY(), dx, getScrollY(),
duration);
invalidate();
} void enableChildrenCache() {
final int count = getChildCount();
for (int i = 0; i < count; i++) {
final View layout = (View) getChildAt(i);
layout.setDrawingCacheEnabled(true);
}
} void clearChildrenCache() {
final int count = getChildCount();
for (int i = 0; i < count; i++) {
final View layout = (View) getChildAt(i);
layout.setDrawingCacheEnabled(false);
}
} }

SlidingMenu对SlidingView做了进一步封装处理:

public class SlidingMenu extends RelativeLayout {

	private SlidingView mSlidingView;
private View mLeftView;
private View mRightView;
// menu width
private int alignScreenWidth; public SlidingMenu(Context context) {
super(context);
} public SlidingMenu(Context context, AttributeSet attrs) {
super(context, attrs);
} public SlidingMenu(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
} public void setAlignScreenWidth(int alignScreenWidth) {
this.alignScreenWidth = alignScreenWidth;
} public void setLeftView(View view) {
LayoutParams behindParams = new LayoutParams(alignScreenWidth,
LayoutParams.MATCH_PARENT);
addView(view, behindParams);
mLeftView = view;
} public void setRightView(View view) {
LayoutParams behindParams = new LayoutParams(alignScreenWidth,
LayoutParams.MATCH_PARENT);
behindParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
addView(view, behindParams);
mRightView = view;
} public void setCenterView(View view) {
LayoutParams aboveParams = new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT);
mSlidingView = new SlidingView(getContext());
addView(mSlidingView, aboveParams);
mSlidingView.setView(view);
mSlidingView.invalidate();
mSlidingView.setLeftView(mLeftView);
mSlidingView.setRightView(mRightView);
} public void showLeftView() {
mSlidingView.showLeftView();
} public void showRightView() {
mSlidingView.showRightView();
} public void showCenterView() {
mSlidingView.showCenterView();
} }

SlidingMenu的使用代码

public class SlidingActivity extends Activity implements OnClickListener{
SlidingMenu mSlidingMenu; @Override
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
setContentView(R.layout.main); DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm); mSlidingMenu = (SlidingMenu) findViewById(R.id.slidingMenu);
mSlidingMenu.setAlignScreenWidth((dm.widthPixels / 5) * 2); View leftView=getLayoutInflater().inflate(R.layout.left_menu, null);
View rightView=getLayoutInflater().inflate(R.layout.right_menu, null);
View centerView=getLayoutInflater().inflate(R.layout.center, null); mSlidingMenu.setLeftView(leftView);
mSlidingMenu.setRightView(rightView);
mSlidingMenu.setCenterView(centerView); Button showLeftMenu=(Button)centerView.findViewById(R.id.center_left_btn);
showLeftMenu.setOnClickListener(this);
Button showRightMenu=(Button)centerView.findViewById(R.id.center_right_btn);
showRightMenu.setOnClickListener(this);
} @Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.center_left_btn:
mSlidingMenu.showLeftView();
break;
case R.id.center_right_btn:
mSlidingMenu.showRightView();
break;
default:
break;
}
} }

                                

代码:http://download.csdn.net/detail/xyz_lmn/5109965

/**
* @author 张兴业
*  iOS入门群:83702688
*  android开发进阶群:241395671
*  我的新浪微博:@张兴业TBOW
*  我的邮箱:xy-zhang#163.com(#->@)
*/

Android UI开发第二十七篇——实现左右划出菜单的更多相关文章

  1. Android UI开发第二十八篇——Fragment中使用左右滑动菜单

    Fragment实现了Android UI的分片管理,尤其在平板开发中,好处多多.这一篇将借助Android UI开发第二十六篇——Fragment间的通信. Android UI开发第二十七篇——实 ...

  2. Android UI开发第二十四篇——Action Bar

    Action bar是一个标识应用程序和用户位置的窗口功能,并且给用户提供操作和导航模式.在大多数的情况下,当你需要突出展现用户行为或全局导航的activity中使用action bar,因为acti ...

  3. 【转】Android UI开发第二十四篇——Action Bar

    Action bar是一个标识应用程序和用户位置的窗口功能,并且给用户提供操作和导航模式.在大多数的情况下,当你需要突出展现用户行为或全局导航的activity中使用action bar,因为acti ...

  4. Android UI开发第二十六篇——Fragment间的通信

    为了重用Fragment的UI组件,创建的每个Fragment都应该是自包含的.有它自己的布局和行为的模块化组件.一旦你定义了这些可重用的Fragment,你就可以把它们跟一个Activity关联,并 ...

  5. Android UI开发第二十九篇——Android中五种常用的menu(菜单)

    Android Menu在手机的应用中起着导航的作用,作者总结了5种常用的Menu. 1.左右推出的Menu 前段时间比较流行,我最早是在海豚浏览器中看到的,当时耳目一新.最早使用左右推出菜单的,听说 ...

  6. Android UI开发第三十篇——使用Fragment构建灵活的桌面

    http://www.lupaworld.com/article-222973-1.html 当我们设计应用程序时,希望能够尽最大限度的适配各种设备,包括4寸屏.7寸屏. 10寸屏等等,Android ...

  7. Android UI开发第三十五篇——AppCompat实现Action Bar

    每一位Android开发者对Action Bar这种设计都不陌生了,毕竟它已经发布了至少两年了.Android团队发布Action Bar设计规范时同时放出了ActionBar的Api来支持这种设计. ...

  8. Android UI开发第四十一篇——墨迹天气3.0引导界面及动画实现

    周末升级了墨迹天气,看着引导界面做的不错,模仿一下,可能与原作者的代码实现不一样,但是实现的效果还是差不多的.先分享一篇以前的文章,android动画的基础知识,<Android UI开发第十二 ...

  9. Android UI开发第三十九篇——Tab界面实现汇总及比较

    Tab布局是iOS的经典布局,Android应用中也有大量应用,前面也写过Android中TAb的实现,<Android UI开发第十八篇——ActivityGroup实现tab功能>.这 ...

随机推荐

  1. selinux 是什么 (Linux)

    SElinux是Linux安全加强工具.关闭用setenforce 0或者修改文件vim /etc/sysconfig/selinux 把SELINUX=enforcing 改为 SELINUX=di ...

  2. 注册表 API 以及开机自启动

    注册表是window系统中非常重要的一部分,今天在网上查了一些文章学习了下,觉得其中有一句话总结的很经典:注册表是用来存储信息的. 这句话虽然有点废,但是说的没错.当然,注册表中包含的内容非常多,远没 ...

  3. unity web项目发布服务器Data file is corrupt (not a Unity W

    楼上问题需要在iis 中配置MIME 加一个 .unity3d MIME类型:application/octet-stream http://www.cnblogs.com/123ing/p/3913 ...

  4. react-native-storage + AsyncStorage 实现数据存储

    1.组件封装 import Storage from 'react-native-storage'; import { AsyncStorage } from 'react-native'; cons ...

  5. Android开发之Is Library篇

    一.生活场景描述 由于公司有一个项目开发的时间比较长,项目里堆砌的代码也比较多,并且有些功能在给不同客户发布的时候有些功能还不需要,这样功能模块分离就很有必要了. 所以,Library就被推到了前台, ...

  6. Docker -CentOS 6.5上安装

    开始安装daoker之旅: 1. [root@localhost ~]# uname -r -.el6.x86_64 2. [root@localhost ~]# cat /etc/issue Cen ...

  7. 《深入PHP:面向对象、模式与实践》(二)

    第4章 高级特性 本章内容提要: 静态属性和方法:通过类而不是对象来访问数据和功能 抽象类和接口:设计和实现分离 错误处理:异常 Final类和方法:限制继承 拦截器方法:自动委托 析构方法:对象销毁 ...

  8. javascript原型的改动与重写(覆盖)区别

    每一个JavaScript函数都有prototype属性(javascript对象没有这个属性),这个属性引用了一个对象,这个对象就是原型对象.javascript同意我们改动这个原型对象. 改动有2 ...

  9. 深入PHP中慎用双等于(==)的详解

    PHP比较运算符出现的频率实在是太高了,尤其是 ==if(a == b){// do something}但是,你真的掌握了 == 了吗?细节很重要!来看下面的代码,说出你认为正确的答案var_dum ...

  10. GTS、GCK,GSR全称

    GTS:Global 3-state buffer delay 全局使能,三态 GCK:Global Clock buffer delay   全局时钟 GSR:Global set/reset bu ...