Android 3D 미닫이 식 슬라이딩 메뉴 원본 분석 실현

머리말
  또 곽 림 대신 의 블 로 그 를 보 았 습 니 다'안 드 로 이 드 3D 슬라이딩 메뉴 완전 해석,미닫이 식 입체 효과 구현'사용자 정의 컨트롤 에 관 한 것 입 니 다.사용자 정의 컨트롤 에 대해 알 고 있 지만 예전 의 요 구 는 사용 하면 되 었 습 니 다.그러나 나중에 점점 더 사용 하 는 것 이 부족 하 다 는 것 을 알 게 되 었 습 니 다.문제 가 발생 하면 어떻게 분석 해 야 할 지 모 르 기 때문에 저 는 다른 사람의 블 로그 에 있 는 사용자 정의 컨트롤 의 소스 코드 를 알 아 보 려 고 합 니 다.시간 이 오래 걸 릴 수도 있 지만,분명 가치 가 있 습 니 다!
  는 소스 코드 의 물건 이 많 기 때문에 보고 나 서 최적화 할 수 있 는 부분 이 존재 한 다 는 것 을 알 게 되 었 습 니 다.곽 신의 코드 는 그 당시 에 예 를 들 어 설명 하기 위해 서 였 기 때문에 이 컨트롤 류 의 포장 에 대해 자세히 하지 않 았 습 니 다.그래서 저 는 포장 과 최 적 화 를 했 습 니 다.네,프로젝트 에 이식 할 때 더욱 편리 하고 결합 성 이 강 합 니 다.
이루어지다
우리 먼저 설명도 좀 봅 시다.

예.
  효과 도 에서 볼 수 있 듯 이 미 끄 러 질 때 메뉴 가 한 가지 효과 가 있 는데 이 효 과 는 Y 축 을 따라 회전 하 는 효과 이다.이런 효 과 는 Matrix 와 Camera 로 이 루어 진다.구체 적 으로 어떻게 이 루어 지 는 지 나 는 다른 글 에서 간단 한 설명 을 했 는데 이런 효 과 를 쉽게 실현 할 수 있다.
  Image3DView 에서 우 리 는 이러한 효 과 를 봉 인 했 습 니 다.왼쪽 메뉴 인터페이스의 View 에 들 어가 면 이 루어 집 니 다.
  먼저 레이아웃 파일 을 봅 시다.

<com.example.sliding3dlayout.Sliding3DLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:id="@+id/slidingLayout"
 android:layout_width="match_parent"
 android:layout_height="match_parent">
 <RelativeLayout 
  android:layout_height="fill_parent"
  android:layout_width="240dp"
  android:background="#333333"
  android:visibility="invisible"
  >
  <LinearLayout 
   android:layout_centerInParent="true"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:orientation="vertical"
   >
   <TextView
    android:layout_width="fill_parent"
    android:layout_height="50dp"
    android:text="  "
    android:gravity="center"
    android:textColor="#ffffff"
    />
   <TextView
    android:layout_width="fill_parent"
    android:layout_height="50dp"
    android:text="  "
    android:gravity="center"
    android:textColor="#ffffff"
    />
   <TextView
    android:layout_width="fill_parent"
    android:layout_height="50dp"
    android:text="  "
    android:gravity="center"
    android:textColor="#ffffff"
    />
  </LinearLayout>
 </RelativeLayout>
 <LinearLayout
  android:id="@+id/content"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:layout_alignParentRight="true"
  android:background="#ffffff"
  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"
   android:cacheColorHint="#00000000" >
  </ListView>
 </LinearLayout>
</com.example.sliding3dlayout.Sliding3DLayout>
『8195』Sliding3DLayout 류 는 이 메뉴 컨트롤 을 정의 합 니 다.그 안에 두 개의 주요 보기 가 있 습 니 다.첫 번 째 는 메뉴 보기 이 고 두 번 째 는 메 인 인터페이스 보기 입 니 다.미 끄 러 질 때 우 리 는 왼쪽 메뉴 보 기 를 숨 긴 다음 에 Image3DView 컨트롤 을 표시 합 니 다.즉,Y 축 을 따라 회전 합 니 다.미 끄 러 지 는 거리 에 따라 회전 하 는 각도 가 계속 변화 하고 있 습 니 다.Image3DView 의 보기 도 계속 변화 하고 있 습 니 다.메뉴 가 완전히 표 시 될 때 왼쪽 메뉴 의 화면 을 표시 한 다음 에 Image3DView 를 숨 깁 니 다.이렇게 해서 이른바 미끄럼 애니메이션 을 실현 했다.

public class Sliding3DLayout extends RelativeLayout implements OnTouchListener{

