一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

Android滑動(dòng)菜單特效實(shí)現(xiàn),側(cè)滑菜單實(shí)現(xiàn)

 JUST SO LAZY 2013-09-06

人人客戶端有一個(gè)特效還是挺吸引人的,在主界面手指向右滑動(dòng),就可以將菜單展示出來,而主界面會(huì)被隱藏大部分,但是仍有左側(cè)的一小部分同菜單一起展示。

據(jù)說人人客戶端的這個(gè)特效是從facebook客戶端模仿來的,至于facebook是不是又從其它地方模仿來的就不得而知了。好,今天我們就一起來實(shí)現(xiàn)這個(gè)效果,總之我第一次看到這個(gè)特效是在人人客戶端看到的,我也就主觀性地認(rèn)為我是在模仿人人客戶端的特效了。

雖然現(xiàn)在網(wǎng)上類似這種效果的實(shí)現(xiàn)也非常多,可是我發(fā)現(xiàn)實(shí)現(xiàn)方案大都非常復(fù)雜,并不容易理解。但其實(shí)這種效果并不難實(shí)現(xiàn),因此我今天給大家?guī)淼囊彩鞘飞献詈?jiǎn)單的滑動(dòng)菜單實(shí)現(xiàn)方案。

首先還是講一下實(shí)現(xiàn)原理。在一個(gè)Activity的布局中需要有兩部分,一個(gè)是菜單(menu)的布局,一個(gè)是內(nèi)容(content)的布局。兩個(gè)布局橫向排列,菜單布局在左,內(nèi)容布局在右。初始化的時(shí)候?qū)⒉藛尾季窒蜃笃?,以至于能夠完全隱藏,這樣內(nèi)容布局就會(huì)完全顯示在Activity中。然后通過監(jiān)聽手指滑動(dòng)事件,來改變菜單布局的左偏移距離,從而控制菜單布局的顯示和隱藏。原理圖如下:

將菜單布局的左偏移值改成0時(shí),效果圖如下:

好,我們開始用代碼來實(shí)現(xiàn)。首先在Eclipse中新建一個(gè)Android項(xiàng)目,項(xiàng)目名就叫做RenRenSlideMenuDemo。然后寫一下布局文件,創(chuàng)建或打開layout目錄下的activity_main.xml文件,加入如下代碼:

  1. <LinearLayout xmlns:android="http://droid.com/apk/res/android"  
  2.     xmlns:tools="http://droid.com/tools"  
  3.     android:layout_width="fill_parent"  
  4.     android:layout_height="fill_parent"  
  5.     android:orientation="horizontal"  
  6.     tools:context=".MainActivity" >  
  7.   
  8.     <LinearLayout  
  9.         android:id="@ id/menu"  
  10.         android:layout_width="fill_parent"  
  11.         android:layout_height="fill_parent"  
  12.         android:background="@drawable/menu" >  
  13.     </LinearLayout>  
  14.   
  15.     <LinearLayout  
  16.         android:id="@ id/content"  
  17.         android:layout_width="fill_parent"  
  18.         android:layout_height="fill_parent"  
  19.         android:background="@drawable/content" >  
  20.     </LinearLayout>  
  21.   
  22. </LinearLayout>  

這個(gè)布局文件的最外層布局是一個(gè)LinearLayout,排列方向是水平方向排列。這個(gè)LinearLayout下面嵌套了兩個(gè)子LinearLayout,分別就是菜單的布局和內(nèi)容的布局。這里為了要讓布局盡量簡(jiǎn)單,菜單布局和內(nèi)容布局里面沒有加入任何控件,只是給這兩個(gè)布局各添加了一張背景圖片,這兩張背景圖片是我從人人客戶端上截下來的圖。這樣我們可以把注意力都集中在如何實(shí)現(xiàn)滑動(dòng)菜單的效果上面,不用關(guān)心里面各種復(fù)雜的布局了。

 

