目錄:javascript
一、前言java
二、背景git
三、效果展現github
前言 this
基於安卓平臺的SlidingMenu側滑菜單組件(https://github.com/jfeinstein10/SlidingMenu),實現了鴻蒙化遷移和重構,代碼已經開源到(https://gitee.com/isrc_ohos/sliding-menu_ohos),歡迎各位下載使用並提出寶貴意見!url
背景spa
SlidingMenu_ohos提供了一個側滑菜單的導航框架,使菜單能夠隱藏在手機屏幕的左側、右側或左右兩側。當用戶使用時,經過左滑或者右滑的方式調出,既節省了主屏幕的空間,也方便用戶操做,在不少主流APP中都有普遍的應用。
效果展現
因爲菜單從左右兩側調出的顯示效果類似,此處僅以菜單從左側調出爲例進行效果展現。
組件未啓用時,應用顯示主頁面。單指觸摸屏幕左側並逐漸向右滑動,菜單頁面逐漸顯示,主頁面逐漸隱藏。向右滑動的距離超過某個閾值時,菜單頁面所有顯示,效果如圖1所示。
圖1 菜單展現和隱藏效果圖
Sample解析
Sample部分的內容較爲簡單,主要包含兩個部分。一是建立SlidingMenu_ohos組件的對象,可根據用戶的實際需求,調用Library的接口,對組件的具體屬性進行設置。二是將設置好的組件添加到Ability中。下面將詳細介紹組件的使用方法。
一、導入SlidingMenu類
import com.jeremyfeinstein.slidingmenu.lib.SlidingMenu;
二、設置Ability的佈局
此佈局用做爲主頁面的佈局,在組件隱藏的時候顯示。
DirectionalLayout directionalLayout = (DirectionalLayout)LayoutScatter.getInstance(this).parse(ResourceTable.Layout_activity_main,null,false);setUIContent(directionalLayout);
三、實例化組件的對象
SlidingMenu slidingMenu = null; try { //初始化SlidingMenu實例 slidingMenu = new SlidingMenu(this); } catch (IOException e) { e.printStackTrace(); } catch (NotExistException e) { e.printStackTrace(); }
四、設置組件屬性
此步驟能夠根據具體需求,設置組件的位置、觸發範圍、佈局、最大寬度等屬性。
//設置菜單放置位置 slidingMenu.setMode(SlidingMenu.LEFT); //設置組件的觸發範圍 slidingMenu.setTouchScale(100); //設置組件的佈局 slidingMenu.setMenu(ResourceTable.Layout_layout_left_menu); //設置菜單最大寬度 slidingMenu.setMenuWidth(800);
五、關聯Ability
attachToAbility()方法是Library提供的重要方法,用於將菜單組件關聯到Ability。其參數SLIDING_WINDOW和SLIDING_CONTENT是菜單的不一樣模式,SLIDING_WINDOW模式下的菜單包含Title / ActionBar部分,菜單需在整個手機頁面上顯示,如圖2所示;SLIDING_CONTENT模式下的菜單不包括包含Title / ActionBar部分,菜單能夠在手機頁面的局部範圍內顯示,如圖3所示。
try { //關聯Ability,獲取頁面展現根節點 slidingMenu.attachToAbility(directionalLayout,this, SlidingMenu.SLIDING_WINDOW); } catch (NotExistException e) { e.printStackTrace(); } catch (WrongTypeException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }
圖2 SLIDING_WINDOW展現效果圖
圖3 SLIDING_CONTENT展現效果圖
Library解析
Library的工程結構以下圖所示,CustomViewAbove表示主頁面,CustomViewBehind表示菜單頁面,SlidingMenu主要用於控制主頁面位於菜單頁面的上方,還能夠設置菜單的寬度、觸發範圍、顯示模式等屬性。爲了方便解釋,如下均以手指從左側觸摸屏幕並向右滑動爲例進行講解,菜單均採用SLIDING_WINDOW的顯示模式。
圖4 Library的工程結構
一、CustomViewAbove主頁面
CustomViewAbove須要監聽觸摸、移動、擡起和取消等Touch事件,並記錄手指滑動的距離和速度。
(1)對Touch事件的處理
Touch事件決定了菜單的顯示、移動和隱藏。例如:在菜單的觸發範圍內,手指向右滑動(POINT_MOVE)時,菜單會跟隨滑動到手指所在位置。手指擡起(PRIMARY_POINT_UP)或者取消滑動(CANCEL)時,會依據手指滑動的距離和速度決定菜單頁面的下一狀態是所有隱藏仍是所有顯示。
switch (action) { //按下 case TouchEvent.PRIMARY_POINT_DOWN: ..... mInitialMotionX=mLastMotionX=ev.getPointerPosition(mActivePointerId).getX(); break; //滑動 case TouchEvent.POINT_MOVE: ...... //菜單滑動到此時手指所在位置(x) left_scrollto(x); break; //擡起 case TouchEvent.PRIMARY_POINT_UP: ...... //得到菜單的下一狀態(全屏顯示或者所有隱藏) int nextPage = determineTargetPage(pageOffset, initialVelocity,totalDelta); //設置菜單的下一狀態 setCurrentItemInternal(nextPage,initialVelocity); ...... endDrag(); break; //取消 case TouchEvent.CANCEL: ...... //根據菜單當前狀態mCurItem設置菜單下一狀態 setCurrentItemInternal(mCurItem); //結束拖動 endDrag(); break; }
(2)對滑動的距離和速度的處理
手指擡起時,滑動的速度和距離分別大於最小滑動速度和最小移動距離,斷定此時的操做爲快速拖動,菜單當即彈出並所有顯示,如圖5所示。
private int determineTargetPage(float pageOffset, int velocity, int deltaX) { //得到當前菜單狀態,0:左側菜單正在展現,1:菜單隱藏,2:右側菜單正在展現 int targetPage = getCurrentItem(); //針對快速拖動的判斷 if (Math.abs(deltaX) > mFlingDistance && Math.abs(velocity) > mMinimumVelocity) { if (velocity > 0 && deltaX > 0) { targetPage -= 1; } else if (velocity < 0 && deltaX < 0){ targetPage += 1; } } }
圖5 快速拖動效果圖
當手指擡起而且不知足快速拖動標準時,須要根據滑動距離判斷菜單的隱藏或顯示。若菜單已展開的部分超過自身寬度的1/2,菜單當即彈出所有顯示,,效果圖如圖1所示;若不足自身寬度的1/2,則當即彈回所有隱藏,效果圖如圖6所示。
//得到當前菜單狀態,0:左側菜單正在展現,1:菜單隱藏,2:右側菜單正在展現 switch (mCurItem){ case 0: targetPage=1-Math.round(pageOffset); break; case 1: //菜單隱藏時,首先要判斷此時菜單的放置狀態是左側仍是右側 if(current_state == SlidingMenu.LEFT){ targetPage = Math.round(1-pageOffset); } if(current_state == SlidingMenu.RIGHT){ targetPage = Math.round(1+pageOffset); } break; case 2: targetPage = Math.round(1+pageOffset); break; }
圖6 緩慢拖動效果圖
(3)菜單顯示和隱藏的實現
主頁面的左側邊線與手指的位置綁定,當手指向右滑動時,主頁面也會隨手指向右滑動,在這個過程當中菜單頁面漸漸展現出來,實現菜單頁面隨手指滑動慢慢展開的視覺效果。
void setCurrentItemInternal(int item,int velocity) { //得到菜單的目標狀態 item = mViewBehind.getMenuPage(item); mCurItem = item; final int destX = getDestScrollX(mCurItem); /*菜單放置狀態爲左側,經過設置主頁面的位置實現菜單的彈出展現或彈回隱藏 1.destX=0,主頁面左側邊線與屏幕左側邊線對齊,菜單被所有遮擋,實現菜單彈回隱藏 2.destX=MenuWidth,主頁面左側邊線向右移動與菜單總寬度相等的距離,實現菜單彈出展現*/ if (mViewBehind.getMode() == SlidingMenu.LEFT) { mContent.setLeft(destX); mViewBehind.scrollBehindTo(destX); } ...... } // 菜單放置在左側時的菜單滑動操做 public void left_scrollto(float x) { //當menu的展現寬度大於最大寬度時僅展現最大寬度 if(x>getMenuWidth()){ x=getMenuWidth(); } //主頁面(主頁面左側邊線)和菜單(菜單右側邊線)分別移動到指定位置X mContent.setLeft((int)x); mViewBehind.scrollBehindTo((int)x); }
二、CustomViewBehind 菜單頁面
CustomViewBehind爲菜單頁面,邏輯相比於主頁面簡單許多。主要負責根據主頁面中的Touch事件改變自身狀態值,同時向外暴露接口,用於設置或者獲取菜單頁面的最大寬度、自身狀態等屬性。
// 設置菜單最大寬度 public void setMenuWidth(int menuWidth) { this.menuWidth = menuWidth; } // 得到菜單最大寬度 public int getMenuWidth() { return menuWidth; }
3. SlidingMenu
分別實例化CustomViewAbove和CustomViewBehind的對象,並按照主頁面在上菜單頁面在下的順序分別添加到SlidingMenu的容器中。
//添加菜單子控件 addComponent(mViewBehind, behindParams); //添加主頁面子控件 addComponent(mViewAbove, aboveParams);
項目貢獻人
徐澤鑫 鄭森文 朱偉 陳美汝 王佳思 張馨心
做者:朱偉ISRC
想了解更多內容,請訪問51CTO和華爲合做共建的鴻蒙社區:https://harmonyos.51cto.com/