 //            ,           。
  public static final int SNAP_VELOCITY = 200;
  //       ,         。
  public static final int DO_NOTHING = 0;
   //       ,          。
  public static final int SHOW_MENU = 1;
  //       ,          。
  public static final int HIDE_MENU = 2;
   //         
  private int slideState;
   //     。
  private int screenWidth;
   //               。
  private int leftEdge = 0;
  //               。
  private int rightEdge = 0;
  //                     。
  private int touchSlop;
   //           。
  private float xDown;
   //           。
  private float yDown;
   //           。
  private float xMove;
  //           。
  private float yMove;
  //           。
  private float xUp;
  //             。                ,         。
  private boolean isLeftLayoutVisible;
  //      。
  private boolean isSliding;
  //        layout,  onLayout           
  private boolean loadOnce;
  //      。
  private View leftLayout;
  //      。
  private View rightLayout;
   //         3D  
  private Image3DView image3dView;
   //         View。
  private View mBindView;
  //       ,                 ,    leftMargin  。
  private MarginLayoutParams leftLayoutParams;
  //       ,                 。
  private MarginLayoutParams rightLayoutParams;
  //3D     ,          3D     。
  private ViewGroup.LayoutParams image3dViewParams;
  //           。
  private VelocityTracker mVelocityTracker;

 public Sliding3DLayout(Context context, AttributeSet attrs){
  super(context, attrs);
  WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
  screenWidth = wm.getDefaultDisplay().getWidth();
  touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
 }

 public Sliding3DLayout(Context context){
  this(context,null);
 }

 /**
  *             ,     ,         。
  * @return           true,      false。
  */
 public boolean isLeftLayoutVisible(){
  return isLeftLayoutVisible;
 }

 /**
  *          View,     View                。
  * @param v
  *       View  。
  */
 public void setScrollEvent(View v){
  mBindView = v;
  mBindView.setOnTouchListener(this);
 }

 @Override
 public boolean onTouch(View v, MotionEvent event){
  createVelocityTracker(event);
  switch(event.getAction()){
  case MotionEvent.ACTION_DOWN:
   xDown = event.getRawX();
   yDown = event.getRawY();
   slideState = DO_NOTHING ;
   break;
  case MotionEvent.ACTION_MOVE:
   //      ,         ,        ,        leftMargin ,           
   xMove = event.getRawX();
   yMove = event.getRawY();

   int moveDistanceX = (int)(xMove - xDown);
   int moveDistanceY = (int)(yMove - yDown);
   checkSlideState(moveDistanceX, moveDistanceY);
   switch(slideState){
   case SHOW_MENU:
    rightLayoutParams.rightMargin = -moveDistanceX;
    onSlide();
    break;
   case HIDE_MENU:
    rightLayoutParams.rightMargin = rightEdge - moveDistanceX;
    onSlide();
    break;
    default:
     break;
   }
   break;
  case MotionEvent.ACTION_UP:
   xUp = event.getRawX();
   int upDistanceX = (int)(xUp - xDown);
   if(isSliding){
    switch (slideState){
    case SHOW_MENU:
     if(shouldScrollToLeftLayout()){
      scrollToLeftLayout();
     }else{
      scrollToRightLayout();
     }
     break;
    case HIDE_MENU:
     if(shouldScrollToRightLayout()){
      scrollToRightLayout();
     }else{
      scrollToLeftLayout();
     }
     break;
    }
   }else if (upDistanceX < touchSlop && isLeftLayoutVisible){
    scrollToRightLayout();
   }
   recycleVelocityTracker();
   break;
  }
  if (v.isEnabled()){
   if (isSliding){
    unFocusBindView();
    return true;
   }
   if (isLeftLayoutVisible) {
    return true;
   }
   return false;
  }
  return true;
 }

 @Override
 protected void onLayout(boolean changed, int l, int t, int r, int b) {
  super.onLayout(changed, l, t, r, b);
  if(changed&&!loadOnce){
   //        
   leftLayout = getChildAt(0);
   leftLayoutParams = (MarginLayoutParams)leftLayout.getLayoutParams();
   rightEdge = -leftLayoutParams.width;

   //      
   rightLayout = getChildAt(1);
   rightLayoutParams = (MarginLayoutParams)rightLayout.getLayoutParams();
   rightLayoutParams.width = screenWidth;
   rightLayout.setLayoutParams(rightLayoutParams);

   image3dView = new Image3DView(getContext());
   /*ViewGroup.LayoutParams params = new LayoutParams(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, 
     android.view.ViewGroup.LayoutParams.WRAP_CONTENT);*/
   image3dView.setVisibility(INVISIBLE);

   addView(image3dView);
   //        3D        
   image3dView.setSourceView(leftLayout);
   loadOnce = true;
  }
 }

