上篇給大家介紹QQ5.0側滑菜單的視頻課程,對于側滑的時的動畫效果的實現有了新的認識,似乎打通了任督二脈,目前可以實現任意效果的側滑菜單了,感謝鴻洋大大!!
用的是HorizontalScrollView來實現的側滑菜單功能,HorizontalScrollView的好處是為我們解決了滑動功能,處理了滑動沖突問題,讓我們使用起來非常方便,但是滑動和沖突處理都是android中的難點,是我們應該掌握的知識點,掌握了這些,我們可以不依賴于系統的API,隨心所欲打造我們想要的效果,因此這篇文章我將直接自定義ViewGroup來實現側滑菜單功能
首先我們先來看一看效果圖,第一個效果圖是一個最普通的側滑菜單,我們一會兒會先做出這種側滑菜單,然后再在此基礎上實現另外兩個效果
第一種
第二種
第三種
實現第一種側滑菜單,繼承自ViewGroup
繼承自ViewGroup需要我們自己來測量,布局,實現滑動的效果,處理滑動沖突,這些都是一些新手無從下手的知識點,希望看了這篇文章后可以對大家有一個幫助
自定義ViewGroup的一般思路是重寫onMeasure方法,在onMeasure方法中調用measureChild來測量子View,然后調用setMeasuredDimension來測量自己的大小。然后重寫onLayout方法,在onLayout中調用子View的layout方法來確定子View的位置,下面我們先來做好這兩件工作
初始時候我們的Content應該是顯示在屏幕中的,而Menu應該是顯示在屏幕外的。當Menu打開時,應該是這種樣子的
mMenuRightPadding是Menu距屏幕右側的一個距離,因為我們Menu打開后,Content還是會留一部分,而不是完全隱藏的
public class MySlidingMenu extends ViewGroup {public MySlidingMenu(Context context) {this(context, null, 0);}public MySlidingMenu(Context context, AttributeSet attrs) {this(context, attrs, 0);}public MySlidingMenu(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);DisplayMetrics metrics = new DisplayMetrics();WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);wm.getDefaultDisplay().getMetrics(metrics);//獲取屏幕的寬和高mScreenWidth = metrics.widthPixels;mScreenHeight = metrics.heightPixels; //設置Menu距離屏幕右側的距離,convertToDp是將代碼中的100轉換成100dpmMenuRightPadding = convertToDp(context,100); }@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {//拿到Menu,Menu是第0個孩子mMenu = (ViewGroup) getChildAt(0);//拿到Content,Content是第1個孩子mContent = (ViewGroup) getChildAt(1);//設置Menu的寬為屏幕的寬度減去Menu距離屏幕右側的距離mMenuWidth = mMenu.getLayoutParams().width = mScreenWidth - mMenuRightPadding;//設置Content的寬為屏幕的寬度mContentWidth = mContent.getLayoutParams().width = mScreenWidth;//測量MenumeasureChild(mMenu,widthMeasureSpec,heightMeasureSpec);//測量ContentmeasureChild(mContent, widthMeasureSpec, heightMeasureSpec);//測量自己,自己的寬度為Menu寬度加上Content寬度,高度為屏幕高度setMeasuredDimension(mMenuWidth + mContentWidth, mScreenHeight);}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {//擺放Menu的位置,根據上面圖可以確定上下左右的坐標mMenu.layout(-mMenuWidth, 0, 0, mScreenHeight);//擺放Content的位置mContent.layout(0, 0, mScreenWidth, mScreenHeight);}/*** 將傳進來的數轉化為dp*/private int convertToDp(Context context , int num){return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,num,context.getResources().getDisplayMetrics());}}
目前我們的側滑菜單中的兩個子View的位置應該是這個樣子
左側菜單是隱藏在屏幕左側外部的,但是現在還不能滑動,如果想要實現滑動功能,我們可以使用View的scrollTo和scrollBy方法,這兩個方法的區別是scrollTo是直接將view移動到指定的位置,scrollBy是相對于當前的位置移動一個偏移量,所以我們應該重寫onTouchEvent方法,用來計算出當前手指的一個偏移量,然后使用scrollBy方法一點一點的移動,就形成了一個可以跟隨手指移動的view的動畫效果了
在寫代碼之前,我們先掃清一下障礙,我們先來弄清楚這些坐標是怎么回事
好了,把這些坐標弄清楚后,我們就簡單多了,下面直接看onTouchEvent方法
@Overridepublic boolean onTouchEvent(MotionEvent event) {int action = event.getAction();switch (action){case MotionEvent.ACTION_DOWN:mLastX = (int) event.getX();mLastY = (int) event.getY();break;case MotionEvent.ACTION_MOVE:int currentX = (int) event.getX();int currentY = (int) event.getY();//拿到x方向的偏移量int dx = currentX - mLastX;if (dx < 0){//向左滑動//邊界控制,如果Menu已經完全顯示,再滑動的話//Menu左側就會出現白邊了,進行邊界控制if (getScrollX() + Math.abs(dx) >= 0) {//直接移動到(0,0)位置,不會出現白邊scrollTo(0, 0);} else {//Menu沒有完全顯示呢//其實這里dx還是-dx,大家不用刻意去記//大家可以先使用dx,然后運行一下,發現//移動的方向是相反的,那么果斷這里加個負號就可以了scrollBy(-dx, 0);}}else{//向右滑動//邊界控制,如果Content已經完全顯示,再滑動的話//Content右側就會出現白邊了,進行邊界控制if (getScrollX() - dx <= -mMenuWidth) {//直接移動到(-mMenuWidth,0)位置,不會出現白邊scrollTo(-mMenuWidth, 0);} else {//Content沒有完全顯示呢//根據手指移動scrollBy(-dx, 0);}}mLastX = currentX;mLastY = currentY;break;}return true;}
現在我們的SlidingMenu依然是不能夠水平滑動的,但是listview可以豎直滑動,原因是我們的SlidingMenu默認是不攔截事件的,那么事件會傳遞給他的子View去執行,也就是說傳遞給了Content的ListView去執行了,所以listview是可以滑動的,為了簡單,我們先重寫onInterceptTouchEvent方法,我們返回true,讓SlidingMenu攔截事件,我們的SlidingMenu就能夠滑動了,但是ListView是不能滑動的,等下我們會進行滑動沖突的處理,現在先實現SlidingMenu的功能
@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {return true;}
好了,現在我們可以自由的滑動我們的SlidingMenu了,并且進行了很好的邊界控制,現在我們再添加個功能,就是當Menu打開大于二分之一時,松開手指,Menu自動打開。當Menu打開小于二分之一時,松開手指,Menu自動關閉。自動滑動的功能我們要借助Scroller來實現
我們在構造方法中初始化一個Scroller
public MySlidingMenu(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);...mScroller = new Scroller(context);...}
然后重寫computeScroll方法,這個方法是保證Scroller自動滑動的必須方法,這是一個模板方法,到哪里都這么些就好了
@Overridepublic void computeScroll() {if (mScroller.computeScrollOffset()){scrollTo(mScroller.getCurrX(), mScroller.getCurrY());invalidate();}}
接著我們在onTouchEvent的ACTION_UP中進行判斷,判斷當前menu打開了多少
case MotionEvent.ACTION_UP:if (getScrollX() < -mMenuWidth / 2){//打開Menu//調用startScroll方法,第一個參數是起始X坐標,第二個參數//是起始Y坐標,第三個參數是X方向偏移量,第四個參數是Y方向偏移量mScroller.startScroll(getScrollX(), 0, -mMenuWidth - getScrollX(), 0, 300);//設置一個已經打開的標識,當實現點擊開關自動打開關閉功能時會用到isOpen = true;//一定不要忘了調用這個方法重繪,否則沒有動畫效果invalidate();}else{//關閉Menu//同上mScroller.startScroll(getScrollX(), 0, -getScrollX(), 0, 300);isOpen = false;invalidate();}break;
關于startScroll中的startX和startY好判斷,那么dx和dy怎么計算呢?其實也非常簡單,比如我們startX坐標為30,我們想移動到-100,那么startX+dx = -100 主站蜘蛛池模板: 日本在线一区二区三区 | 精品成人一区二区 | 欧美精品在线一区二区三区 | 久久久久久久久久久九 | 嫩草久久 | 国产成人一区二区三区 | 成人av自拍| 偷拍呻吟高潮91 | 三级视频在线观看 | 九九久久久 | 高清在线一区二区 | 美女逼网站 | 欧美日韩综合精品 | 一区二区三区免费看 | 亚洲免费人成在线视频观看 | 欧美一级黄色片 | 国产99久| 久久精品一区二区 | 精品久久99 | 亚洲区在线 | 精品一区av| 久久国产精品免费视频 | 九九九久久国产免费 | av免费网站在线观看 | 中文字幕第6页 | 国产真实精品久久二三区 | 欧美久久精品 | 久久国产精品一区二区三区 | 在线视频 欧美日韩 | 亚洲成人一二区 | 欧美不卡在线 | 国产欧美精品一区二区三区四区 | 亚洲高清av在线 | 伊人精品视频在线观看 | 97在线播放| 精品1区| 超碰偷拍 | 自拍偷拍专区 | 日韩国产在线观看 | а天堂中文最新一区二区三区 | 日韩中文视频 |