Android SwipeMenuListView 프레임 워 크 상세 분석

주말 에 특별히 Android SwipeMenu ListView(슬라이딩 메뉴)의 지식 자 료 를 정리 합 니 다.다음은 정리 내용 입 니 다.
SwipeMenuListView(슬라이딩 메뉴)
A swipe menu for ListView.아주 좋 은 슬라이딩 메뉴 오픈 소스 항목 입 니 다.
Demo

 프로필
오랫동안 사용자 정의 뷰 와 이벤트 배 포 를 보고 프로젝트 를 찾 아 연습 하고 싶 었 습 니 다.마침 자기가 배 운 것 을 증명 했다.
github 에서 이 항목 을 찾 았 습 니 다.SwipeMenu ListView 는 정말 좋 습 니 다.이벤트 배포 와 사용자 정의 View 에 시사 점 이 있 습 니 다.작은 흠 이 있 지만 나중에 설명 하 겠 습 니 다.미끄럼 메뉴 가 어떻게 실현 되 는 지 알 고 싶 은 학생 은 이 글 이 당신 에 게 절대적 으로 도움 이 되 고 거시적인 미시적 인 측면 에서 모든 파일 을 상세 하 게 분석 했다.
항목 주소:https://github.com/baoyongzhang/SwipeMenuListView/tree/b00e0fe8c2b8d6f08607bfe2ab390c7cee8df274 버 전:b00e0fe 의 사용 은 매우 간단 합 니 다.세 단계 만 있 으 면 github 에서 알 아 볼 수 있 고 지면 을 차지 하지 않 습 니 다.본 고 는 원리 만 분석 합 니 다.그리고 만약 에 코드 를 보면 나 와 느낌 이 다 르 고 어려워 보인다 면 내 가 주석 을 달 았 던 것 을 볼 수 있다.http://download.csdn.net/detail/jycboy/9667699
먼저 두 개의 그림 을 보 세 요.하 나 는 대체적인 이해 가 있 습 니 다.
  이것 은 프레임 의 모든 유형 이다.
1.아래 그림 은 보기 차원:

위의 그림 에서:SwipeMenuLayout 는 ListView 에서 item 의 레이아웃 으로 좌우 두 부분 으로 나 뉘 는데 일 부 는 정상적으로 표 시 된 contentView 이 고 일 부 는 미 끄 러 진 menuView 이다.미 끄 러 진 SwipeMenuView 는 LinearLayout 에서 계승 되 고 view 를 추가 할 때 가로 로 추가 되 며 가로 로 여러 개 를 추가 할 수 있 습 니 다.
2.아래 의 그림 은 도표 구조 이다.

위 는 클래스 간 의 호출 관계 로 클래스 옆 에 클래스 의 주요 역할 을 표시 했다.
2.소스 코드 분석
SwipeMenu,SwipeMenu Item 은 실체 류 로 속성 과 setter,getter 방법 을 정 의 했 습 니 다.보시 면 됩 니 다.기본적으로 소스 코드 의 주석 이 매우 명확 하 다.
2.1 SwipeMenuView:코드 에 주석 이 잘 달 려 있 습 니 다.

/**
 *    LinearLayout,    swipemenu    
 *        Item    Item     
 * @author baoyz
 * @date 2014-8-23
 *
 */
public class SwipeMenuView extends LinearLayout implements OnClickListener {
 
  private SwipeMenuListView mListView;
  private SwipeMenuLayout mLayout;
  private SwipeMenu mMenu;
  private OnSwipeItemClickListener onItemClickListener;
  private int position;
 
  public int getPosition() {
    return position;
  }
 
  public void setPosition(int position) {
    this.position = position;
  }
 
