Android 는 슬라이딩 메뉴 프레임 워 크 를 이용 하여 슬라이딩 메뉴 효 과 를 구현 합 니 다.

앞서 역사상 가장 간단 한 슬라이딩 메뉴 의 실현 방식 을 소개 해 드 렸 는데 기억 하 실 거 라 고 믿 습 니 다.그 중의 실현 원 리 를 잊 었 거나 아직 보지 못 한 친 구 는 먼저 이전의 글 을 한 번 보 세 요Android 모방 클 라 이언 트 슬라이딩 메뉴 의 사 이 드 슬라이드 효과 구현 코드역사상 가장 간단 한 사 이 드 스 케 이 트 실현 은 우리 가 오늘 실현 해 야 할 미끄럼 메뉴 구조 도 같은 원리 에 기초 하고 있 기 때 문 입 니 다.
이전 글 에서 도 마지막 으로 언급 했 듯 이 애플 리 케 이 션 에 많은 Activity 가 미끄럼 메뉴 기능 을 추가 해 야 한다 면 모든 Activity 는 백 줄 의 코드 를 써 야 효 과 를 낼 수 있 고 아무리 간단 한 미끄럼 메뉴 구현 방안 도 소 용이 없다.따라서 우 리 는 오늘 미끄럼 메뉴 의 프레임 워 크 를 실현 하고 모든 Activity 에서 1 분 동안 미끄럼 메뉴 기능 을 도입 할 수 있 습 니 다.
우선 실현 원 리 를 말 해 보 자.슬라이딩 메뉴 의 프레임 워 크 라 고 하 더 라 도 솔직히 말하자면 간단 합 니 다.바로 우리 가 레이아웃 을 사용자 정의 하 는 것 입 니 다.이 사용자 정의 레이아웃 에서 슬라이딩 메뉴 의 기능 을 잘 실현 한 다음 에 Activity 의 레이아웃 파일 에 사용자 정의 레이아웃 을 도입 하면 이 Activity 는 슬라이딩 메뉴 의 기능 을 가지 게 됩 니 다.원 리 를 다 말 했 으 니 매우 간단 하지 않 습 니까?다음은 우리 가 손 을 써 서 실현 합 시다.
Eclipse 에 안 드 로 이 드 프로젝트 를 새로 만 들 었 습 니 다.프로젝트 이름 은 RenRenSliding Layout 입 니 다.
SlidingLayout 라 는 클래스 를 새로 만 들 었 습 니 다.이 클래스 는 LinearLayout 에서 계승 되 었 고 OnTouchListener 인 터 페 이 스 를 실 현 했 습 니 다.구체 적 인 코드 는 다음 과 같 습 니 다.

