上篇給大家介紹QQ5.0側滑菜單的視頻課程,對于側滑的時的動畫效果的實現(xiàn)有了新的認識,似乎打通了任督二脈,目前可以實現(xiàn)任意效果的側滑菜單了,感謝鴻洋大大?。?/p>
用的是HorizontalScrollView來實現(xiàn)的側滑菜單功能,HorizontalScrollView的好處是為我們解決了滑動功能,處理了滑動沖突問題,讓我們使用起來非常方便,但是滑動和沖突處理都是android中的難點,是我們應該掌握的知識點,掌握了這些,我們可以不依賴于系統(tǒng)的API,隨心所欲打造我們想要的效果,因此這篇文章我將直接自定義ViewGroup來實現(xiàn)側滑菜單功能
首先我們先來看一看效果圖,第一個效果圖是一個最普通的側滑菜單,我們一會兒會先做出這種側滑菜單,然后再在此基礎上實現(xiàn)另外兩個效果
第一種
第二種
第三種
實現(xiàn)第一種側滑菜單,繼承自ViewGroup
繼承自ViewGroup需要我們自己來測量,布局,實現(xiàn)滑動的效果,處理滑動沖突,這些都是一些新手無從下手的知識點,希望看了這篇文章后可以對大家有一個幫助
自定義ViewGroup的一般思路是重寫onMeasure方法,在onMeasure方法中調(diào)用measureChild來測量子View,然后調(diào)用setMeasuredDimension來測量自己的大小。然后重寫onLayout方法,在onLayout中調(diào)用子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的位置,根據(jù)上面圖可以確定上下左右的坐標mMenu.layout(-mMenuWidth, 0, 0, mScreenHeight);//擺放Content的位置mContent.layout(0, 0, mScreenWidth, mScreenHeight);}/*** 將傳進來的數(shù)轉化為dp*/private int convertToDp(Context context , int num){return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,num,context.getResources().getDisplayMetrics());}}
目前我們的側滑菜單中的兩個子View的位置應該是這個樣子
左側菜單是隱藏在屏幕左側外部的,但是現(xiàn)在還不能滑動,如果想要實現(xiàn)滑動功能,我們可以使用View的scrollTo和scrollBy方法,這兩個方法的區(qū)別是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已經(jīng)完全顯示,再滑動的話//Menu左側就會出現(xiàn)白邊了,進行邊界控制if (getScrollX() + Math.abs(dx) >= 0) {//直接移動到(0,0)位置,不會出現(xiàn)白邊scrollTo(0, 0);} else {//Menu沒有完全顯示呢//其實這里dx還是-dx,大家不用刻意去記//大家可以先使用dx,然后運行一下,發(fā)現(xiàn)//移動的方向是相反的,那么果斷這里加個負號就可以了scrollBy(-dx, 0);}}else{//向右滑動//邊界控制,如果Content已經(jīng)完全顯示,再滑動的話//Content右側就會出現(xiàn)白邊了,進行邊界控制if (getScrollX() - dx <= -mMenuWidth) {//直接移動到(-mMenuWidth,0)位置,不會出現(xiàn)白邊scrollTo(-mMenuWidth, 0);} else {//Content沒有完全顯示呢//根據(jù)手指移動scrollBy(-dx, 0);}}mLastX = currentX;mLastY = currentY;break;}return true;}
現(xiàn)在我們的SlidingMenu依然是不能夠水平滑動的,但是listview可以豎直滑動,原因是我們的SlidingMenu默認是不攔截事件的,那么事件會傳遞給他的子View去執(zhí)行,也就是說傳遞給了Content的ListView去執(zhí)行了,所以listview是可以滑動的,為了簡單,我們先重寫onInterceptTouchEvent方法,我們返回true,讓SlidingMenu攔截事件,我們的SlidingMenu就能夠滑動了,但是ListView是不能滑動的,等下我們會進行滑動沖突的處理,現(xiàn)在先實現(xiàn)SlidingMenu的功能
@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {return true;}
好了,現(xiàn)在我們可以自由的滑動我們的SlidingMenu了,并且進行了很好的邊界控制,現(xiàn)在我們再添加個功能,就是當Menu打開大于二分之一時,松開手指,Menu自動打開。當Menu打開小于二分之一時,松開手指,Menu自動關閉。自動滑動的功能我們要借助Scroller來實現(xiàn)
我們在構造方法中初始化一個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//調(diào)用startScroll方法,第一個參數(shù)是起始X坐標,第二個參數(shù)//是起始Y坐標,第三個參數(shù)是X方向偏移量,第四個參數(shù)是Y方向偏移量mScroller.startScroll(getScrollX(), 0, -mMenuWidth - getScrollX(), 0, 300);//設置一個已經(jīng)打開的標識,當實現(xiàn)點擊開關自動打開關閉功能時會用到isOpen = true;//一定不要忘了調(diào)用這個方法重繪,否則沒有動畫效果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 主站蜘蛛池模板: 婷婷一区二区三区 | 精品中文视频 | 成人午夜网址 | 蜜桃精品视频 | 久久成人激情视频 | 免费国产不卡午夜福在线 | 曰韩毛片 | 成年免费观看视频 | 成人啪啪18免费网站 | 欧美一级片在线 | av播放在线 | 日韩黄色片免费看 | 日韩字幕在线观看 | 亚洲综合视频网站 | av免费在线观看av | 精品成人免费视频 | 亚洲免费在线看 | 免费观看黄色片视频 | 午夜噜噜噜 | 99爱视频在线观看 | 免费高清一级欧美片在线观看 | 一级大片在线观看 | 成人h精品动漫一区二区三区 | 在线a免费观看 | 中文字幕在线观看1 | 曰韩黄色片 | 欧美a级大胆视频 | 色污视频在线观看 | 日韩专区在线 | 青青草成人免费视频在线 | 国产精品999在线 | 日本大片在线播放 | 国产精品午夜未成人免费观看 | 天天艹综合| 久久色网站 | 久久蜜臀一区二区三区av | 免费毛片a线观看 | 国产一级小视频 | av影院在线播放 | 中文字幕网站在线 | 中文字幕在线免费 |