  public SwipeMenuView(SwipeMenu menu, SwipeMenuListView listView) {
    super(menu.getContext());
    mListView = listView;
    mMenu = menu; //
    // MenuItem list  
    List<SwipeMenuItem> items = menu.getMenuItems();
    int id = 0;
    //  item   View   SwipeMenuView 
    for (SwipeMenuItem item : items) {
      addItem(item, id++);
    }
  }
  /**
   *   MenuItem     UI  ,  item         LinearLayout,
   * SwipeMenuView     LinearLayout,
   */
  private void addItem(SwipeMenuItem item, int id) {
    //    
    LayoutParams params = new LayoutParams(item.getWidth(),
        LayoutParams.MATCH_PARENT);
 
    LinearLayout parent = new LinearLayout(getContext());
    //  menuitem id,           item  
    parent.setId(id);
    parent.setGravity(Gravity.CENTER);
    parent.setOrientation(LinearLayout.VERTICAL);
    parent.setLayoutParams(params);
    parent.setBackgroundDrawable(item.getBackground());
    //     
    parent.setOnClickListener(this);
    addView(parent); //   SwipeMenuView ,   
 
    if (item.getIcon() != null) {
      parent.addView(createIcon(item));
    }
    if (!TextUtils.isEmpty(item.getTitle())) {
      parent.addView(createTitle(item));
    }
  }
  //  img
  private ImageView createIcon(SwipeMenuItem item) {
    ImageView iv = new ImageView(getContext());
    iv.setImageDrawable(item.getIcon());
    return iv;
  }
  /*      title
   */
  private TextView createTitle(SwipeMenuItem item) {
    TextView tv = new TextView(getContext());
    tv.setText(item.getTitle());
    tv.setGravity(Gravity.CENTER);
    tv.setTextSize(item.getTitleSize());
    tv.setTextColor(item.getTitleColor());
    return tv;
  }
 
  @Override
  /**
   *     mLayout      
   *   onItemClick    
   */
  public void onClick(View v) {
    if (onItemClickListener != null && mLayout.isOpen()) {
      onItemClickListener.onItemClick(this, mMenu, v.getId());
    }
  }
 
  public OnSwipeItemClickListener getOnSwipeItemClickListener() {
    return onItemClickListener;
  }
 
  /**
   *   item     
   * @param onItemClickListener
   */
  public void setOnSwipeItemClickListener(OnSwipeItemClickListener onItemClickListener) {
    this.onItemClickListener = onItemClickListener;
  }
 
  public void setLayout(SwipeMenuLayout mLayout) {
    this.mLayout = mLayout;
  }
 
  /**
   *          
   */
  public static interface OnSwipeItemClickListener {
    /**
     * onClick       onItemClick
     * @param view    
     * @param menu menu   
     * @param index menuItem id
     */
    void onItemClick(SwipeMenuView view, SwipeMenu menu, int index);
  }
}
**SwipeMenuView 는 미끄럼 할 때 보 이 는 View 입 니 다.그의 구조 함수 SwipeMenuView(SwipeMenu menu,SwipeMenuListView listView)를 보십시오.항목:menu.getMenuItems()옮 겨 다 니 기;addItem 방법 을 사용 하여 SwipeMenuView 에 item 을 추가 합 니 다.
addItem 방법 에서:모든 아 이 템 은 LinearLayout 입 니 다.
2.2 SwipeMenuLayout​:
이런 종류의 코드 는 좀 길 어서 우 리 는 세 부분 으로 나 누 어 보고 핵심 코드 만 붙 이 고 나머지 는 보면 알 수 있 을 것 이다.

public class SwipeMenuLayout extends FrameLayout {
 
  private static final int CONTENT_VIEW_ID = 1;
  private static final int MENU_VIEW_ID = 2;
 
  private static final int STATE_CLOSE = 0;
  private static final int STATE_OPEN = 1;
  //  
  private int mSwipeDirection;
  private View mContentView;
  private SwipeMenuView mMenuView;
  。。。。。
  public SwipeMenuLayout(View contentView, SwipeMenuView menuView) {
    this(contentView, menuView, null, null);
  }
 