public class SlidingLayout extends LinearLayout implements OnTouchListener { 
 /** 
 *             ,           。 
 */ 
 public static final int SNAP_VELOCITY = 200; 
 /** 
 *      。 
 */ 
 private int screenWidth; 
 /** 
 *                。           ,marginLeft      ,     。 
 */ 
 private int leftEdge; 
 /** 
 *                。   0, marginLeft  0  ,    。 
 */ 
 private int rightEdge = 0; 
 /** 
 *          ,          。 
 */ 
 private int leftLayoutPadding = 80; 
 /** 
 *            。 
 */ 
 private float xDown; 
 /** 
 *            。 
 */ 
 private float xMove; 
 /** 
 *            。 
 */ 
 private float xUp; 
 /** 
 *              。                ,         。 
 */ 
 private boolean isLeftLayoutVisible; 
 /** 
 *       。 
 */ 
 private View leftLayout; 
 /** 
 *       。 
 */ 
 private View rightLayout; 
 /** 
 *          View。 
 */ 
 private View mBindView; 
 /** 
 *        ,                 ,    leftMargin  。 
 */ 
 private MarginLayoutParams leftLayoutParams; 
 /** 
 *        ,                 。 
 */ 
 private MarginLayoutParams rightLayoutParams; 
 /** 
 *            。 
 */ 
 private VelocityTracker mVelocityTracker; 
 /** 
 *   SlidingLayout     ,          。 
 * 
 * @param context 
 * @param attrs 
 */ 
 public SlidingLayout(Context context, AttributeSet attrs) { 
 super(context, attrs); 
 WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 
 screenWidth = wm.getDefaultDisplay().getWidth(); 
 } 
 /** 
 *          View,     View                。 
 * 
 * @param bindView 
 *      View  。 
 */ 
 public void setScrollEvent(View bindView) { 
 mBindView = bindView; 
 mBindView.setOnTouchListener(this); 
 } 
 /** 
 *             ,       30. 
 */ 
 public void scrollToLeftLayout() { 
 new ScrollTask().execute(30); 
 } 
 /** 
 *             ,       -30. 
 */ 
 public void scrollToRightLayout() { 
 new ScrollTask().execute(-30); 
 } 
 /** 
 *             ,     ,         。 
 * 
 * @return           true,      false。 
 */ 
 public boolean isLeftLayoutVisible() { 
 return isLeftLayoutVisible; 
 } 
 /** 
 *  onLayout                 。 
 */ 
 @Override 
 protected void onLayout(boolean changed, int l, int t, int r, int b) { 
 super.onLayout(changed, l, t, r, b); 
 if (changed) { 
 //          
 leftLayout = getChildAt(0); 
 leftLayoutParams = (MarginLayoutParams) leftLayout.getLayoutParams(); 
 //                   leftLayoutPadding 
 leftLayoutParams.width = screenWidth - leftLayoutPadding; 
 //                  
 leftEdge = -leftLayoutParams.width; 
 leftLayoutParams.leftMargin = leftEdge; 
 leftLayout.setLayoutParams(leftLayoutParams); 
 //          
 rightLayout = getChildAt(1); 
 rightLayoutParams = (MarginLayoutParams) rightLayout.getLayoutParams(); 
 rightLayoutParams.width = screenWidth; 
 rightLayout.setLayoutParams(rightLayoutParams); 
 } 
 } 
 @Override 
 public boolean onTouch(View v, MotionEvent event) { 
 createVelocityTracker(event); 
 switch (event.getAction()) { 
 case MotionEvent.ACTION_DOWN: 
 //      ,          
 xDown = event.getRawX(); 
 break; 
 case MotionEvent.ACTION_MOVE: 
 //      ,         ,        ,        leftMargin ,            
 xMove = event.getRawX(); 
 int distanceX = (int) (xMove - xDown); 
 if (isLeftLayoutVisible) { 
 leftLayoutParams.leftMargin = distanceX; 
 } else { 
 leftLayoutParams.leftMargin = leftEdge + distanceX; 
 } 
 if (leftLayoutParams.leftMargin < leftEdge) { 
 leftLayoutParams.leftMargin = leftEdge; 
 } else if (leftLayoutParams.leftMargin > rightEdge) { 
 leftLayoutParams.leftMargin = rightEdge; 
 } 
 leftLayout.setLayoutParams(leftLayoutParams); 
 break; 
 case MotionEvent.ACTION_UP: 
 //      ,           ,            ,          
 xUp = event.getRawX(); 
 if (wantToShowLeftLayout()) { 
 if (shouldScrollToLeftLayout()) { 
 scrollToLeftLayout(); 
 } else { 
 scrollToRightLayout(); 
 } 
 } else if (wantToShowRightLayout()) { 
 if (shouldScrollToContent()) { 
 scrollToRightLayout(); 
 } else { 
 scrollToLeftLayout(); 
 } 
 } 
 recycleVelocityTracker(); 
 break; 
 } 
 return isBindBasicLayout(); 
 } 
 /** 
 *                    。            ,           ,                。 
 * 
 * @return              true,    false。 
 */ 
 private boolean wantToShowRightLayout() { 
 return xUp - xDown < 0 && isLeftLayoutVisible; 
 } 
 /** 
 *                    。            ,            ,                。 
 * 
 * @return              true,    false。 
 */ 
 private boolean wantToShowLeftLayout() { 
 return xUp - xDown > 0 && !isLeftLayoutVisible; 
 } 
 /** 
 *                  。             1/2,          SNAP_VELOCITY, 
 *                 。 
 * 
 * @return                  true,    false。 
 */ 
 private boolean shouldScrollToLeftLayout() { 
 return xUp - xDown > screenWidth / 2 || getScrollVelocity() > SNAP_VELOCITY; 
 } 
 /** 
 *                  。          leftLayoutPadding     1/2, 
 *           SNAP_VELOCITY,                 。 
 * 
 * @return                  true,    false。 
 */ 
 private boolean shouldScrollToContent() { 
 return xDown - xUp + leftLayoutPadding > screenWidth / 2 
 || getScrollVelocity() > SNAP_VELOCITY; 
 } 
 /** 
 *          View       layout,      layout,       layout, 
 * AbsoluteLayout    。 
 * 
 * @return          View LinearLayout,RelativeLayout,FrameLayout, 
 * TableLayout     true,    false。 
 */ 
 private boolean isBindBasicLayout() { 
 if (mBindView == null) { 
 return false; 
 } 
 String viewName = mBindView.getClass().getName(); 
 return viewName.equals(LinearLayout.class.getName()) 
 || viewName.equals(RelativeLayout.class.getName()) 
 || viewName.equals(FrameLayout.class.getName()) 
 || viewName.equals(TableLayout.class.getName()); 
 } 
 /** 
 *   VelocityTracker  ,         VelocityTracker  。 
 * 
 * @param event 
 *               
 */ 
 private void createVelocityTracker(MotionEvent event) { 
 if (mVelocityTracker == null) { 
 mVelocityTracker = VelocityTracker.obtain(); 
 } 
 mVelocityTracker.addMovement(event); 
 } 
 /** 
 *             View      。 
 * 
 * @return     ,               。 
 */ 
 private int getScrollVelocity() { 
 mVelocityTracker.computeCurrentVelocity(1000); 
 int velocity = (int) mVelocityTracker.getXVelocity(); 
 return Math.abs(velocity); 
 } 
 /** 
 *   VelocityTracker  。 
 */ 
 private void recycleVelocityTracker() { 
 mVelocityTracker.recycle(); 
 mVelocityTracker = null; 
 } 
 class ScrollTask extends AsyncTask<Integer, Integer, Integer> { 
 @Override 
 protected Integer doInBackground(Integer... speed) { 
 int leftMargin = leftLayoutParams.leftMargin; 
 //             ,             ,    。 
 while (true) { 
 leftMargin = leftMargin + speed[0]; 
 if (leftMargin > rightEdge) { 
 leftMargin = rightEdge; 
 break; 
 } 
 if (leftMargin < leftEdge) { 
 leftMargin = leftEdge; 
 break; 
 } 
 publishProgress(leftMargin); 
 //           ,         20  ,             。 
 sleep(20); 
 } 
 if (speed[0] > 0) { 
 isLeftLayoutVisible = true; 
 } else { 
 isLeftLayoutVisible = false; 
 } 
 return leftMargin; 
 } 
 @Override 
 protected void onProgressUpdate(Integer... leftMargin) { 
 leftLayoutParams.leftMargin = leftMargin[0]; 
 leftLayout.setLayoutParams(leftLayoutParams); 
 } 
 @Override 
 protected void onPostExecute(Integer leftMargin) { 
 leftLayoutParams.leftMargin = leftMargin; 
 leftLayout.setLayoutParams(leftLayoutParams); 
 } 
 } 
 /** 
 *              。 
 * 
 * @param millis 
 *           ,       
 */ 
 private void sleep(long millis) { 
 try { 
 Thread.sleep(millis); 
 } catch (InterruptedException e) { 
 e.printStackTrace(); 
 } 
 } 
} 
 이곳 을 보면,나 는 모두 가 반드시 이 코드 들 이 매우 익숙 하 다 고 느 낄 것 이 라 고 믿는다.맞 아,기본적으로 이 코드 들 은 이전 글 의 코드 와 크게 다 르 지 않 아.예전 에는 이 코드 들 이 Activity 에 쓰 여 있 었 지만 지금 은 사용자 정의 View 로 이동 했다.