 /**
  *   VelocityTracker  。
  */
 private void recycleVelocityTracker() {
  mVelocityTracker.recycle();
  mVelocityTracker = null;
 }

 /**
  *             ,       10.
  */
 public void scrollToLeftLayout(){
  image3dView.clearSourceBitmap();

  new ScrollTask().execute(-10);
 }

 /**
  *             ,       -10.
  */
 public void scrollToRightLayout(){
  image3dView.clearSourceBitmap();
  new ScrollTask().execute(10);
 }

 /**
  *             View      。
  * 
  * @return     ,               。
  */
 private int getScrollVelocity() {
  mVelocityTracker.computeCurrentVelocity(1000);
  int velocity = (int) mVelocityTracker.getXVelocity();
  return Math.abs(velocity);
 }

 /**
  *                  。             1/2,          SNAP_VELOCITY,
  *                 。
  * 
  * @return                  true,    false。
  */
 private boolean shouldScrollToLeftLayout() {
  return xUp - xDown > leftLayoutParams.width / 2 || getScrollVelocity() > SNAP_VELOCITY;
 }

 /**
  *                  。          leftLayoutPadding     1/2,
  *           SNAP_VELOCITY,                 。
  * 
  * @return                  true,    false。
  */
 private boolean shouldScrollToRightLayout(){
  return xDown - xUp > leftLayoutParams.width / 2 || getScrollVelocity() > SNAP_VELOCITY;
 }
 /**
  *             ,     ,     ,      。
  */
 private void onSlide(){
  checkSlideBorder();
  rightLayout.setLayoutParams(rightLayoutParams);
  image3dView.clearSourceBitmap();
  image3dViewParams = image3dView.getLayoutParams();
  image3dViewParams.width = -rightLayoutParams.rightMargin;
  //       3D     
  image3dView.setLayoutParams(image3dViewParams);
  showImage3dView();
 }

 public void toggle(){
  if(isLeftLayoutVisible())
   scrollToRightLayout();
  else
   scrollToLeftLayout();
 }

 /**
  *             ,3D    ,          3D   。
  */
 private void showImage3dView() {
  if (image3dView.getVisibility() != View.VISIBLE) {
   image3dView.setVisibility(View.VISIBLE);
  }
  if (leftLayout.getVisibility() != View.INVISIBLE) {
   leftLayout.setVisibility(View.INVISIBLE);
  }
 }

 /**
  *                 ,          。
  */
 private void checkSlideBorder(){
  if (rightLayoutParams.rightMargin > leftEdge){
   rightLayoutParams.rightMargin = leftEdge;
  } else if (rightLayoutParams.rightMargin < rightEdge) {
   rightLayoutParams.rightMargin = rightEdge;
  }
 }

 /**
  *          ,           ,   slideState           。
  * 
  * @param moveDistanceX
  *          
  * @param moveDistanceY
  *          
  */
 private void checkSlideState(int moveDistanceX, int moveDistanceY) {
  if (isLeftLayoutVisible) {
   //       ,       
   if (!isSliding && Math.abs(moveDistanceX) >= touchSlop && moveDistanceX < 0) {
    isSliding = true;
    slideState = HIDE_MENU;
   }
  }//           
  else if (!isSliding && Math.abs(moveDistanceX) >= touchSlop && moveDistanceX > 0
    && Math.abs(moveDistanceY) < touchSlop) {
   isSliding = true;
   slideState = SHOW_MENU;
  }
 }

 /**
  *   VelocityTracker  ,         VelocityTracker  。
  * 
  * @param event
  *                
  */
 private void createVelocityTracker(MotionEvent event) {
  if (mVelocityTracker == null) {
   mVelocityTracker = VelocityTracker.obtain();
  }
  mVelocityTracker.addMovement(event);
 }

 class ScrollTask extends AsyncTask<Integer, Integer, Integer>{

  @Override
  protected Integer doInBackground(Integer... speed){
   int rightMargin = rightLayoutParams.rightMargin;
   //             ,             ,    。
   while(true){
    rightMargin+=speed[0];
    if (rightMargin < rightEdge) {
     rightMargin = rightEdge;
     break;
    }
    if (rightMargin > leftEdge) {
     rightMargin = leftEdge;
     break;
    }
    publishProgress(rightMargin);
    //           ,         5  ,             。
    sleep(5);
   }
   if (speed[0] > 0){
    isLeftLayoutVisible = false;
   } else {
    isLeftLayoutVisible = true;
   }
   isSliding = false;
   return rightMargin;
  }