  public SwipeMenuLayout(View contentView, SwipeMenuView menuView,
      Interpolator closeInterpolator, Interpolator openInterpolator) {
    super(contentView.getContext());
    mCloseInterpolator = closeInterpolator;
    mOpenInterpolator = openInterpolator;
    mContentView = contentView;
    mMenuView = menuView;
    // SwipeMenuLayout   SwipeMenuView,        
    mMenuView.setLayout(this);
    init();
  }
  private void init() {
    setLayoutParams(new AbsListView.LayoutParams(LayoutParams.MATCH_PARENT,
        LayoutParams.WRAP_CONTENT));
 
    mGestureListener = new SimpleOnGestureListener() {
      @Override
      public boolean onDown(MotionEvent e) {
        isFling = false;
        return true;
      }
 
      @Override
      //velocityX     x      ,     ,     
      public boolean onFling(MotionEvent e1, MotionEvent e2,
          float velocityX, float velocityY) {
        // TODO
        if (Math.abs(e1.getX() - e2.getX()) > MIN_FLING
            && velocityX < MAX_VELOCITYX) {
          isFling = true;
        }
        Log.i("tag","isFling="+isFling+" e1.getX()="+e1.getX()+" e2.getX()="+e2.getX()+
            " velocityX="+velocityX+" MAX_VELOCITYX="+MAX_VELOCITYX);
        // Log.i("byz", MAX_VELOCITYX + ", velocityX = " + velocityX);
        return super.onFling(e1, e2, velocityX, velocityY);
      }
    };
    mGestureDetector = new GestureDetectorCompat(getContext(),
        mGestureListener);
 
    。。。。
 
    LayoutParams contentParams = new LayoutParams(
        LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
    mContentView.setLayoutParams(contentParams);
    if (mContentView.getId() < 1) {
      //noinspection ResourceType
      mContentView.setId(CONTENT_VIEW_ID);
    }
    //noinspection ResourceType
    mMenuView.setId(MENU_VIEW_ID);
    mMenuView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
        LayoutParams.WRAP_CONTENT));
 
    addView(mContentView);
    addView(mMenuView);
 
  }
위의 init 방법 에서 볼 수 있 듯 이 SwipeMenu Layout 는 두 부분 으로 구성 되 는데 각각 사용자 의 item View 와 menu View 이다.손가락 이 미 끄 러 지 는 동작 은 통과 입 니 다.  SimpleOnGestureListener  완성 하 겠 습 니 다.

/**
   *     ,         
   *          API,     API  SwipeMenuListView,  MotionEvent SwipeMenuListView MotionEvent
   * @param event
   * @return
   */
  public boolean onSwipe(MotionEvent event) {
    mGestureDetector.onTouchEvent(event);
    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
      mDownX = (int) event.getX();//     x  
      isFling = false;
      break;
    case MotionEvent.ACTION_MOVE:
      // Log.i("byz", "downX = " + mDownX + ", moveX = " + event.getX());
      int dis = (int) (mDownX - event.getX());
      if (state == STATE_OPEN) {//    open ,dis  0
        Log.i("tag", "dis = " + dis);//      0
        //DIRECTION_LEFT = 1 || DIRECTION_RIGHT = -1
        dis += mMenuView.getWidth()*mSwipeDirection;//mSwipeDirection=1
        Log.i("tag", "dis = " + dis + ", mSwipeDirection = " + mSwipeDirection);
      }
      Log.i("tag", "ACTION_MOVE downX = " + mDownX + ", moveX = " + event.getX()+", dis="+dis);
      swipe(dis);
      break;
    case MotionEvent.ACTION_UP:
      //      ,       
      //   ,       item   ,         item,        ,    ?
      if ((isFling || Math.abs(mDownX - event.getX()) > (mMenuView.getWidth() / 2)) &&
          Math.signum(mDownX - event.getX()) == mSwipeDirection) {
        Log.i("tag", "ACTION_UP downX = " + mDownX + ", moveX = " + event.getX());
        // open
        smoothOpenMenu();
      } else {
        // close
        smoothCloseMenu();
        return false;
      }
      break;
    }
    return true;
  }
 
  public boolean isOpen() {
    return state == STATE_OPEN;
  }
  /**
   *   dis   , mContentView mMenuView   dis  
   * @param dis
   */
  private void swipe(int dis) {
    if(!mSwipEnable){
      return ;
    }
    //left is positive;right is negative
    if (Math.signum(dis) != mSwipeDirection) {//left=1;right =-1
      dis = 0; //   
    } else if (Math.abs(dis) > mMenuView.getWidth()) {//      ,dis  mMenuView.getWidth()
      dis = mMenuView.getWidth()*mSwipeDirection;
    }
    //      ,    (    ),
    mContentView.layout(-dis, mContentView.getTop(),
        mContentView.getWidth() -dis, getMeasuredHeight());
 
    if (mSwipeDirection == SwipeMenuListView.DIRECTION_LEFT) {//1
      //      menuview   ,     
      mMenuView.layout(mContentView.getWidth() - dis, mMenuView.getTop(),
          mContentView.getWidth() + mMenuView.getWidth() - dis,
          mMenuView.getBottom());
    } else {
      mMenuView.layout(-mMenuView.getWidth() - dis, mMenuView.getTop(),
          - dis, mMenuView.getBottom());
    }
  }
  /**
   *     state = STATE_CLOSE;
   *   menu
   */
  public void smoothCloseMenu() {
    state = STATE_CLOSE;
    if (mSwipeDirection == SwipeMenuListView.DIRECTION_LEFT) {
      mBaseX = -mContentView.getLeft();
      //  mMenuView.getWidth()   ,     
      mCloseScroller.startScroll(0, 0, mMenuView.getWidth(), 0, 350);
    } else {
      mBaseX = mMenuView.getRight();
      mCloseScroller.startScroll(0, 0, mMenuView.getWidth(), 0, 350);
    }
    postInvalidate();
  }
 
  public void smoothOpenMenu() {
    if(!mSwipEnable){
      return ;
    }
    state = STATE_OPEN;
    if (mSwipeDirection == SwipeMenuListView.DIRECTION_LEFT) {
      mOpenScroller.startScroll(-mContentView.getLeft(), 0, mMenuView.getWidth(), 0, 350);
      Log.i("tag","mContentView.getLeft()="+mContentView.getLeft()+", mMenuView="+mMenuView.getWidth());//-451,       dis,-(downX-moveX)
      //mContentView.getLeft()=-540, mMenuView=540 ,          ,    !  ・
    } else {
      mOpenScroller.startScroll(mContentView.getLeft(), 0, mMenuView.getWidth(), 0, 350);
    }
    //  ui thread       ,     
    postInvalidate();
  }
  。。。
}
위의 주요 방법 은 onSwipe 와 swipe 두 가지 방법 입 니 다.주요 논 리 는 onSwipe 는 외부 에서 호출 된 API 입 니 다.
SwipeMenuListView 의 onTouchEvent 이벤트 처리 방법 에서 onSwipe 를 호출 했 습 니 다.스 와 이 프 는 mContentView 와 mMenuView 를 모두 dis 거 리 를 미 끄 러 뜨리 는 것 이다.

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    //        ,      
    mMenuView.measure(MeasureSpec.makeMeasureSpec(0,
        MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(
        getMeasuredHeight(), MeasureSpec.EXACTLY));
  }
  protected void onLayout(boolean changed, int l, int t, int r, int b) {
    mContentView.layout(0, 0, getMeasuredWidth(),
        mContentView.getMeasuredHeight());
    if (mSwipeDirection == SwipeMenuListView.DIRECTION_LEFT) {//  
      //    view,         ,     
      mMenuView.layout(getMeasuredWidth(), 0,
          getMeasuredWidth() + mMenuView.getMeasuredWidth(),
          mContentView.getMeasuredHeight());
    } else {  //  ,     
      mMenuView.layout(-mMenuView.getMeasuredWidth(), 0,
          0, mContentView.getMeasuredHeight());
    }
  }