이어서 제 가 이전 과 다른 부분 을 설명 하 겠 습 니 다.여기 서 onLayout 방법 을 다시 썼 습 니 다.getChildAt(0)에서 얻 은 레이아웃 을 왼쪽 레이아웃 으로 하고 getChildAt(1)에서 얻 은 레이아웃 을 오른쪽 레이아웃 으로 사용 합 니 다.또한 왼쪽 레이아웃 의 폭 을 화면 너비 에서 left LayoutPadding 을 줄 이 고 오른쪽 레이아웃 의 폭 을 화면 너비 로 다시 정의 합 니 다.그리고 왼쪽 레이아웃 을 화면 밖으로 옮 기 면 오른쪽 레이아웃 만 볼 수 있 습 니 다.따라서 여기 서 우 리 는 Sliding Layout 라 는 레이아웃 을 사용 하 는 전제 조건 을 알 수 있 습 니 다.이 레이아웃 에 두 개의 키 요 소 를 제공 해 야 합 니 다.첫 번 째 요 소 는 왼쪽 레이아웃 으로 화면 에서 이동 하고 두 번 째 요 소 는 오른쪽 레이아웃 으로 화면 에 표 시 됩 니 다.
그리고 set ScrollEvent 방법 을 살 펴 보 겠 습 니 다.이 방법 은 View 를 매개 변수 로 받 은 다음 에 이 View 에 touch 이 벤트 를 연결 합 니 다.이게 무슨 뜻 이 죠?오른쪽 레이아웃 이 LinearLayout 라면 LinearLayout 의 touch 사건 을 감청 하여 왼쪽 레이아웃 의 표시 와 숨 김 을 제어 할 수 있 습 니 다.그러나 오른쪽 레이아웃 의 LinearLayout 에 ListView 가 추가 되 어 있 고 이 ListView 는 LinearLayout 전 체 를 가득 채 우 고 있 습 니 다.이 럴 때 LinearLayout 는 더 이상 터치 되 지 않 을 것 입 니 다.이 럴 때 저 희 는 touch 사건 을 ListView 에 등록 해 야 합 니 다.setScrollEvent 방법 은 등록 인 터 페 이 스 를 제공 하 는 것 입 니 다.touch 이 벤트 는 들 어 오 는 View 에 등 록 됩 니 다.
마지막 으로 낯 선 방법 이 하나 더 있 습 니 다.isBind Basic Layout.이 방법 은 등록 터치 이벤트 의 View 가 네 가지 기본 레이아웃 중 하나 인지 판단 하 는 것 입 니 다.만약 에 true 로 돌아 가지 않 으 면 false 로 돌아 갑 니 다.이 방법 은 전체 SlidingLayout 에서 매우 중요 한 역할 을 합 니 다.주로 onTouch 사건 이 true 로 돌아 가 는 지 false 로 돌아 가 는 지 제어 하 는 데 사 용 됩 니 다.이것 은 레이아웃 에 있 는 View 의 기능 이 사용 가능 한 지 에 영향 을 줄 것 입 니 다.안 드 로 이 드 의 이벤트 퍼 가기 체제 와 관련 되 어 있 기 때문에 내용 이 비교적 많 기 때문에 여기 서 상세 하 게 설명 하지 않 겠 습 니 다.저 는 앞으로 안 드 로 이 드 의 사건 체 제 를 전문 적 으로 글 을 써 서 소개 하 는 것 을 고려 하 겠 습 니 다.기본 레이아웃 이 라면 트 루 로 돌아 가 고,그렇지 않 으 면 false 로 돌아 가 는 것 을 간단하게 기억 하 세 요.
자,우리 의 Sliding Layout 를 다 썼 습 니 다.다음은 기적 을 보 는 순간 입 니 다.Activity 에서 어떻게 1 분 동안 미끄럼 메뉴 기능 을 도입 하 는 지 살 펴 보 겠 습 니 다.
layot 디 렉 터 리 에 있 는 activity 를 만 들 거나 열기main.xml 파일,다음 코드 추가:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
 xmlns:tools="http://schemas.android.com/tools" 
 android:layout_width="fill_parent" 
 android:layout_height="fill_parent" 
 android:orientation="horizontal" 
 tools:context=".MainActivity" > 
 <!--           ,orientation        --> 
 <com.example.slide.SlidingLayout 
 android:id="@+id/slidingLayout" 
 android:layout_width="fill_parent" 
 android:layout_height="fill_parent" 
 android:orientation="horizontal" > 
 <!-- 
          ,          ,                 , 
  LinearLayout, RelativeLayout, FrameLayout TableLayout。 
              ,       。             , 
      Activity    ,          。 
 --> 
 <RelativeLayout 
 android:id="@+id/menu" 
 android:layout_width="fill_parent" 
 android:layout_height="fill_parent" 
 android:background="#00ccff" > 
 <TextView 
 android:layout_width="wrap_content" 
 android:layout_height="wrap_content" 
 android:layout_centerInParent="true" 
 android:text="This is menu" 
 android:textColor="#000000" 
 android:textSize="28sp" /> 
 </RelativeLayout> 
 <LinearLayout 
 android:id="@+id/content" 
 android:layout_width="fill_parent" 
 android:layout_height="fill_parent" 
 android:orientation="vertical" > 
 <Button 
 android:id="@+id/menuButton" 
 android:layout_width="wrap_content" 
 android:layout_height="wrap_content" 
 android:text="Menu" /> 
 <ListView 
 android:id="@+id/contentList" 
 android:layout_width="fill_parent" 
 android:layout_height="fill_parent" > 
 </ListView> 
 </LinearLayout> 
 </com.example.slide.SlidingLayout> 
 