  @Override
  protected void onProgressUpdate(Integer... rightMargin) {
   rightLayoutParams.rightMargin = rightMargin[0];
   rightLayout.setLayoutParams(rightLayoutParams);
   image3dViewParams = image3dView.getLayoutParams();
   image3dViewParams.width = -rightLayoutParams.rightMargin;
   image3dView.setLayoutParams(image3dViewParams);
   showImage3dView();
   unFocusBindView();
  }

  @Override
  protected void onPostExecute(Integer rightMargin){
   rightLayoutParams.rightMargin = rightMargin;
   rightLayout.setLayoutParams(rightLayoutParams);
   image3dView.setVisibility(INVISIBLE);
   if (isLeftLayoutVisible){
    leftLayout.setVisibility(View.VISIBLE);
   }
  }

 }

 /**
  *                      。
  */
 private void unFocusBindView() {
  if (mBindView != null) {
   mBindView.setPressed(false);
   mBindView.setFocusable(false);
   mBindView.setFocusableInTouchMode(false);
  }
 }

 /**
  *              。
  * 
  * @param millis
  *             ,      
  */
 private void sleep(long millis) {
  try {
   Thread.sleep(millis);
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
 }
}

  Sliding3DLayout 에 View 가 들 어 왔 습 니 다.이 View 는 효과 그림 의 ListView 입 니 다.왜 이 View 에 들 어 왔 습 니까?우 리 는 미끄럼,즉 ListView 의 미끄럼 을 감시 하고 이 미끄럼 에 따라 메뉴 를 표시 할 지 여 부 를 판단 해 야 하기 때문에 실제 문제 가 발생 했 습 니 다.우 리 는 잠시 후에 이 문 제 를 다시 이야기 하 겠 습 니 다.
  Sliding3DLayout 에는 모두 3 개의 View 대상 이 있 습 니 다.하 나 는 왼쪽 메뉴 View 이 고 하 나 는 메 인 인터페이스의 View 입 니 다.마지막 하 나 는 Image3DView 입 니 다.onLayout 방법 에서 우 리 는 이 세 개의 대상 을 얻어 야 합 니 다.앞의 두 개 는 xml 레이아웃 파일 에서 얻 을 수 있 습 니 다.Sliding3DLayout 에서 우 리 는 썼 고 Image3DView 는 쓰 지 않 았 기 때 문 입 니 다.그래서 대상 을 만 들 고 addView 방법 을 사용 하여 Sliding3DLayout 에 가입 해 야 합 니 다.다음 에 우리 가 얻 어야 할 것 은 MarginLayoutParams 대상 입 니 다.메 인 인터페이스 View 와 Image3DView 대상 의 MarginLayoutParams 를 포함 합 니 다.MarginLayoutParams 대상 이 왜 필요 합 니까?View 의 MarginLayoutParams 대상 을 얻 으 면 rightMargin 속성의 값 을 설정 할 수 있 기 때 문 입 니 다.이 값 은 View 에서 오른쪽 거리 입 니 다.이 값 을 마이너스 로 설정 하면 메 인 화면 에서 rightLayout.setLayoutParams(rightLayoutParams)입 니 다.이 방법 을 사용 하면 메 인 화면 이 오른쪽으로 일정한 거 리 를 이동 하여 메 인 화면 이 오른쪽 을 가리 키 며 미 끄 러 지 는 것 을 실현 하여 애니메이션 의 연속 성 을 실현 한다.
  실현 할 때 제 가 본 적 이 없 는 유형 인 Velocity Tracker 를 사 용 했 습 니 다.곽 신 은 이런 유형 은 손가락 이 미 끄 러 지 는 속 도 를 계산 하 는 것 이 라 고 말 했 습 니 다.구체 적 으로 어떻게 사용 해 야 하 는 지 다음 글 에서 설명 하 겠 습 니 다.
  앞서 언급 한 문 제 는 바로 미끄럼 감청 의 View 를 설정 하 는 것 입 니 다.만약 에 이 View 가 ListView 가 아니 라 ImageView,TextView,LinearLayout 라면 오른쪽으로 미 끄 러 질 때 미 끄 러 지지 않 는 문제 가 발생 할 수 있 습 니 다.여러분 이 직접 해 보 세 요.저도 해결 방법 을 찾 지 못 했 기 때문에 해결 방법 을 찾 으 셨 다 면 저 와 소통 해 주 셨 으 면 좋 겠 습 니 다.
작은 매듭
  마침내 소스 코드 를 다 보 았 는데 곽 신의 실력 에 감 탄 했 습 니 다.코드 는 정말 놀 랍 고 많은 것 을 포함 하여 자신 이 보고 알 게 된 후에 자신 에 게 도 향상 되 었 습 니 다.소스 코드 를 보 는 길이 멀 어 졌 으 면 좋 겠 어 요!
원본 다운로드,점<매트릭스 의 preTranslate()와 post Translate()에 대한 이해>
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기