위의 onMeasure,onLayout 방법 은 View 에서 자주 다시 쓰 는 방법 을 사용자 정의 하 는 것 입 니 다.onMeasure 는 view 의 크기 를 측정 하 는 것 입 니 다.여 기 는 너비 유형 을 UNSPECIFIED 로 설정 하여 무한 확장 할 수 있 습 니 다.onLayout 는 view 의 크기 를 측정 한 후에 view 를 부모 레이아웃 의 어떤 위치 에 두 었 는 지 코드 에서 미끄럼 방향 에 따라 menuView 가 왼쪽(또는 오른쪽)에 숨 어 있 는 지 알 수 있 습 니 다.
2.3 SwipeMenuAdapter

public class SwipeMenuAdapter implements WrapperListAdapter,
    OnSwipeItemClickListener {
 
  private ListAdapter mAdapter;
  private Context mContext;
  private SwipeMenuListView.OnMenuItemClickListener onMenuItemClickListener;
 
  public SwipeMenuAdapter(Context context, ListAdapter adapter) {
    mAdapter = adapter;
    mContext = context;
  }
  。。。。
  /**
   *            
   *           Item    SwipeMenuLayout
   */
  public View getView(int position, View convertView, ViewGroup parent) {
    SwipeMenuLayout layout = null;
    if (convertView == null) {
      View contentView = mAdapter.getView(position, convertView, parent);//item view
      SwipeMenu menu = new SwipeMenu(mContext); //  SwipeMenu
      menu.setViewType(getItemViewType(position));
      createMenu(menu); //   ,     
      SwipeMenuView menuView = new SwipeMenuView(menu,
          (SwipeMenuListView) parent);
      menuView.setOnSwipeItemClickListener(this);
      SwipeMenuListView listView = (SwipeMenuListView) parent;
      layout = new SwipeMenuLayout(contentView, menuView,
          listView.getCloseInterpolator(),
          listView.getOpenInterpolator());
      layout.setPosition(position);
    } else {
      layout = (SwipeMenuLayout) convertView;
      layout.closeMenu();
      layout.setPosition(position);
      View view = mAdapter.getView(position, layout.getContentView(),
          parent);
    }
    if (mAdapter instanceof BaseSwipListAdapter) {
      boolean swipEnable = (((BaseSwipListAdapter) mAdapter).getSwipEnableByPosition(position));
      layout.setSwipEnable(swipEnable);
    }
    return layout;
  }
  //        ,   ,       ,    。
  public void createMenu(SwipeMenu menu) {
    // Test Code
   。。。。。。
  }
  /**
   * OnSwipeItemClickListener     
   *           ,   。
   */
  public void onItemClick(SwipeMenuView view, SwipeMenu menu, int index) {
    if (onMenuItemClickListener != null) {
      onMenuItemClickListener.onMenuItemClick(view.getPosition(), menu,
          index);
    }
  }
  。。。。//       
}
2.4 핵심 클래스:SwipeMenuListview,
이 코드 는 매우 길 어서 볼 때 인내심 이 필요 하 다.