</LinearLayout> 
루트 레이아웃 아래 에 사용자 정의 레이아웃 com.example.slide.sliding Layout 를 도입 한 다음 에 그 안에 두 개의 하위 요소,하 나 는 RelativeLayout 와 하 나 는 LinearLayout 를 추가 한 것 을 볼 수 있 습 니 다.Relative Layout 에 간단 해서 TextView 를 추 가 했 습 니 다.LinearLayout 에 우 리 는 버튼 과 ListView 를 추가 했다.
그리고 MainActivity 를 프로그램의 주 Activity 로 만 들 거나 열 고 코드 를 추가 합 니 다.

public class MainActivity extends Activity { 
 /** 
 *       ,                       。 
 */ 
 private SlidingLayout slidingLayout; 
 /** 
 * menu  ,          ,           。 
 */ 
 private Button menuButton; 
 /** 
 *   content    ListView。 
 */ 
 private ListView contentListView; 
 /** 
 *    contentListView    。 
 */ 
 private ArrayAdapter<String> contentListAdapter; 
 /** 
 *     contentListAdapter    。 
 */ 
 private String[] contentItems = { "Content Item 1", "Content Item 2", "Content Item 3", 
 "Content Item 4", "Content Item 5", "Content Item 6", "Content Item 7", 
 "Content Item 8", "Content Item 9", "Content Item 10", "Content Item 11", 
 "Content Item 12", "Content Item 13", "Content Item 14", "Content Item 15", 
 "Content Item 16" }; 
 @Override 
 protected void onCreate(Bundle savedInstanceState) { 
 super.onCreate(savedInstanceState); 
 setContentView(R.layout.activity_main); 
 slidingLayout = (SlidingLayout) findViewById(R.id.slidingLayout); 
 menuButton = (Button) findViewById(R.id.menuButton); 
 contentListView = (ListView) findViewById(R.id.contentList); 
 contentListAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, 
 contentItems); 
 contentListView.setAdapter(contentListAdapter); 
 //           contentListView  
 slidingLayout.setScrollEvent(contentListView); 
 menuButton.setOnClickListener(new OnClickListener() { 
 @Override 
 public void onClick(View v) { 
 //       menu      ,               
 if (slidingLayout.isLeftLayoutVisible()) { 
 slidingLayout.scrollToRightLayout(); 
 } else { 
 slidingLayout.scrollToLeftLayout(); 
 } 
 } 
 }); 
 } 
 } 
 상기 코드 의 중점 은 SlidingLayout 의 set ScrollEvent 방법 을 호출 하여 ListView 에 touch 이 벤트 를 등록 하 는 것 입 니 다.동시에 버튼 에 클릭 이 벤트 를 추가 하여 클릭 하여 왼쪽 레이아웃 을 표시 하고 왼쪽 레이아웃 을 숨 기 는 기능 을 실현 합 니 다.
