slidingMenu 详解,快速实现左右滑动

来源:互联网 发布:java 7 8 新特性 编辑:程序博客网 时间:2024/05/21 21:50

先上效果图:(宽度是自适应的)


一步一步来啦!

工程的结构:


(1)布局文件,这里需要四个layout布局文件,left.xml,right.xml,center.xml和启动用的activity_main.xml

启动layout布局文件 activity_main.xml 代码如下,

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    tools:context=".MainActivity" >        <com.zhong.haolin_my_view.ui.MySlidingMenu        android:layout_width="fill_parent"        android:layout_height="fill_parent"        android:id="@+id/MySlidingMenu">    </com.zhong.haolin_my_view.ui.MySlidingMenu></FrameLayout>
主界面布局文件 center.xml 代码如下:

<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    android:id="@+id/center_fragment"     android:background="@color/bg">        <TextView         android:layout_width="fill_parent"        android:layout_height="fill_parent"        android:text="中间center"/>    <Button        android:id="@+id/button1"        android:layout_width="130dip"        android:layout_height="wrap_content"        android:layout_marginTop="220dip"        android:text="Button" />    <Button        android:id="@+id/button2"        android:layout_width="130dip"        android:layout_height="wrap_content"        android:text="Button"         android:layout_marginTop="120dip"          android:layout_marginLeft="80dip" /></FrameLayout>
左侧菜单布局文件 left.xml 代码如下:

<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="fill_parent"     android:id="@+id/left_fragment"    android:background="@color/bg_left">      <TextView         android:layout_width="fill_parent"        android:layout_height="fill_parent"        android:text="左边菜单left"/></FrameLayout>
右侧菜单布局文件 right.xml 代码如下:
<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="fill_parent"     android:id="@+id/right_fragment"    android:background="@color/bg_right">    <TextView         android:layout_width="fill_parent"        android:layout_height="fill_parent"        android:text="右边菜单right"/></FrameLayout>
(2)启动类MainActivity.java 代码如下:

public class MainActivity extends FragmentActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);final MySlidingMenu slidingMenu = (MySlidingMenu)findViewById(R.id.MySlidingMenu);slidingMenu.setView(getLayoutInflater().inflate(R.layout.left, null),getLayoutInflater().inflate(R.layout.right, null),getLayoutInflater().inflate(R.layout.center, null));Button button = (Button)findViewById(R.id.button1);button.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {slidingMenu.showLeft();}});Button button2 = (Button)findViewById(R.id.button2);button2.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {slidingMenu.showRight();}});}}

(3)MySlidingMenu滑动类,继承自RelativeLayout,有两层布局,第一层是LeftLayout和RightLayout,第二层是MySlidingView,其实也就是一个FramLayout,代码如下:

public class MySlidingMenu extends RelativeLayout {/** * 左边菜单 */private View LeftLayout;/** * 右边菜单 */private View rightLayout;/* * 主界面 */private MySlidingView contenerlayout;public MySlidingMenu(Context context) {super(context);}public MySlidingMenu(Context context, AttributeSet attrs) {super(context, attrs);}public MySlidingMenu(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);}// 添加左菜单private void setLeftLatout(View view){LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.FILL_PARENT);layoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);super.addView(view, layoutParams);LeftLayout = view;}// 添加右菜单private void setRightLayout(View view){LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.FILL_PARENT);layoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);super.addView(view, layoutParams);rightLayout = view;}// 添加主界面private void setContenerLayout(View view){LayoutParams layoutParams = new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT);contenerlayout = new MySlidingView(getContext());super.addView(contenerlayout, layoutParams);contenerlayout.setView(view);contenerlayout.setLeftLayout(LeftLayout);contenerlayout.setRightlayout(rightLayout);contenerlayout.invalidate();}// 添加左菜单,右菜单,主界面public void setView(View leftView, View rightView, View mainView){setLeftLatout(leftView);setRightLayout(rightView);setContenerLayout(mainView);}// 显示左菜单public void showLeft(){contenerlayout.showLeftView();}// 显示右菜单public void showRight(){contenerlayout.showRightView();}}
上面的代码还是比较简单,接下来才是重头菜,真正实现滑动的MySlidingView
(4)MySlidingView.java 代码如下:

public class MySlidingView extends ViewGroup {    /**     * 主布局     */    private FrameLayout mContainer;    /**     * 超过此距离,控件才允许滑动     */    private int mTouchSlop;     /**      * 记录是否能滑动布局      */    private boolean mIsBeingDragged ;    /**     * 记录最后的一次触屏     */    private float mLastMotionX ;    private float mLastMotionY ;    /**     * 平滑组件     */    private Scroller mScroller;    /**     * 左侧菜单     */    private View leftLayout;    /**     * 右侧菜单     */    private View rightlayout;    /**     * 速度     */private static final int SNAP_VELOCITY = 100;public MySlidingView(Context context) {super(context);init();}public MySlidingView(Context context, AttributeSet attrs) {super(context, attrs);init();}public MySlidingView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);init();}// 同时绘制mContainer@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);// L.i(getClass(), "onMeasure[widthMeasureSpec:"+widthMeasureSpec+",heightMeasureSpec:"+heightMeasureSpec+"]");mContainer.measure(widthMeasureSpec, heightMeasureSpec);}@Overrideprotected void onLayout(boolean changed, int left, int top, int right, int bottom) {// L.i(getClass(), "onLayout[changed:"+changed+",left:"+left+",top:"+top+",right:"+right+",bottom:"+bottom+"]");int width = right - left;int height = bottom - top;mContainer.layout(0, 0, width, height);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);}// endprivate void init(){mContainer = new FrameLayout(getContext());mScroller = new Scroller(getContext());mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();super.addView(mContainer);}public void setView(View view) {if(mContainer.getChildCount() > 0)mContainer.removeAllViews();mContainer.addView(view);}@Overridepublic void scrollTo(int x, int y) {super.scrollTo(x, y);postInvalidate();// 刷新UI可以在UI中刷新}// 整个viewgroup一起滑动@Overridepublic 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();}}    // 手指滑动检测,来决定viewgroup是否能滑动@Overridepublic 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);// xDiff 要大于系统设置的这个距离,控件才能移动// xDiff > yDiff 手指是否滑动if (xDiff > mTouchSlop && xDiff > yDiff) {mIsBeingDragged = true;mLastMotionX = x;}break;}return mIsBeingDragged;}// 滑动@Overridepublic boolean onTouchEvent(MotionEvent event) {// 添加速度组件跟踪速度变化,计算出event的瞬时伪速度.再此不使用//if(mVelocityTracker == null)//mVelocityTracker = VelocityTracker.obtain();//mVelocityTracker.addMovement(event);final float x = event.getX();final float y = event.getY();switch (event.getAction()) {case MotionEvent.ACTION_DOWN:// 正在滑动时,强制停止滑动if(!mScroller.isFinished())mScroller.abortAnimation();mLastMotionX = x;mLastMotionY = y;break;case MotionEvent.ACTION_CANCEL:case MotionEvent.ACTION_MOVE:if(mIsBeingDragged){final float disX = mLastMotionX - x;//手指滑动的距离mLastMotionX = x;float oldScroll = getScrollX();     //现有的位置坐标float scrollX = oldScroll + disX;   //要滑动到的坐标// 向右滑,显示左界面if(disX<0 && scrollX<0){// L.i(getClass(), "[ 向右滑,显示左界面  ]");float leftBound  = -leftLayout.getWidth();float rightBound = 0;if(scrollX > rightBound) scrollX = rightBound;if(scrollX < leftBound) scrollX = leftBound;}// 想左滑,显示右界面else if(disX>0 && scrollX>0){// L.i(getClass(), "[ 向左滑,显示右界面  ]");float leftBound  = 0;float rightBound = rightlayout.getWidth();if(scrollX<leftBound) scrollX = leftBound;if(scrollX>rightBound) scrollX = rightBound; }// L.i(getClass(), "scrollTo[scrollX:"+scrollX+"]");// 主要用于滑动和绝对固定,否则会超出左右菜单的边界scrollTo((int) scrollX, getScrollY());}break;case MotionEvent.ACTION_UP:if (mIsBeingDragged) {int oldScroll = getScrollX();int dx = 0;//L.i(getClass(), "ACTION_MOVE[oldScroll:"+oldScroll+",volecityX:"+volecityX+"]");//L.i(getClass(), "ACTION_MOVE[leftLayout.getWidth() / 2:"+leftLayout.getWidth() / 2//+",rightlayout.getWidth() / 2:"+rightlayout.getWidth() / 2+"]"); if(oldScroll < 0){// 显示左边菜单if(oldScroll < -leftLayout.getWidth() / 2  ){  dx = -leftLayout.getWidth() - oldScroll;// L.i(getClass(), "ACTION_MOVE[显示左边菜单]");}// 回归原位else if(oldScroll >= -leftLayout.getWidth() / 2  ){dx = - oldScroll;// L.i(getClass(), "ACTION_MOVE[显示左边菜单    回归原位]");}}// 判断往左滑else{// 显示右边菜单if(oldScroll > rightlayout.getWidth() / 2  ){ dx = rightlayout.getWidth() - oldScroll; // L.i(getClass(), "ACTION_MOVE[显示右边菜单]");} // 回归原位 else if(oldScroll <= rightlayout.getWidth() / 2  ){dx = -oldScroll;// L.i(getClass(), "ACTION_MOVE[显示右边菜单           回归原位]");}}// L.i(getClass(), "ACTION_MOVE[dx:"+dx+"]");// 保证只有三种状态。显示左界面、主界面、右界面中的一种,而不是只显示界面的一半// 移动dx距离smoothScrollTo(dx);clearChildrenCache();}break;} return true;}// ViewGroup 平滑void smoothScrollTo(int dx) {int duration = 500;mScroller.startScroll(getScrollX(), getScrollY(), dx, getScrollY(), duration);invalidate();}// 显示左边菜单public void showLeftView(){// L.i(getClass(), "showLeftView()");int x = getScrollX();int leftWith = leftLayout.getWidth();if(x == 0){// 展开左菜单smoothScrollTo(-leftWith);}//已经展开左菜单了,收缩左菜单else if(x == -leftWith){smoothScrollTo(leftWith);}}// 显示右边菜单public void showRightView(){// L.i(getClass(), "showRightView()");int x = getScrollX();int rightWidth = rightlayout.getWidth();if(x == 0){// 展开右菜单smoothScrollTo(rightWidth);}//已经展开右菜单了,收缩右菜单else if(x == rightWidth){smoothScrollTo(-rightWidth);}}// 设置允许绘制void enableChildrenCache(){int childCount = getChildCount();for(int i=0;i < childCount;i++){final View view = getChildAt(i);view.setDrawingCacheEnabled(true);}}// 设置不允许绘制void clearChildrenCache(){int childCount = getChildCount();for(int i=0;i<childCount;i++){final View view = getChildAt(i);view.setDrawingCacheEnabled(false);}}public View getLeftLayout() {return leftLayout;}public void setLeftLayout(View leftLayout) {this.leftLayout = leftLayout;}public View getRightlayout() {return rightlayout;}public void setRightlayout(View rightlayout) {this.rightlayout = rightlayout;}}

打完收工。see you !


0 0
原创粉丝点击