public class SwipeMenuListView extends ListView {
 
  private static final int TOUCH_STATE_NONE = 0;
  private static final int TOUCH_STATE_X = 1;
  private static final int TOUCH_STATE_Y = 2;
 
  public static final int DIRECTION_LEFT = 1; //  
  public static final int DIRECTION_RIGHT = -1;
  private int mDirection = 1;//swipe from right to left by default
 
  private int MAX_Y = 5;
  private int MAX_X = 3;
  private float mDownX;
  private float mDownY;
  private int mTouchState;
  private int mTouchPosition;
 
  private SwipeMenuLayout mTouchView;
  private OnSwipeListener mOnSwipeListener;
  //  menuItem 
  private SwipeMenuCreator mMenuCreator;
  //menuItem item    
  private OnMenuItemClickListener mOnMenuItemClickListener;
  private OnMenuStateChangeListener mOnMenuStateChangeListener;
  private Interpolator mCloseInterpolator; //     
  private Interpolator mOpenInterpolator;
 
  //----added in myself--           ,
  //        demo       ,   item     ,     item,       item    ,    QQ   ,     ,          。
  private int mOldTouchPosition = -1;
  private boolean shouldCloseMenu;
  //--------
 
  public SwipeMenuListView(Context context) {
    super(context);
    init();
  }
 