創(chuàng)建或打開MainActivity,這個(gè)類仍然是程序的主Activity,也是這次demo唯一的Activity,在里面加入如下代碼:

  1. public class MainActivity extends Activity implements OnTouchListener {  
  2.   
  3.     /** 
  4.      * 滾動(dòng)顯示和隱藏menu時(shí),手指滑動(dòng)需要達(dá)到的速度。 
  5.      */  
  6.     public static final int SNAP_VELOCITY = 200;  
  7.   
  8.     /** 
  9.      * 屏幕寬度值。 
  10.      */  
  11.     private int screenWidth;  
  12.   
  13.     /** 
  14.      * menu最多可以滑動(dòng)到的左邊緣。值由menu布局的寬度來定,marginLeft到達(dá)此值之后,不能再減少。 
  15.      */  
  16.     private int leftEdge;  
  17.   
  18.     /** 
  19.      * menu最多可以滑動(dòng)到的右邊緣。值恒為0,即marginLeft到達(dá)0之后,不能增加。 
  20.      */  
  21.     private int rightEdge = 0;  
  22.   
  23.     /** 
  24.      * menu完全顯示時(shí),留給content的寬度值。 
  25.      */  
  26.     private int menuPadding = 80;  
  27.   
  28.     /** 
  29.      * 主內(nèi)容的布局。 
  30.      */  
  31.     private View content;  
  32.   
  33.     /** 
  34.      * menu的布局。 
  35.      */  
  36.     private View menu;  
  37.   
  38.     /** 
  39.      * menu布局的參數(shù),通過此參數(shù)來更改leftMargin的值。 
  40.      */  
  41.     private LinearLayout.LayoutParams menuParams;  
  42.   
  43.     /** 
  44.      * 記錄手指按下時(shí)的橫坐標(biāo)。 
  45.      */  
  46.     private float xDown;  
  47.   
  48.     /** 
  49.      * 記錄手指移動(dòng)時(shí)的橫坐標(biāo)。 
  50.      */  
  51.     private float xMove;  
  52.   
  53.     /** 
  54.      * 記錄手機(jī)抬起時(shí)的橫坐標(biāo)。 
  55.      */  
  56.     private float xUp;  
  57.   
  58.     /** 
  59.      * menu當(dāng)前是顯示還是隱藏。只有完全顯示或隱藏menu時(shí)才會(huì)更改此值,滑動(dòng)過程中此值無效。 
  60.      */  
  61.     private boolean isMenuVisible;  
  62.   
  63.     /** 
  64.      * 用于計(jì)算手指滑動(dòng)的速度。 
  65.      */  
  66.     private VelocityTracker mVelocityTracker;  
  67.   
  68.     @Override  
  69.     protected void onCreate(Bundle savedInstanceState) {  
  70.         super.onCreate(savedInstanceState);  
  71.         setContentView(R.layout.activity_main);  
  72.         initValues();  
  73.         content.setOnTouchListener(this);  
  74.     }  
  75.   
  76.     /** 
  77.      * 初始化一些關(guān)鍵性數(shù)據(jù)。包括獲取屏幕的寬度,給content布局重新設(shè)置寬度,給menu布局重新設(shè)置寬度和偏移距離等。 
  78.      */  
  79.     private void initValues() {  
  80.         WindowManager window = (WindowManager) getSystemService(Context.WINDOW_SERVICE);  
  81.         screenWidth = window.getDefaultDisplay().getWidth();  
  82.         content = findViewById(R.id.content);  
  83.         menu = findViewById(R.id.menu);  
  84.         menuParams = (LinearLayout.LayoutParams) menu.getLayoutParams();  
  85.         // 將menu的寬度設(shè)置為屏幕寬度減去menuPadding  
  86.         menuParams.width = screenWidth - menuPadding;  
  87.         // 左邊緣的值賦值為menu寬度的負(fù)數(shù)  
  88.         leftEdge = -menuParams.width;  
  89.         // menu的leftMargin設(shè)置為左邊緣的值,這樣初始化時(shí)menu就變?yōu)椴豢梢?/span>  
  90.         menuParams.leftMargin = leftEdge;  
  91.         // 將content的寬度設(shè)置為屏幕寬度  
  92.         content.getLayoutParams().width = screenWidth;  
  93.     }  
  94.   
  95.     @Override  
  96.     public boolean onTouch(View v, MotionEvent event) {  
  97.         createVelocityTracker(event);  
  98.         switch (event.getAction()) {  
  99.         case MotionEvent.ACTION_DOWN:  
  100.             // 手指按下時(shí),記錄按下時(shí)的橫坐標(biāo)  
  101.             xDown = event.getRawX();  
  102.             break;  
  103.         case MotionEvent.ACTION_MOVE:  
  104.             // 手指移動(dòng)時(shí),對(duì)比按下時(shí)的橫坐標(biāo),計(jì)算出移動(dòng)的距離,來調(diào)整menu的leftMargin值,從而顯示和隱藏menu  
  105.             xMove = event.getRawX();  
  106.             int distanceX = (int) (xMove - xDown);  
  107.             if (isMenuVisible) {  
  108.                 menuParams.leftMargin = distanceX;  
  109.             } else {  
  110.                 menuParams.leftMargin = leftEdge   distanceX;  
  111.             }  
  112.             if (menuParams.leftMargin < leftEdge) {  
  113.                 menuParams.leftMargin = leftEdge;  
  114.             } else if (menuParams.leftMargin > rightEdge) {  
  115.                 menuParams.leftMargin = rightEdge;  
  116.             }  
  117.             menu.setLayoutParams(menuParams);  
  118.             break;  
  119.         case MotionEvent.ACTION_UP:  
  120.             // 手指抬起時(shí),進(jìn)行判斷當(dāng)前手勢(shì)的意圖,從而決定是滾動(dòng)到menu界面,還是滾動(dòng)到content界面  
  121.             xUp = event.getRawX();  
  122.             if (wantToShowMenu()) {  
  123.                 if (shouldScrollToMenu()) {  
  124.                     scrollToMenu();  
  125.                 } else {  
  126.                     scrollToContent();  
  127.                 }  
  128.             } else if (wantToShowContent()) {  
  129.                 if (shouldScrollToContent()) {  
  130.                     scrollToContent();  
  131.                 } else {  
  132.                     scrollToMenu();  
  133.                 }  
  134.             }  
  135.             recycleVelocityTracker();  
  136.             break;  
  137.         }  
  138.         return true;  
  139.     }  
  140.   
  141.     /** 
  142.      * 判斷當(dāng)前手勢(shì)的意圖是不是想顯示content。如果手指移動(dòng)的距離是負(fù)數(shù),且當(dāng)前menu是可見的,則認(rèn)為當(dāng)前手勢(shì)是想要顯示content。 
  143.      *  
  144.      * @return 當(dāng)前手勢(shì)想顯示content返回true,否則返回false。 
  145.      */  
  146.     private boolean wantToShowContent() {  
  147.         return xUp - xDown < 0 && isMenuVisible;  
  148.     }  
  149.   
  150.     /** 
  151.      * 判斷當(dāng)前手勢(shì)的意圖是不是想顯示menu。如果手指移動(dòng)的距離是正數(shù),且當(dāng)前menu是不可見的,則認(rèn)為當(dāng)前手勢(shì)是想要顯示menu。 
  152.      *  
  153.      * @return 當(dāng)前手勢(shì)想顯示menu返回true,否則返回false。 
  154.      */  
  155.     private boolean wantToShowMenu() {  
  156.         return xUp - xDown > 0 && !isMenuVisible;  
  157.     }  
  158.   
  159.     /** 
  160.      * 判斷是否應(yīng)該滾動(dòng)將menu展示出來。如果手指移動(dòng)距離大于屏幕的1/2,或者手指移動(dòng)速度大于SNAP_VELOCITY, 
  161.      * 就認(rèn)為應(yīng)該滾動(dòng)將menu展示出來。 
  162.      *  
  163.      * @return 如果應(yīng)該滾動(dòng)將menu展示出來返回true,否則返回false。 
  164.      */  
  165.     private boolean shouldScrollToMenu() {  
  166.         return xUp - xDown > screenWidth / 2 || getScrollVelocity() > SNAP_VELOCITY;  
  167.     }  
  168.   
  169.     /** 
  170.      * 判斷是否應(yīng)該滾動(dòng)將content展示出來。如果手指移動(dòng)距離加上menuPadding大于屏幕的1/2, 
  171.      * 或者手指移動(dòng)速度大于SNAP_VELOCITY, 就認(rèn)為應(yīng)該滾動(dòng)將content展示出來。 
  172.      *  
  173.      * @return 如果應(yīng)該滾動(dòng)將content展示出來返回true,否則返回false。 
  174.      */  
  175.     private boolean shouldScrollToContent() {  
  176.         return xDown - xUp   menuPadding > screenWidth / 2 || getScrollVelocity() > SNAP_VELOCITY;  
  177.     }  
  178.   
  179.     /** 
  180.      * 將屏幕滾動(dòng)到menu界面,滾動(dòng)速度設(shè)定為30. 
  181.      */  
  182.     private void scrollToMenu() {  
  183.         new ScrollTask().execute(30);  
  184.     }  
  185.   
  186.     /** 
  187.      * 將屏幕滾動(dòng)到content界面,滾動(dòng)速度設(shè)定為-30. 
  188.      */  
  189.     private void scrollToContent() {  
  190.         new ScrollTask().execute(-30);  
  191.     }  
  192.   
  193.     /** 
  194.      * 創(chuàng)建VelocityTracker對(duì)象,并將觸摸content界面的滑動(dòng)事件加入到VelocityTracker當(dāng)中。 
  195.      *  
  196.      * @param event 
  197.      *            content界面的滑動(dòng)事件 
  198.      */  
  199.     private void createVelocityTracker(MotionEvent event) {  
  200.         if (mVelocityTracker == null) {  
  201.             mVelocityTracker = VelocityTracker.obtain();  
  202.         }  
  203.         mVelocityTracker.addMovement(event);  
  204.     }  
  205.   
  206.     /** 
  207.      * 獲取手指在content界面滑動(dòng)的速度。 
  208.      *  
  209.      * @return 滑動(dòng)速度,以每秒鐘移動(dòng)了多少像素值為單位。 
  210.      */  
  211.     private int getScrollVelocity() {  
  212.         mVelocityTracker.computeCurrentVelocity(1000);  
  213.         int velocity = (int) mVelocityTracker.getXVelocity();  
  214.         return Math.abs(velocity);  
  215.     }  
  216.   
  217.     /** 
  218.      * 回收VelocityTracker對(duì)象。 
  219.      */  
  220.     private void recycleVelocityTracker() {  
  221.         mVelocityTracker.recycle();  
  222.         mVelocityTracker = null;  
  223.     }  
  224.   
  225.     class ScrollTask extends AsyncTask<Integer, Integer, Integer> {  
  226.   
  227.         @Override  
  228.         protected Integer doInBackground(Integer... speed) {  
  229.             int leftMargin = menuParams.leftMargin;  
  230.             // 根據(jù)傳入的速度來滾動(dòng)界面,當(dāng)滾動(dòng)到達(dá)左邊界或右邊界時(shí),跳出循環(huán)。  
  231.             while (true) {  
  232.                 leftMargin = leftMargin   speed[0];  
  233.                 if (leftMargin > rightEdge) {  
  234.                     leftMargin = rightEdge;  
  235.                     break;  
  236.                 }  
  237.                 if (leftMargin < leftEdge) {  
  238.                     leftMargin = leftEdge;  
  239.                     break;  
  240.                 }  
  241.                 publishProgress(leftMargin);  
  242.                 // 為了要有滾動(dòng)效果產(chǎn)生,每次循環(huán)使線程睡眠20毫秒,這樣肉眼才能夠看到滾動(dòng)動(dòng)畫。  
  243.                 sleep(20);  
  244.             }  
  245.             if (speed[0] > 0) {  
  246.                 isMenuVisible = true;  
  247.             } else {  
  248.                 isMenuVisible = false;  
  249.             }  
  250.             return leftMargin;  
  251.         }  
  252.   
  253.         @Override  
  254.         protected void onProgressUpdate(Integer... leftMargin) {  
  255.             menuParams.leftMargin = leftMargin[0];  
  256.             menu.setLayoutParams(menuParams);  
  257.         }  
  258.   
  259.         @Override  
  260.         protected void onPostExecute(Integer leftMargin) {  
  261.             menuParams.leftMargin = leftMargin;  
  262.             menu.setLayoutParams(menuParams);  
  263.         }  
  264.     }  
  265.   
  266.     /** 
  267.      * 使當(dāng)前線程睡眠指定的毫秒數(shù)。 
  268.      *  
  269.      * @param millis 
  270.      *            指定當(dāng)前線程睡眠多久,以毫秒為單位 
  271.      */  
  272.     private void sleep(long millis) {  
  273.         try {  
  274.             Thread.sleep(millis);  
  275.         } catch (InterruptedException e) {  
  276.             e.printStackTrace();  
  277.         }  
  278.     }  
  279. }  

