多年前,我想写一个左右滑动菜单,但我没有时间。 我一直拖到现在。 这段代码实现参考了网上流行的SlidingMenu。 使用的 FrameLayout 布局不是扩展的 HorizontalScrollView。
菜单视图在程序中自定义: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;
}
}
}
(Many years ago, I wanted to write a left-right sliding menu, but I didn't have time. I've been putting it off until now. This code implementation refers to the online popular slidingmenu. The FrameLayout layout used is not an extended horizontalscrollview.
The menu view is customized in the program: slidingview, which inherits from ViewGroup and uses FrameLayout layout. Rewrite the onintercepttouchevent (motionevent EV) method to realize ontouch distributed interception, and rewrite the ontouchevent (motionevent EV) method to realize left-right sliding.
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;
/**
*The distribution interception of ontouch is realized
*/
@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 {
mLeft
)
|