  public SwipeMenuListView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init();
  }
 
  public SwipeMenuListView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init();
  }
  //     
  private void init() {
    MAX_X = dp2px(MAX_X);
    MAX_Y = dp2px(MAX_Y);
    mTouchState = TOUCH_STATE_NONE;
  }
 
  @Override
  /**
   *    adapter       ,   SwipeMenuAdapter
   */
  public void setAdapter(ListAdapter adapter) {
    super.setAdapter(new SwipeMenuAdapter(getContext(), adapter) {
      @Override
      public void createMenu(SwipeMenu menu) {
        if (mMenuCreator != null) {
          mMenuCreator.create(menu);
        }
      }
 
      @Override
      public void onItemClick(SwipeMenuView view, SwipeMenu menu,
                  int index) {
        boolean flag = false;
        if (mOnMenuItemClickListener != null) {
          flag = mOnMenuItemClickListener.onMenuItemClick(
              view.getPosition(), menu, index);
        }
        //    list  item  menu
        if (mTouchView != null && !flag) {
          mTouchView.smoothCloseMenu();
        }
      }
    });
  }
  。。。。。
  @Override
  //    ,               
  public boolean onInterceptTouchEvent(MotionEvent ev) {
    //      ,               swip,               
    int action = ev.getAction();
    switch (action) {
      case MotionEvent.ACTION_DOWN:
        mDownX = ev.getX();
        mDownY = ev.getY();
        boolean handled = super.onInterceptTouchEvent(ev);
        mTouchState = TOUCH_STATE_NONE; //  Down         
        //  item position
        mTouchPosition = pointToPosition((int) ev.getX(), (int) ev.getY());
 
        //       item   view,  SwipeMenuLayout
        View view = getChildAt(mTouchPosition - getFirstVisiblePosition());
        //                  ,    open  
        if (view instanceof SwipeMenuLayout) {
          //          .mTouchView SwipeMenuLayout
          //       mTouchView,  mTouchView;      view,     true
          if (mTouchView != null && mTouchView.isOpen() && !inRangeOfView(mTouchView.getMenuView(), ev)) {
            Log.i("tag","Listview  onInterceptTouchEvent ACTION_DOWN。");
            return true;
          }
          mTouchView = (SwipeMenuLayout) view;
          mTouchView.setSwipeDirection(mDirection);//   left=1
        }
        //        view,     
        if (mTouchView != null && mTouchView.isOpen() && view != mTouchView) {
          handled = true;
        }
 
        if (mTouchView != null) {
          mTouchView.onSwipe(ev);
        }
        return handled;
      case MotionEvent.ACTION_MOVE: //MOVE     , onTouch     
        float dy = Math.abs((ev.getY() - mDownY));
        float dx = Math.abs((ev.getX() - mDownX));
        if (Math.abs(dy) > MAX_Y || Math.abs(dx) > MAX_X) {
          //     down          TOUCH_STATE_NONE     true   onTouchEvent          
          if (mTouchState == TOUCH_STATE_NONE) {
            if (Math.abs(dy) > MAX_Y) {
              mTouchState = TOUCH_STATE_Y;
            } else if (dx > MAX_X) {
              mTouchState = TOUCH_STATE_X;
              if (mOnSwipeListener != null) {
                mOnSwipeListener.onSwipeStart(mTouchPosition);
              }
            }
          }
          return true;
        }
    }
    return super.onInterceptTouchEvent(ev);
  }
 
  @Override
  public boolean onTouchEvent(MotionEvent ev) {
    if (ev.getAction() != MotionEvent.ACTION_DOWN && mTouchView == null)
      return super.onTouchEvent(ev);
    int action = ev.getAction();
    switch (action) {
      case MotionEvent.ACTION_DOWN: //  DOWN             ,        :1. menu     ,      item  
                      //2.menu     ,      item
                      //3.  item , DOWN MOVE
        Log.i("tag","Listview  onTouchEvent ACTION_DOWN。        item");
        int oldPos = mTouchPosition; //       ,onInterceptTouchEvent           ,mTouchPosition    
        if(mOldTouchPosition == -1){//-1 is the original value
          mOldTouchPosition = mTouchPosition;
        }
        mDownX = ev.getX();
        mDownY = ev.getY();
        mTouchState = TOUCH_STATE_NONE;
 
        mTouchPosition = pointToPosition((int) ev.getX(), (int) ev.getY());//list 
        //    ,pldPos   ,  mOldTouchPosition
        if (mTouchPosition == mOldTouchPosition && mTouchView != null
            && mTouchView.isOpen()) {
          mTouchState = TOUCH_STATE_X; //x  (  )  
          //  SwipeMenuLayout onSwipe()    
          mTouchView.onSwipe(ev);
          Log.i("tag","Listview  onTouchEvent ACTION_DOWN。          item");
          return true;
        }
      if(mOldTouchPosition != mTouchPosition){ //when the DOWN position is different
          //shouldCloseMenu = true;
          mOldTouchPosition = mTouchPosition;
        }
        View view = getChildAt(mTouchPosition - getFirstVisiblePosition());
        //     menu   ,          item
        //          !
        if (mTouchView != null && mTouchView.isOpen()) {
          //  swipeMenu
          mTouchView.smoothCloseMenu();
          mTouchView = null;
          // return super.onTouchEvent(ev);
          // try to cancel the touch event
          MotionEvent cancelEvent = MotionEvent.obtain(ev);
          cancelEvent.setAction(MotionEvent.ACTION_CANCEL);
          onTouchEvent(cancelEvent); //    ,    
 
          //  menu close   
          if (mOnMenuStateChangeListener != null) {
            mOnMenuStateChangeListener.onMenuClose(oldPos);
          }
          return true;
        }
 
        if (view instanceof SwipeMenuLayout) {
          mTouchView = (SwipeMenuLayout) view;
          mTouchView.setSwipeDirection(mDirection);
        }
        if (mTouchView != null) {
          mTouchView.onSwipe(ev);
        }
        break;
      case MotionEvent.ACTION_MOVE:
        //     header,   header   
        mTouchPosition = pointToPosition((int) ev.getX(), (int) ev.getY()) - getHeaderViewsCount();
        //            ,    ,   mTouchView    ,          swip view
        //   mTouchView swip 。                 view
        if (!mTouchView.getSwipEnable() || mTouchPosition != mTouchView.getPosition()) {
          break;
        }
        float dy = Math.abs((ev.getY() - mDownY));
        float dx = Math.abs((ev.getX() - mDownX));
        if (mTouchState == TOUCH_STATE_X) { //X    
          if (mTouchView != null) {
            mTouchView.onSwipe(ev); //      
          }
          getSelector().setState(new int[]{0});
          ev.setAction(MotionEvent.ACTION_CANCEL);
          super.onTouchEvent(ev);//    
          return true;
        } else if (mTouchState == TOUCH_STATE_NONE) {//DOWN    Move
          if (Math.abs(dy) > MAX_Y) {
            mTouchState = TOUCH_STATE_Y;
          } else if (dx > MAX_X) {
            mTouchState = TOUCH_STATE_X;
            if (mOnSwipeListener != null) {
              mOnSwipeListener.onSwipeStart(mTouchPosition);
            }
          }
        }
        break;
      case MotionEvent.ACTION_UP: //   menu
        Log.i("tag","onTouchEvent   ACTION_UP");
        if (mTouchState == TOUCH_STATE_X) {
          if (mTouchView != null) {
            Log.i("tag","onTouchEvent   ACTION_UP        ");
            boolean isBeforeOpen = mTouchView.isOpen();
            //      
            mTouchView.onSwipe(ev);
            boolean isAfterOpen = mTouchView.isOpen();
            if (isBeforeOpen != isAfterOpen && mOnMenuStateChangeListener != null) {
              if (isAfterOpen) {
                mOnMenuStateChangeListener.onMenuOpen(mTouchPosition);
              } else {
                mOnMenuStateChangeListener.onMenuClose(mTouchPosition);
              }
            }
            if (!isAfterOpen) {
              mTouchPosition = -1;
              mTouchView = null;
            }
          }
          if (mOnSwipeListener != null) {
            //         
            mOnSwipeListener.onSwipeEnd(mTouchPosition);
          }
          ev.setAction(MotionEvent.ACTION_CANCEL);
          super.onTouchEvent(ev);
          return true;
        }
        break;
    }
    return super.onTouchEvent(ev);
  }
 
  public void smoothOpenMenu(int position) {
    if (position >= getFirstVisiblePosition()
        && position <= getLastVisiblePosition()) {
      View view = getChildAt(position - getFirstVisiblePosition());
      if (view instanceof SwipeMenuLayout) {
        mTouchPosition = position;
        if (mTouchView != null && mTouchView.isOpen()) {
          mTouchView.smoothCloseMenu();
        }
        mTouchView = (SwipeMenuLayout) view;
        mTouchView.setSwipeDirection(mDirection);
        mTouchView.smoothOpenMenu();
      }
    }
  }
  /**
   *         ,               px,   dp->px
   * @param dp
   * @return
   */
  private int dp2px(int dp) {
    return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,
        getContext().getResources().getDisplayMetrics());
  }
  public static interface OnMenuItemClickListener {
    boolean onMenuItemClick(int position, SwipeMenu menu, int index);
  }
 
  public static interface OnSwipeListener {
    void onSwipeStart(int position);
 
    void onSwipeEnd(int position);
  }
 
  public static interface OnMenuStateChangeListener {
    void onMenuOpen(int position);
 
    void onMenuClose(int position);
  }
  。。。。
}
이런 유형 에서 가장 중요 한 논 리 는 사건 에 대한 판단 과 배포,언제 사건 을 차단 하고 서로 다른 사건 이 어떤 조작 에 대응 하 는 지 하 는 것 이다.사건 에 대해 잘 모 르 는 친구 들 이 인터넷 에서 관련 블 로 그 를 찾 아 볼 수도 있 고 제 후속 블 로 그 를 볼 수도 있 습 니 다.이틀 동안 해 야 할 일 입 니 다.
여기 서 SwipeMenuListView 의 이벤트 배포 논 리 를 분석 합 니 다.핵심 은 SwipeMenuListView 에서 item 의 클릭 이벤트 와 미끄럼 이벤트 의 처리 입 니 다.미 끄 러 질 때 SwipeMenu ListView 차단 사건 은 스스로 처리 하고 이 논 리 를 기억 하 며 코드 를 보면 한눈 에 알 수 있 습 니 다.다음은 제 가 그린 사건 배포 절차 도 입 니 다.