全部的代碼都在這里了,我們可以看到,加上注釋總共才兩百多行的代碼就能實(shí)現(xiàn)滑動(dòng)菜單的特效。下面我來對(duì)以上代碼解釋一下,首先初始化的時(shí)候調(diào)用initValues方法,在這里面將內(nèi)容布局的寬度設(shè)定為屏幕的寬度,菜單布局的寬度設(shè)定為屏幕的寬度減去menuPadding值,這樣可以保證在菜單布局展示的時(shí)候,仍有一部分內(nèi)容布局可以看到。如果不在初始化的時(shí)候重定義兩個(gè)布局寬度,就會(huì)按照layout文件里面聲明的一樣,兩個(gè)布局都是fill_parent,這樣就無法實(shí)現(xiàn)滑動(dòng)菜單的效果了。然后將菜單布局的左偏移量設(shè)置為負(fù)的菜單布局的寬度,這樣菜單布局就會(huì)被完全隱藏,只有內(nèi)容布局會(huì)顯示在界面上。

之后給內(nèi)容布局注冊(cè)監(jiān)聽事件,這樣當(dāng)手指在內(nèi)容布局上滑動(dòng)的時(shí)候就會(huì)觸發(fā)onTouch事件。在onTouch事件里面,根據(jù)手指滑動(dòng)的距離會(huì)改變菜單布局的左偏移量,從而控制菜單布局的顯示和隱藏。當(dāng)手指離開屏幕的時(shí)候,會(huì)判斷應(yīng)該滑動(dòng)到菜單布局還是內(nèi)容布局,判斷依據(jù)是根據(jù)手指滑動(dòng)的距離或者滑動(dòng)的速度,細(xì)節(jié)可以看代碼中的注釋。