마지막 으로 오래된 규칙 입 니 다.AndroidManifest.xml 코드 를 드 립 니 다.

<?xml version="1.0" encoding="utf-8"?> 
<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
 package="com.example.slide" 
 android:versionCode="1" 
 android:versionName="1.0" > 
 <uses-sdk 
 android:minSdkVersion="8" 
 android:targetSdkVersion="8" /> 
 <application 
 android:allowBackup="true" 
 android:icon="@drawable/ic_launcher" 
 android:label="@string/app_name" 
 android:theme="@android:style/Theme.NoTitleBar" > 
 <activity 
 android:name="com.example.slide.MainActivity" 
 android:label="@string/app_name" > 
 <intent-filter> 
 <action android:name="android.intent.action.MAIN" /> 
 <category android:name="android.intent.category.LAUNCHER" /> 
 </intent-filter> 
 </activity> 
 </application> 
 
</manifest> 
자,이제 운행 합 시다.우선 프로그램 이 열 렸 을 때 오른쪽 레이아웃 이 표 시 됩 니 다.손가락 으로 인터페이스 에서 오른쪽으로 미 끄 러 지면 왼쪽 레이아웃 이 나타 나 는 것 을 볼 수 있다.
                
왼쪽 레이아웃 이 완전히 표 시 될 때 효과 도 는 다음 과 같 습 니 다.
 