터치 이 벤트 는 이벤트 시퀀스 입 니 다:ACTIONDOWN->ACTION_MOVE->....ACTION_MOVE->ACTION_UP.ACTION 으로DOWN 부터,ACTION 으로UP 종료.
다음은 제 인쇄 프로 세 스 입 니 다.(코드 에 로그 추가)

I/tag: Listview  onInterceptTouchEvent ACTION_DOWN。view=class com.baoyz.swipemenulistview.SwipeMenuLayout
I/tag: onInterceptTouchEvent ACTION_DOWN handled=false
I/tag: SwipeMenuLayout onTouchEvent
I/tag: Listview  onTouchEvent ACTION_DOWN。        item
I/tag: oldPos=1 mTouchPosition=1
I/tag: ACTION_MOVE downX = 987, moveX = 906.69666, dis=80
I/tag: ACTION_MOVE downX = 987, moveX = 855.5785, dis=131
I/tag: ACTION_MOVE downX = 987, moveX = 797.6258, dis=189
I/tag: ACTION_MOVE downX = 987, moveX = 735.9639, dis=251
I/tag: ACTION_MOVE downX = 987, moveX = 666.5104, dis=320
I/tag: ACTION_MOVE downX = 987, moveX = 589.0626, dis=397
I/tag: ACTION_MOVE downX = 987, moveX = 509.15567, dis=477
I/tag: ACTION_MOVE downX = 987, moveX = 431.7224, dis=555
I/tag: ACTION_MOVE downX = 987, moveX = 361.2613, dis=625
I/tag: ACTION_MOVE downX = 987, moveX = 319.70398, dis=667
I/tag: onTouchEvent   ACTION_UP
I/tag: onTouchEvent   ACTION_UP        
I/tag: isFling=true e1.getX()=987.08606 e2.getX()=319.70398 velocityX=-4122.911 MAX_VELOCITYX=-1500
I/tag: ACTION_UP downX = 987, moveX = 319.70398
I/tag: mContentView.getLeft()=-540, mMenuView=540
 3.존재 하 는 문제