最后還是給出AndroidManifest.xml的代碼,都是自動(dòng)生成的,非常簡(jiǎn)單:

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://droid.com/apk/res/android"  
  3.     package="com.example.renrenslidemenudemo"  
  4.     android:versionCode="1"  
  5.     android:versionName="1.0" >  
  6.   
  7.     <uses-sdk  
  8.         android:minSdkVersion="8"  
  9.         android:targetSdkVersion="8" />  
  10.   
  11.     <application  
  12.         android:allowBackup="true"  
  13.         android:icon="@drawable/ic_launcher"  
  14.         android:label="@string/app_name"  
  15.         android:theme="@android:style/Theme.NoTitleBar" >  
  16.         <activity  
  17.             android:name="com.example.renrenslidemenudemo.MainActivity"  
  18.             android:label="@string/app_name" >  
  19.             <intent-filter>  
  20.                 <action android:name="android.intent.action.MAIN" />  
  21.   
  22.                 <category android:name="android.intent.category.LAUNCHER" />  
  23.             </intent-filter>  
  24.         </activity>  
  25.     </application>  
  26.   
  27. </manifest>  

好了,現(xiàn)在我們運(yùn)行一下,看一下效果吧,首先是程序剛打開的時(shí)候,顯示的是內(nèi)容布局。用手指在界面向右滑動(dòng),可以看到菜單布局出現(xiàn)。

                             

