高仿QQHD mini左右滑动菜单栏效果

来源:互联网 发布:rar在mac怎么打开 编辑:程序博客网 时间:2024/06/05 04:03

首先来看看几张效果图:

1.进入程序时,首先显示中间菜单,即QQHD mini的最近会话列表。


2.向左滑动,或者点击左上角图标,可以展开左边菜单栏,即QQHD mini的好友列表,有动画效果。


3.向右滑动或者点击右上角图标,可以展开右边菜单,即QQHD mini的设置之类的布局,这里我放了一个自定义view,作为例子。



下面让我们来看看最重要的那个自定义view的源码:

[java] view plaincopy
  1. /** 
  2.  * 可左右切换菜单栏的LinearLayout 
  3.  *  
  4.  * @author way 
  5.  *  
  6.  */  
  7. public class CenterLayout extends LinearLayout {  
  8.   
  9.     private final static String TAG = "CenterLayout";  
  10.   
  11.     public static final int LEFT = 0x001;// 当前显示左菜单栏  
  12.   
  13.     public static final int RIGHT = 0x002;// 当前显示右菜单栏  
  14.   
  15.     public static final int MIDDLE = 0x000;// 当前显示中间主界面  
  16.   
  17.     private int mCurState = MIDDLE;// 当前显示的view  
  18.   
  19.     public final int MENU_border_Width = 50;// 边栏宽度  
  20.   
  21.     private Scroller mScroller;  
  22.   
  23.     private LinearLayout leftLayout, rightLayout, childLayout;  
  24.   
  25.     private Context context;  
  26.   
  27.     private boolean fling;  
  28.   
  29.     private boolean mIsBeingDragged = false;  
  30.   
  31.     private int mTouchSlop;  
  32.     /** 
  33.      * Position of the last motion event. 
  34.      */  
  35.     private float mLastMotionX, mLastMotionY;  
  36.   
  37.     /** 
  38.      * ID of the active pointer. This is used to retain consistency during 
  39.      * drags/flings if multiple pointers are used. 
  40.      */  
  41.     private int mActivePointerId = INVALID_POINTER;  
  42.   
  43.     /** 
  44.      * Sentinel value for no current active pointer. Used by 
  45.      * {@link #mActivePointerId}. 
  46.      */  
  47.     private static final int INVALID_POINTER = -1;  
  48.   
  49.     int menuWidth = 0;  
  50.     int moveWidth = 0;  
  51.   
  52.     // 3个构造器  
  53.     public CenterLayout(Context context, AttributeSet attrs) {  
  54.         super(context, attrs);  
  55.         initView(context);  
  56.     }  
  57.   
  58.     public CenterLayout(Context context) {  
  59.         super(context);  
  60.         initView(context);  
  61.     }  
  62.   
  63.     public Scroller getScroller() {  
  64.         return mScroller;  
  65.     }  
  66.   
  67.     // 初始化view  
  68.     public void initView(Context context) {  
  69.         this.context = context;  
  70.         this.menuWidth = MENU_border_Width;  
  71.         this.mScroller = new Scroller(context, AnimationUtils.loadInterpolator(  
  72.                 context, android.R.anim.overshoot_interpolator));  
  73.   
  74.         final ViewConfiguration configuration = ViewConfiguration.get(context);  
  75.         mTouchSlop = configuration.getScaledTouchSlop();  
  76.         mCurState = MIDDLE;// 初始化默认状态  
  77.     }  
  78.   
  79.     /** 
  80.      * 获取屏幕宽度 
  81.      *  
  82.      * @param context 
  83.      * @return 
  84.      */  
  85.     private int getViewWidthInPix(Context context) {  
  86.         int viewWidthInPix = -1;  
  87.         if (viewWidthInPix == -1) {  
  88.             WindowManager manager = (WindowManager) context  
  89.                     .getSystemService(Context.WINDOW_SERVICE);  
  90.             viewWidthInPix = manager.getDefaultDisplay().getWidth();  
  91.         }  
  92.         return viewWidthInPix;  
  93.     }  
  94.   
  95.     @Override  
  96.     protected void onLayout(boolean changed, int left, int top, int right,  
  97.             int bottom) {  
  98.         super.onLayout(changed, left, top, right, bottom);  
  99.   
  100.         for (int i = 0; i < getChildCount(); i++) {  
  101.             View child = getChildAt(i);  
  102.             child.layout(child.getLeft() + moveWidth, child.getTop(),  
  103.                     child.getRight() + moveWidth, child.getBottom());  
  104.         }  
  105.   
  106.     }  
  107.   
  108.     @Override  
  109.     public void computeScroll() {  
  110.         if (mScroller.computeScrollOffset()) {  
  111.             scrollTo(mScroller.getCurrX(), 0);  
  112.             postInvalidate();  
  113.         }  
  114.     }  
  115.   
  116.     @Override  
  117.     public boolean onInterceptTouchEvent(MotionEvent ev) {  
  118.         // TODO Auto-generated method stub  
  119.         // Log.i(TAG, "onInterceptTouchEvent------>" + ev.getAction());  
  120.         final int action = ev.getAction();  
  121.         if ((action == MotionEvent.ACTION_MOVE) && (mIsBeingDragged)) {  
  122.             return true;// 拦截不传递给child view  
  123.         }  
  124.   
  125.         switch (action & MotionEvent.ACTION_MASK) {  
  126.         case MotionEvent.ACTION_DOWN: {  
  127.             final float x = ev.getX();  
  128.             final float y = ev.getY();  
  129.             if (!inChild((int) x, (int) y)) {  
  130.                 mIsBeingDragged = false;  
  131.                 break;  
  132.                 // 超出边界,return false传递给子view处理  
  133.             }  
  134.   
  135.             /* 
  136.              * Remember location of down touch. ACTION_DOWN always refers to 
  137.              * pointer index 0. 
  138.              */  
  139.             mLastMotionX = x;  
  140.             mLastMotionY = y;  
  141.             mActivePointerId = ev.getPointerId(0);  
  142.   
  143.             /* 
  144.              * If being flinged and user touches the screen, initiate drag; 
  145.              * otherwise don't. mScroller.isFinished should be false when being 
  146.              * flinged. 
  147.              */  
  148.             mIsBeingDragged = !mScroller.isFinished();  
  149.             break;  
  150.         }  
  151.         case MotionEvent.ACTION_MOVE: {  
  152.             /* 
  153.              * mIsBeingDragged == false, otherwise the shortcut would have 
  154.              * caught it. Check whether the user has moved far enough from his 
  155.              * original down touch. 
  156.              */  
  157.   
  158.             /* 
  159.              * Locally do absolute value. mLastMotionY is set to the y value of 
  160.              * the down event. 
  161.              */  
  162.             final int activePointerId = mActivePointerId;  
  163.             if (activePointerId == INVALID_POINTER) {  
  164.                 // If we don't have a valid id, the touch down wasn't on  
  165.                 // content.  
  166.                 break;  
  167.             }  
  168.   
  169.             final int pointerIndex = ev.findPointerIndex(activePointerId);  
  170.             final float x = ev.getX(pointerIndex);  
  171.             final float y = ev.getY(pointerIndex);  
  172.             final int xDiff = (int) Math.abs(x - mLastMotionX);  
  173.             final int yDiff = (int) Math.abs(y - mLastMotionY);  
  174.             if (xDiff > mTouchSlop && yDiff < xDiff) {  
  175.                 mIsBeingDragged = true;  
  176.             }  
  177.             break;  
  178.         }  
  179.         case MotionEvent.ACTION_CANCEL:  
  180.         case MotionEvent.ACTION_UP:  
  181.             mIsBeingDragged = false;  
  182.             mActivePointerId = INVALID_POINTER;  
  183.             scrollToScreen();  
  184.             break;  
  185.         }  
  186.         return mIsBeingDragged;  
  187.     }  
  188.   
  189.     @Override  
  190.     public boolean onTouchEvent(MotionEvent event) {  
  191.   
  192.         // Log.i(TAG, "onTouchEvent ---->>>>>" + event.getAction());  
  193.         if (event.getAction() == MotionEvent.ACTION_DOWN  
  194.                 && !inChild((int) event.getX(), (int) event.getY())) {  
  195.             // Don't handle edge touches immediately -- they may actually belong  
  196.             // to one of our  
  197.             // descendants.  
  198.             return false;  
  199.         }  
  200.   
  201.         switch (event.getAction() & MotionEvent.ACTION_MASK) {  
  202.         case MotionEvent.ACTION_DOWN:  
  203.             return true// 本VIEW消化掉  
  204.   
  205.         case MotionEvent.ACTION_MOVE:  
  206.             final int activePointerIndex = event  
  207.                     .findPointerIndex(mActivePointerId);  
  208.   
  209.             final float x = event.getX(activePointerIndex);  
  210.             final float y = event.getY(activePointerIndex);  
  211.   
  212.             final int distanceX = (int/* Math.abs */-(x - mLastMotionX);  
  213.   
  214.             // 在滑动过程中,就需要显示新的brotherView,不然显示的还是之前的brotherView,最后松开手时会突然变称新brotherView,影响体验  
  215.             if (distanceX < 0 && getScrollX() < 0 && leftLayout != null) {  
  216.                 setBrotherVisibility(LEFT);  
  217.             } else if (distanceX > 0 && getScrollX() > 0 && rightLayout != null) {  
  218.                 setBrotherVisibility(RIGHT);  
  219.             } else {  
  220.                 setBrotherVisibility(MIDDLE);  
  221.             }  
  222.   
  223.             scrollBy((int) distanceX, 0);  
  224.   
  225.             mLastMotionX = x;  
  226.             mLastMotionY = y;  
  227.             break;  
  228.   
  229.         case MotionEvent.ACTION_UP:  
  230.             mIsBeingDragged = false;  
  231.             mActivePointerId = INVALID_POINTER;  
  232.             scrollToScreen();  
  233.             break;  
  234.   
  235.         default:  
  236.             return super.onTouchEvent(event);  
  237.         }  
  238.         return mIsBeingDragged;  
  239.   
  240.     }  
  241.   
  242.     @Override  
  243.     protected void onScrollChanged(int l, int t, int oldl, int oldt) {  
  244.         // TODO Auto-generated method stub  
  245.         super.onScrollChanged(l, t, oldl, oldt);  
  246.     }  
  247.   
  248.     private void scrollToScreen() {  
  249.   
  250.         int scrollDistance = 0;  
  251.   
  252.         if (Math.abs(getScrollX()) > getWidth() / 2)  
  253.             scrollDistance = (getScrollX() > 0) ? getWidth() - menuWidth  
  254.                     - getScrollX() : -(getWidth() - menuWidth - Math  
  255.                     .abs(getScrollX()));  
  256.         else  
  257.             scrollDistance = -getScrollX();  
  258.   
  259.         int distance = scrollDistance + getScrollX();  
  260.         Log.i(TAG, " distance = " + distance);  
  261.         if (distance > 0) {  
  262.             mCurState = RIGHT;  
  263.         } else if (distance < 0) {  
  264.             mCurState = LEFT;  
  265.         } else {  
  266.             mCurState = MIDDLE;  
  267.         }  
  268.         mScroller.startScroll(getScrollX(), 0, scrollDistance, 0,  
  269.                 Math.abs(scrollDistance) * 2);  
  270.         invalidate();  
  271.   
  272.     }  
  273.   
  274.     public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,  
  275.             float velocityY) {  
  276.         if (Math.abs(velocityX) > ViewConfiguration.get(context)  
  277.                 .getScaledMinimumFlingVelocity()) {  
  278.             fling = true;  
  279.             scrollToScreen();  
  280.         }  
  281.   
  282.         return fling;  
  283.     }  
  284.   
  285.     private boolean inChild(int x, int y) {  
  286.         if (getChildCount() > 0) {  
  287.             final int scrollX = mScroller.getCurrX();  
  288.             final View child = getChildAt(0);  
  289.   
  290.             return !(scrollX + x < 0 || scrollX + x > getWidth() || y < 0 || y > getHeight());  
  291.   
  292.         }  
  293.         return false;  
  294.     }  
  295.   
  296.     /** 
  297.      * 设置当前显示的view 
  298.      *  
  299.      * @param whichpg 
  300.      */  
  301.     public void setPage(int whichpg) {  
  302.         int targetX = 0, moveDistance = 0;  
  303.   
  304.         if (whichpg == LEFT) {  
  305.             targetX = -(getViewWidthInPix(context) - menuWidth);  
  306.             mCurState = LEFT;  
  307.         } else if (whichpg == RIGHT) {  
  308.             targetX = getViewWidthInPix(context) - menuWidth;  
  309.             mCurState = RIGHT;  
  310.         } else {  
  311.             mCurState = MIDDLE;  
  312.         }  
  313.         setBrotherVisibility(whichpg);  
  314.         moveDistance = targetX - getScrollX();  
  315.         mScroller.startScroll(getScrollX(), 0, moveDistance, 0,  
  316.                 Math.abs(moveDistance) * 2);  
  317.         invalidate();  
  318.     }  
  319.   
  320.     /** 
  321.      * 返回当前显示的view 
  322.      *  
  323.      * @return 
  324.      */  
  325.     public int getPage() {  
  326.         return mCurState;  
  327.     }  
  328.   
  329.     public void addChildView(View child) {  
  330.         this.childLayout.addView(child);  
  331.     }  
  332.   
  333.     /** 
  334.      * 设置BrotherView 
  335.      *  
  336.      * @param left 
  337.      * @param right 
  338.      */  
  339.     public void setBrotherLayout(LinearLayout left, LinearLayout right) {  
  340.         this.leftLayout = left;  
  341.         this.rightLayout = right;  
  342.     }  
  343.   
  344.     /** 
  345.      * 根据当前状态显示或隐藏view 
  346.      *  
  347.      * @param state 
  348.      */  
  349.     private void setBrotherVisibility(int state) {  
  350.         switch (state) {  
  351.         case LEFT:  
  352.             rightLayout.setVisibility(View.GONE);  
  353.             leftLayout.setVisibility(View.VISIBLE);  
  354.             break;  
  355.         case RIGHT:  
  356.             rightLayout.setVisibility(View.VISIBLE);  
  357.             leftLayout.setVisibility(View.GONE);  
  358.             break;  
  359.         case MIDDLE:  
  360.             break;  
  361.         default:  
  362.             break;  
  363.         }  
  364.     }  
  365. }  

好了,源码地址:http://download.csdn.net/detail/weidi1989/5320596
0 0
原创粉丝点击