1.프레임 워 크 를 내 려 놓 고 실행 하면 질문 하 나 를 발견 할 수 있 습 니 다.
  ListView 의 item 이 미 끄 러 졌 을 때 item 1 로 가정 합 니 다.이 때 다른 아 이 템 을 미 끄 러 뜨 려 item 2 라 고 합 니 다.
  이 경우 item 1 이 닫 히 지 않 고 item 2 도 당연히 열 리 지 않 습 니 다.
  이런 효 과 는 결코 좋 지 않다.나 는 코드 에서 이미 이 문 제 를 수정 했다.구체 적 인 코드 는 내 가 이미 표시 했다.
2.바로 아래 코드 입 니 다.SwipeMenu ListView 의 onTouchEvent(MotionEvent ev)의 ACTIONDOWN 에서 이 코드 는 onTouchEvent 와 onInterceptTouchEvent 에 대응 하 는 MotionEvent 때문에 영원히 실행 되 지 않 습 니 다.
mTouchPosition==oldPos 는 영원히 같다.

//          !       mTouchPosition != oldPos CloseMenu,                  ,
        //        MotionEvent      
        if (mTouchView != null && mTouchView.isOpen()) {
          //  swipeMenu
          mTouchView.smoothCloseMenu();
          //mTouchView = null;
          // return super.onTouchEvent(ev);
          // try to cancel the touch event
          MotionEvent cancelEvent = MotionEvent.obtain(ev);
          cancelEvent.setAction(MotionEvent.ACTION_CANCEL);
          onTouchEvent(cancelEvent); //    ,    
 
          //  menu close   
          if (mOnMenuStateChangeListener != null) {
            mOnMenuStateChangeListener.onMenuClose(oldPos);
          }
          return true;
        }
코드 에서 나 는 이미 이 문 제 를 수정 했다.현재 github 에 원작 자 에 게 제출 되 었 습 니 다.
읽 어 주 셔 서 감사합니다. 여러분 에 게 도움 이 되 기 를 바 랍 니 다.본 사이트 에 대한 여러분 의 지지 에 감 사 드 립 니 다!

좋은 웹페이지 즐겨찾기