而當(dāng)菜單布局完全展示的時(shí)候,效果如下圖:

                                 

 


 

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    欧美日韩乱一区二区三区| 中文字幕精品少妇人妻| 99视频精品免费视频播放| 精品久久少妇激情视频| 日本午夜免费福利视频| 高清免费在线不卡视频| 国产白丝粉嫩av在线免费观看| 国产精品一区二区有码| 果冻传媒在线观看免费高清| 后入美臀少妇一区二区| 国产日本欧美特黄在线观看| 午夜久久久精品国产精品| 日本午夜免费啪视频在线| 91久久精品中文内射| 成人精品视频在线观看不卡| 成人你懂的在线免费视频| 亚洲视频在线观看免费中文字幕 | 久久三级国外久久久三级| 久久精品国产亚洲av麻豆| 91午夜少妇极品福利| 久久精品国产亚洲av麻豆| 日韩精品小视频在线观看| 国产日韩久久精品一区| 亚洲精品偷拍视频免费观看| 国产亚洲午夜高清国产拍精品| 日韩精品一区二区不卡| 国产亚洲不卡一区二区| 国产偷拍盗摄一区二区| 国产亚洲中文日韩欧美综合网| 亚洲精品福利入口在线| 国产亚洲成av人在线观看| 在线观看免费视频你懂的| 东京热加勒比一区二区| 精品香蕉国产一区二区三区| 91偷拍与自偷拍精品| 国自产拍偷拍福利精品图片| 午夜国产精品国自产拍av| 一二区不卡不卡在线观看| 国产午夜精品在线免费看| 天堂热东京热男人天堂| 国产中文另类天堂二区|