使用 ViewGroup 自定义 SlidingLayout

public class SlidingLayout extends ViewGroup implements GestureDetector.OnGestureListener {

  private static final int HORIZONTAL_SCROLL_TRIGGER_DISTANCE = 150;
  private static final int VERTICAL_SCROLL_TRIGGER_DISTANCE = 60;
  private View contentView;
  private View menuView;

  private boolean isMenuOpened;
  private boolean isScrolling;
  private Scroller scroller;
  private int distance;
  private GestureDetector gestureDetector;
  private int screenWidth;
  private int screenHeight;
  private int duration;
  private boolean isHorizontalScroll;
  private float touchDownX;
  private float touchDownY;

  public SlidingLayout(Context context) {
    super(context);
    init(context);
  }

  public SlidingLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
    init(context);
  }

  public SlidingLayout(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init(context);
  }

  private void init(Context context) {
    scroller = new Scroller(context);
    gestureDetector = new GestureDetector(context, this);
    isMenuOpened = false;
    isScrolling = false;
    duration = 300;
    distance = 700;
  }

  public void setDistance(int distance) {
    this.distance = distance;
  }

  public void setScreenWidth(int screenWidth) {
    this.screenWidth = screenWidth;
  }

  public void setScreenHeight(int screenHeight) {
    this.screenHeight = screenHeight;
  }

  @Override
  public void computeScroll() {
    if (scroller.computeScrollOffset()) {
      scrollTo(scroller.getCurrX(), scroller.getCurrY());
      postInvalidate();
    }
    super.computeScroll();
  }

  /**
   * When the scroll distance more than HORIZONTAL_SCROLL_TRIGGER_DISTANCE in
   * the horizontal direction, the menu view start to scroll.
   */
  @Override
  public boolean dispatchTouchEvent(MotionEvent ev) {
    Logger.i("sliding layout", "dispatchTouchEvent");
    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
      touchDownX = ev.getX();
      touchDownY = ev.getY();
    } else if (ev.getAction() == MotionEvent.ACTION_MOVE) {
      if (Math.abs(touchDownX - ev.getX()) > HORIZONTAL_SCROLL_TRIGGER_DISTANCE
          && Math.abs(touchDownY - ev.getY()) <= VERTICAL_SCROLL_TRIGGER_DISTANCE) {
        isHorizontalScroll = true;
      }
    } else if (ev.getAction() == MotionEvent.ACTION_UP && isScrolling) {
      slideMenu();
      isHorizontalScroll = false;
    }
    gestureDetector.onTouchEvent(ev);
    return super.dispatchTouchEvent(ev);
  }


  @Override
  protected void onLayout(boolean changed, int l, int t, int r, int b) {
    if (changed) {
      Logger.i("sliding layout", "onLayout");
      contentView = getChildAt(0);
      menuView = getChildAt(1);

      // Set content view full screen.
      contentView.measure(0, 0);
      contentView.layout(0, 0, screenWidth, screenHeight);
    }
  }

  void closeMenu() {
    isMenuOpened = false;
    scroller.startScroll(getScrollX(), 0, -distance, 0, duration);
    invalidate();
  }

  /**
   * Check whether the menu view is opened.
   * 
   * @return true if opened, or false.
   */
  public boolean isOpen() {
    return isMenuOpened;
  }

  private void slideMenu() {
    
    if (getScrollX() < distance / 2) {
      scroller.startScroll(getScrollX(), 0, -getScrollX(), 0, duration);
      isMenuOpened = false;
    } else if (getScrollX() > distance / 2) {
      scroller.startScroll(getScrollX(), 0, distance - getScrollX(), 0, duration);
      isMenuOpened = true;
      menuView.setClickable(true);
    }

    invalidate();
  }

  /**
   * Init menu view.
   */
  @Override
  public boolean onDown(MotionEvent e) {
    menuView.measure(0, 0);
    menuView.layout(screenWidth, 0, screenWidth + distance, screenHeight);
    return true;
  }

  @Override
  public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
    Logger.i("sliding layout", "onScroll: " + getScrollX() + "," + distanceX + ","
        + isMenuOpened);
    if (((getScrollX() > 0 && getScrollX() < distance)
        || (getScrollX() == 0 && distanceX >= 0) || (getScrollX() >= distance && distanceX < 0))
        && isHorizontalScroll) {
      isScrolling = true;
      scrollBy((int) distanceX, 0);
    } else if (getScrollX() > distance && isMenuOpened && distanceX > 0) {
      isScrolling = false;
    }

    return true;
  }

  @Override
  public void onLongPress(MotionEvent e) {
  }

  @Override
  public void onShowPress(MotionEvent e) {
  }

  @Override
  public boolean onSingleTapUp(MotionEvent e) {
    return false;
  }

  @Override
  public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
    return false;
  }

}

你可能感兴趣的:(使用 ViewGroup 自定义 SlidingLayout)