그 밖 에 Menu 단 추 를 누 르 면 왼쪽 레이아웃 의 표시 와 숨 김 을 제어 할 수 있 으 니 직접 시도 해 보 세 요.
사용자 정의 레이아웃 을 사용 하면 임의의 Activity 에 슬라이딩 메뉴 기능 을 간단하게 추가 할 수 있 습 니 다.아무리 많은 Activity 가 있어 도 두려워 하지 않 아 도 됩 니 다.1 분 동안 슬라이딩 메뉴 를 도입 하 는 것 이 좋 습 니 다.
다시 한 번 정리 해 보 세 요.Activity 에 미끄럼 메뉴 기능 을 추가 하려 면 두 단계 만 필요 합 니 다.
1.Acitivty 의 layot 에 사용자 정의 레이아웃 을 도입 하고 이 레이아웃 에 두 개의 직접 하위 요 소 를 추가 합 니 다.
2.Activity 에서 set ScrollEvent 방법 을 통 해 View 에 touch 이 벤트 를 등록 합 니 다.
자,오늘 설명 은 여기 서 마 치 겠 습 니 다.궁금 한 분 은 아래 에 메 시 지 를 남 겨 주세요.
원본 다운로드,여 기 를 클릭 하 세 요.
보충:
이 글 은 비교적 일찍 썼 기 때문에 그때 쓴 미끄럼 메뉴 에 아직도 많은 문제 가 존재 했다.나 는 그 후에 위의 코드 를 많이 바 꾸 었 고 수정판 의 미끄럼 메뉴 를 만 들 었 다.이 버 전 은 주로 다음 과 같은 내용 을 수정 했다.
1.미끄럼 방식 을 커버 형 으로 바 꾸 었 습 니 다.
2.ListView 를 위아래 로 굴 릴 때 메뉴 가 쉽게 미 끄 러 지지 않 습 니 다.
3.미 끄 러 지고 있 을 때 내용 레이아웃 에 있 는 이 벤트 를 차단 합 니 다.
4.메뉴 레이아웃 이 표 시 될 때 오른쪽 에 있 는 내용 레이아웃 을 클릭 하면 메뉴 를 숨 길 수 있 습 니 다.
5.프로그램 을 처음 열 었 을 때 메뉴 가 잠시 표시 되 고 순식간에 사라 질 수 있 는 bug 를 복원 합 니 다.
수정판 원본 다운로드,여 기 를 클릭 하 세 요.
또한 양 방향 슬라이딩 메뉴 에 관심 이 있 으 신 분 은 돌려 보 세 요.  Android 에서 양 방향 슬라이딩 효 과 를 실현 하 는 인 스 턴 스 코드
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기