年前就想写左右滑动菜单,苦于没有时间,一直拖到现在,这篇代码实现参考了网上流行的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. Spring核心项目及微服务架构方向

    spring 顶级项目:Spring IO platform:用于系统部署,是可集成的,构建现代化应用的版本平台,具体来说当你使用maven dependency引入spring jar包时它就在工作 ...

  2. 【转】SQL SERVER获取索引脚本

    关于如何获取索引脚本的语句很多,上次在项目中需要去查询并获取索引脚本,所以写了一个简单的查询语句来进行获取. WITH    idxcol          AS ( SELECT           ...

  3. centos7下安装openvpn,访问内网服务器 (二) windows访问

    一.简介 在上一章中已经安装好了openvpn,并且已经启动成功,现在就可以通过openvpn的客户端进行连接访问内网服务器了. 二.安装openvpn客户端 下载地址: https://www.te ...

  4. 客户端与服务端Post报文构造请求及Http Post与Get请求方法

    客户端 namespace Client.Controllers { public class HomeController : Controller { // // GET: /Home/ publ ...

  5. java正则表达式基础知识(转)

    1基础 2.1 简单字符类 构造 描述 [abc] a,b或c [^abc] 除a,b或c外的字符 [a-zA-Z] a至z 或 A至Z [a-d[m-p]] a至d 或 m至p [a-z&& ...

  6. gitlab 6 安装备忘录

    gitlab 6.2-stable;Ubuntu 13.10;ruby 2.0.0 推荐使用PostgreSQL,MySQL不同版本可能碰到兼容性问题(www.oschina.net/question ...

  7. sqlserver利用链接服务器查询或同步本地数据库和远程数据库

    这个实际上是SQLserver的分布式查询:如果一个项目需要二至多台服务器,而我们又必须从几台服务器中将数据取出来,这就必须用分布式查询!在这里有两个概念:本地数据源.远程数据源!本地数据源指的是单个 ...

  8. obj-fit

    该 object-fit CSS 属性指定替换元素的内容应该如何适应到其使用的高度和宽度确定的框. 初始值 fill 适用于 替换元素 遗传 是 媒体 视觉 计算值 按规定 动画类型 离散的 为了规范 ...

  9. HDU - 5301 Buildings

    Buildings Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) Total S ...

  10. hdu5794 A Simple Chess 容斥+Lucas 从(1,1)开始出发,每一步从(x1,y1)到达(x2,y2)满足(x2−x1)^2+(y2−y1)^2=5, x2>x1,y2>y1; 其实就是走日字。而且是往(n,m)方向走的日字。还有r个障碍物,障碍物不可以到达。求(1,1)到(n,m)的路径条数。

    A Simple Chess Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)To ...