Пример #1
0
  public SwipeBackLayout(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs);
    mDragHelper = ViewDragHelper.create(this, new ViewDragCallback());

    TypedArray a =
        context.obtainStyledAttributes(
            attrs, R.styleable.SwipeBackLayout, defStyle, R.style.SwipeBackLayout);

    int edgeSize = a.getDimensionPixelSize(R.styleable.SwipeBackLayout_edge_size, -1);
    if (edgeSize > 0) setEdgeSize(edgeSize);
    int mode = EDGE_FLAGS[a.getInt(R.styleable.SwipeBackLayout_edge_flag, 0)];
    setEdgeTrackingEnabled(mode);

    int shadowLeft =
        a.getResourceId(R.styleable.SwipeBackLayout_shadow_left, R.drawable.shadow_left);
    int shadowRight =
        a.getResourceId(R.styleable.SwipeBackLayout_shadow_right, R.drawable.shadow_right);
    int shadowBottom =
        a.getResourceId(R.styleable.SwipeBackLayout_shadow_bottom, R.drawable.shadow_bottom);
    setShadow(shadowLeft, EDGE_LEFT);
    setShadow(shadowRight, EDGE_RIGHT);
    setShadow(shadowBottom, EDGE_BOTTOM);
    a.recycle();
    final float density = getResources().getDisplayMetrics().density;
    final float minVel = MIN_FLING_VELOCITY * density;
    mDragHelper.setMinVelocity(minVel);
    mDragHelper.setMaxVelocity(minVel * 2f);
  }
  public CardSlidePanel(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.card);

    bottomMarginTop = (int) a.getDimension(R.styleable.card_bottomMarginTop, bottomMarginTop);
    yOffsetStep = (int) a.getDimension(R.styleable.card_yOffsetStep, yOffsetStep);
    // 滑动相关类
    mDragHelper = ViewDragHelper.create(this, 10f, new DragHelperCallback());
    mDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);
    a.recycle();
  }
  @Override
  public void computeScroll() {
    if (mDragHelper != null && mDragHelper.continueSettling(true)) {
      if (!isEnabled()) {
        mDragHelper.abort();
        return;
      }

      ViewCompat.postInvalidateOnAnimation(this);
    }
  }
  @Override
  public boolean onInterceptTouchEvent(MotionEvent ev) {
    final int action = MotionEventCompat.getActionMasked(ev);

    if (!isEnabled()
        || !isTouchEnabled()
        || (mIsUnableToDrag && action != MotionEvent.ACTION_DOWN)) {
      mDragHelper.cancel();
      return super.onInterceptTouchEvent(ev);
    }

    if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
      mDragHelper.cancel();
      return false;
    }

    final float x = ev.getX();
    final float y = ev.getY();

    switch (action) {
      case MotionEvent.ACTION_DOWN:
        {
          mIsUnableToDrag = false;
          mInitialMotionX = x;
          mInitialMotionY = y;
          break;
        }

      case MotionEvent.ACTION_MOVE:
        {
          final float adx = Math.abs(x - mInitialMotionX);
          final float ady = Math.abs(y - mInitialMotionY);
          final int dragSlop = mDragHelper.getTouchSlop();

          // Handle any horizontal scrolling on the drag view.
          if (mIsUsingDragViewTouchEvents && adx > dragSlop && ady < dragSlop) {
            return super.onInterceptTouchEvent(ev);
          }

          if ((ady > dragSlop && adx > ady)
              || !isDragViewUnder((int) mInitialMotionX, (int) mInitialMotionY)) {
            mDragHelper.cancel();
            mIsUnableToDrag = true;
            return false;
          }
          break;
        }
    }

    return mDragHelper.shouldInterceptTouchEvent(ev);
  }
 @Override
 public void computeScroll() {
   if (mDragHelper.continueSettling(true)) {
     ViewCompat.postInvalidateOnAnimation(this);
   } else {
     // 动画结束
     synchronized (this) {
       if (mDragHelper.getViewDragState() == ViewDragHelper.STATE_IDLE) {
         orderViewStack();
         btnLock = false;
       }
     }
   }
 }
  /* touch事件的拦截与处理都交给mDraghelper来处理 */
  @Override
  public boolean onInterceptTouchEvent(MotionEvent ev) {
    boolean shouldIntercept = mDragHelper.shouldInterceptTouchEvent(ev);
    int action = ev.getActionMasked();
    if (action == MotionEvent.ACTION_DOWN) {
      // ACTION_DOWN的时候就对view重新排序
      orderViewStack();

      // 保存初次按下时arrowFlagView的Y坐标
      // action_down时就让mDragHelper开始工作,否则有时候导致异常
      mDragHelper.processTouchEvent(ev);
    }

    return shouldIntercept;
  }
  /** 点击按钮消失动画 */
  private void vanishOnBtnClick(int type) {
    synchronized (obj1) {
      View animateView = viewList.get(0);
      if (animateView.getVisibility() != View.VISIBLE || releasedViewList.contains(animateView)) {
        return;
      }

      int finalX = 0;
      if (type == VANISH_TYPE_LEFT) {
        finalX = -childWith;
      } else if (type == VANISH_TYPE_RIGHT) {
        finalX = allWidth;
      }

      if (finalX != 0) {
        releasedViewList.add(animateView);
        if (mDragHelper.smoothSlideViewTo(animateView, finalX, initCenterViewY + allHeight)) {
          ViewCompat.postInvalidateOnAnimation(this);
        }
      }

      if (type >= 0 && cardSwitchListener != null) {
        cardSwitchListener.onCardVanish(isShowing, type);
      }
    }
  }
Пример #8
0
 @Override
 public void computeScroll() {
   mScrimOpacity = 1 - mScrollPercent;
   if (mDragHelper.continueSettling(true)) {
     ViewCompat.postInvalidateOnAnimation(this);
   }
 }
 @Override
 public boolean onTouchEvent(MotionEvent ev) {
   if (!isEnabled() || !isTouchEnabled()) {
     return super.onTouchEvent(ev);
   }
   mDragHelper.processTouchEvent(ev);
   return true;
 }
Пример #10
0
 @Override
 public boolean onTouchEvent(MotionEvent event) {
   if (!mEnable) {
     return false;
   }
   mDragHelper.processTouchEvent(event);
   return true;
 }
Пример #11
0
 /**
  * 将拦截的到事件给ViewDragHelper进行处理
  *
  * @param e
  * @return
  */
 @Override
 public boolean onTouchEvent(MotionEvent e) {
   try {
     dragHelper.processTouchEvent(e);
   } catch (Exception ex) {
     ex.printStackTrace();
   }
   return false;
 }
Пример #12
0
 public void close(boolean animate) {
   if (animate) {
     // 继续滑动
     if (dragHelper.smoothSlideViewTo(vg_main, 0, 0)) {
       ViewCompat.postInvalidateOnAnimation(this);
     }
   } else {
     vg_main.layout(0, 0, width, height);
     dispatchDragEvent(0);
   }
 }
Пример #13
0
 public void open(boolean animate) {
   if (animate) {
     // 继续滑动
     if (dragHelper.smoothSlideViewTo(vg_main, range, 0)) {
       ViewCompat.postInvalidateOnAnimation(this);
     }
   } else {
     vg_main.layout(range, 0, range * 2, height);
     dispatchDragEvent(range);
   }
 }
 @Override
 public boolean onTouchEvent(MotionEvent e) {
   try {
     // 统一交给mDragHelper处理,由DragHelperCallback实现拖动效果
     // 该行代码可能会抛异常,正式发布时请将这行代码加上try catch
     mDragHelper.processTouchEvent(e);
   } catch (Exception ex) {
     ex.printStackTrace();
   }
   return true;
 }
Пример #15
0
 @Override
 public boolean onInterceptTouchEvent(MotionEvent event) {
   if (!mEnable) {
     return false;
   }
   try {
     return mDragHelper.shouldInterceptTouchEvent(event);
   } catch (ArrayIndexOutOfBoundsException e) {
     // FIXME: handle exception
     // issues #9
     return false;
   }
 }
 @Override
 public boolean onTouchEvent(@NonNull MotionEvent ev) {
   if (!isEnabled() || !isTouchEnabled()) {
     return super.onTouchEvent(ev);
   }
   try {
     mDragHelper.processTouchEvent(ev);
     return true;
   } catch (Exception ex) {
     // Ignore the pointer out of range exception
     return false;
   }
 }
Пример #17
0
  @Override
  protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
    final boolean drawContent = child == mContentView;

    boolean ret = super.drawChild(canvas, child, drawingTime);
    if (mScrimOpacity > 0
        && drawContent
        && mDragHelper.getViewDragState() != ViewDragHelper.STATE_IDLE) {
      drawShadow(canvas, child);
      drawScrim(canvas, child);
    }
    return ret;
  }
  /**
   * Smoothly animate mDraggingPane to the target X position within its range.
   *
   * @param slideOffset position to animate to
   * @param velocity initial velocity in case of fling, or 0.
   */
  boolean smoothSlideTo(float slideOffset, int velocity) {
    if (!isEnabled()) {
      // Nothing to do.
      return false;
    }

    int panelTop = computePanelTopPosition(slideOffset);
    if (mDragHelper.smoothSlideViewTo(mSlideableView, mSlideableView.getLeft(), panelTop)) {
      setAllChildrenVisible();
      ViewCompat.postInvalidateOnAnimation(this);
      return true;
    }
    return false;
  }
  /**
   * 松手时处理滑动到边缘的动画
   *
   * @param xvel X方向上的滑动速度
   */
  private void animToSide(View changedView, float xvel, float yvel) {
    int finalX = initCenterViewX;
    int finalY = initCenterViewY;
    int flyType = -1;

    // 1. 下面这一坨计算finalX和finalY,要读懂代码需要建立一个比较清晰的数学模型才能理解,不信拉倒
    int dx = changedView.getLeft() - initCenterViewX;
    int dy = changedView.getTop() - initCenterViewY;
    if (dx == 0) {
      // 由于dx作为分母,此处保护处理
      dx = 1;
    }
    if (xvel > X_VEL_THRESHOLD || dx > X_DISTANCE_THRESHOLD) {
      finalX = allWidth;
      finalY = dy * (childWith + initCenterViewX) / dx + initCenterViewY;
      flyType = VANISH_TYPE_RIGHT;
    } else if (xvel < -X_VEL_THRESHOLD || dx < -X_DISTANCE_THRESHOLD) {
      finalX = -childWith;
      finalY = dy * (childWith + initCenterViewX) / (-dx) + dy + initCenterViewY;
      flyType = VANISH_TYPE_LEFT;
    }

    // 如果斜率太高,就折中处理
    if (finalY > allHeight) {
      finalY = allHeight;
    } else if (finalY < -allHeight / 2) {
      finalY = -allHeight / 2;
    }

    // 如果没有飞向两侧,而是回到了中间,需要谨慎处理
    if (finalX != initCenterViewX) {
      releasedViewList.add(changedView);
    }

    // 2. 启动动画
    if (mDragHelper.smoothSlideViewTo(changedView, finalX, finalY)) {
      ViewCompat.postInvalidateOnAnimation(this);
    }

    // 3. 消失动画即将进行,listener回调
    if (flyType >= 0 && cardSwitchListener != null) {
      cardSwitchListener.onCardVanish(isShowing, flyType);
    }
  }
Пример #20
0
  /** Scroll out contentView and finish the activity */
  public void scrollToFinishActivity() {
    final int childWidth = mContentView.getWidth();
    final int childHeight = mContentView.getHeight();

    int left = 0, top = 0;
    if ((mEdgeFlag & EDGE_LEFT) != 0) {
      left = childWidth + mShadowLeft.getIntrinsicWidth() + OVERSCROLL_DISTANCE;
      mTrackingEdge = EDGE_LEFT;
    } else if ((mEdgeFlag & EDGE_RIGHT) != 0) {
      left = -childWidth - mShadowRight.getIntrinsicWidth() - OVERSCROLL_DISTANCE;
      mTrackingEdge = EDGE_RIGHT;
    } else if ((mEdgeFlag & EDGE_BOTTOM) != 0) {
      top = -childHeight - mShadowBottom.getIntrinsicHeight() - OVERSCROLL_DISTANCE;
      mTrackingEdge = EDGE_BOTTOM;
    }

    mDragHelper.smoothSlideViewTo(mContentView, left, top);
    invalidate();
  }
  @Override
  public boolean onInterceptTouchEvent(MotionEvent ev) {
    // If the scrollable view is handling touch, never intercept
    if (mIsScrollableViewHandlingTouch) {
      mDragHelper.cancel();
      return false;
    }

    final int action = MotionEventCompat.getActionMasked(ev);
    final float x = ev.getX();
    final float y = ev.getY();

    switch (action) {
      case MotionEvent.ACTION_DOWN:
        {
          mIsUnableToDrag = false;
          mInitialMotionX = x;
          mInitialMotionY = y;
          break;
        }

      case MotionEvent.ACTION_MOVE:
        {
          final float adx = Math.abs(x - mInitialMotionX);
          final float ady = Math.abs(y - mInitialMotionY);
          final int dragSlop = mDragHelper.getTouchSlop();

          if ((ady > dragSlop && adx > ady)
              || !isViewUnder(mDragView, (int) mInitialMotionX, (int) mInitialMotionY)) {
            mDragHelper.cancel();
            mIsUnableToDrag = true;
            return false;
          }
          break;
        }

      case MotionEvent.ACTION_CANCEL:
      case MotionEvent.ACTION_UP:
        // If the dragView is still dragging when we get here, we need to call processTouchEvent
        // so that the view is settled
        // Added to make scrollable views work (tokudu)
        if (mDragHelper.isDragging()) {
          mDragHelper.processTouchEvent(ev);
          return true;
        }
        break;
    }
    return mDragHelper.shouldInterceptTouchEvent(ev);
  }
Пример #22
0
 /**
  * 拦截触摸事件
  *
  * @param ev
  * @return
  */
 @Override
 public boolean onInterceptTouchEvent(MotionEvent ev) {
   return dragHelper.shouldInterceptTouchEvent(ev) && gestureDetector.onTouchEvent(ev);
 }
  public SlidingUpPanelLayout(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);

    if (isInEditMode()) {
      mShadowDrawable = null;
      mDragHelper = null;
      return;
    }

    if (attrs != null) {
      TypedArray defAttrs = context.obtainStyledAttributes(attrs, DEFAULT_ATTRS);

      if (defAttrs != null) {
        int gravity = defAttrs.getInt(0, Gravity.NO_GRAVITY);
        setGravity(gravity);
      }

      defAttrs.recycle();

      TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.SlidingUpPanelLayout);

      if (ta != null) {
        mPanelHeight =
            ta.getDimensionPixelSize(R.styleable.SlidingUpPanelLayout_umanoPanelHeight, -1);
        mShadowHeight =
            ta.getDimensionPixelSize(R.styleable.SlidingUpPanelLayout_umanoShadowHeight, -1);
        mParallaxOffset =
            ta.getDimensionPixelSize(R.styleable.SlidingUpPanelLayout_umanoParalaxOffset, -1);

        mMinFlingVelocity =
            ta.getInt(
                R.styleable.SlidingUpPanelLayout_umanoFlingVelocity, DEFAULT_MIN_FLING_VELOCITY);
        mCoveredFadeColor =
            ta.getColor(R.styleable.SlidingUpPanelLayout_umanoFadeColor, DEFAULT_FADE_COLOR);

        mDragViewResId = ta.getResourceId(R.styleable.SlidingUpPanelLayout_umanoDragView, -1);

        mOverlayContent =
            ta.getBoolean(R.styleable.SlidingUpPanelLayout_umanoOverlay, DEFAULT_OVERLAY_FLAG);
        mClipPanel =
            ta.getBoolean(R.styleable.SlidingUpPanelLayout_umanoClipPanel, DEFAULT_CLIP_PANEL_FLAG);

        mAnchorPoint =
            ta.getFloat(R.styleable.SlidingUpPanelLayout_umanoAnchorPoint, DEFAULT_ANCHOR_POINT);

        mSlideState =
            PanelState.values()[
                ta.getInt(
                    R.styleable.SlidingUpPanelLayout_umanoInitialState,
                    DEFAULT_SLIDE_STATE.ordinal())];
      }

      ta.recycle();
    }

    final float density = context.getResources().getDisplayMetrics().density;
    if (mPanelHeight == -1) {
      mPanelHeight = (int) (DEFAULT_PANEL_HEIGHT * density + 0.5f);
    }
    if (mShadowHeight == -1) {
      mShadowHeight = (int) (DEFAULT_SHADOW_HEIGHT * density + 0.5f);
    }
    if (mParallaxOffset == -1) {
      mParallaxOffset = (int) (DEFAULT_PARALAX_OFFSET * density);
    }
    // If the shadow height is zero, don't show the shadow
    if (mShadowHeight > 0) {
      if (mIsSlidingUp) {
        mShadowDrawable = getResources().getDrawable(R.drawable.above_shadow);
      } else {
        mShadowDrawable = getResources().getDrawable(R.drawable.below_shadow);
      }

    } else {
      mShadowDrawable = null;
    }

    setWillNotDraw(false);

    mDragHelper = ViewDragHelper.create(this, 0.5f, new DragHelperCallback());
    mDragHelper.setMinVelocity(mMinFlingVelocity * density);

    mIsTouchEnabled = true;
  }
  @Override
  public boolean dispatchTouchEvent(@NonNull MotionEvent ev) {
    final int action = MotionEventCompat.getActionMasked(ev);

    if (!isEnabled()
        || !isTouchEnabled()
        || (mIsUnableToDrag && action != MotionEvent.ACTION_DOWN)) {
      mDragHelper.cancel();
      return super.dispatchTouchEvent(ev);
    }

    final float y = ev.getY();

    if (action == MotionEvent.ACTION_DOWN) {
      mIsScrollableViewHandlingTouch = false;
      mPrevMotionY = y;
    } else if (action == MotionEvent.ACTION_MOVE) {
      float dy = y - mPrevMotionY;
      mPrevMotionY = y;

      // If the scroll view isn't under the touch, pass the
      // event along to the dragView.
      if (!isViewUnder(mScrollableView, (int) mInitialMotionX, (int) mInitialMotionY)) {
        return super.dispatchTouchEvent(ev);
      }

      // Which direction (up or down) is the drag moving?
      if (dy * (mIsSlidingUp ? 1 : -1) > 0) { // Collapsing
        // Is the child less than fully scrolled?
        // Then let the child handle it.
        if (mScrollableViewHelper.getScrollableViewScrollPosition(mScrollableView, mIsSlidingUp)
            > 0) {
          mIsScrollableViewHandlingTouch = true;
          return super.dispatchTouchEvent(ev);
        }

        // Was the child handling the touch previously?
        // Then we need to rejigger things so that the
        // drag panel gets a proper down event.
        if (mIsScrollableViewHandlingTouch) {
          // Send an 'UP' event to the child.
          MotionEvent up = MotionEvent.obtain(ev);
          up.setAction(MotionEvent.ACTION_CANCEL);
          super.dispatchTouchEvent(up);
          up.recycle();

          // Send a 'DOWN' event to the panel. (We'll cheat
          // and hijack this one)
          ev.setAction(MotionEvent.ACTION_DOWN);
        }

        mIsScrollableViewHandlingTouch = false;
        return this.onTouchEvent(ev);
      } else if (dy * (mIsSlidingUp ? 1 : -1) < 0) { // Expanding
        // Is the panel less than fully expanded?
        // Then we'll handle the drag here.
        if (mSlideOffset < 1.0f) {
          mIsScrollableViewHandlingTouch = false;
          return this.onTouchEvent(ev);
        }

        // Was the panel handling the touch previously?
        // Then we need to rejigger things so that the
        // child gets a proper down event.
        if (!mIsScrollableViewHandlingTouch && mDragHelper.isDragging()) {
          mDragHelper.cancel();
          ev.setAction(MotionEvent.ACTION_DOWN);
        }

        mIsScrollableViewHandlingTouch = true;
        return super.dispatchTouchEvent(ev);
      }
    } else if (action == MotionEvent.ACTION_UP && mIsScrollableViewHandlingTouch) {
      // If the scrollable view was handling the touch and we receive an up
      // we want to clear any previous dragging state so we don't intercept a touch stream
      // accidentally
      mDragHelper.setDragState(ViewDragHelper.STATE_IDLE);
    }

    // In all other cases, just let the default behavior take over.
    return super.dispatchTouchEvent(ev);
  }
Пример #25
0
 /** 有加速度,当我们停止滑动的时候,该不会立即停止动画效果 */
 @Override
 public void computeScroll() {
   if (dragHelper.continueSettling(true)) {
     ViewCompat.postInvalidateOnAnimation(this);
   }
 }
Пример #26
0
 public DragLayout(Context context, AttributeSet attrs, int defStyle) {
   super(context, attrs, defStyle);
   gestureDetector = new GestureDetectorCompat(context, new YScrollDetector());
   dragHelper = ViewDragHelper.create(this, dragHelperCallback);
 }
Пример #27
0
 /**
  * Set the size of an edge. This is the range in pixels along the edges of this view that will
  * actively detect edge touches or drags if edge tracking is enabled.
  *
  * @param size The size of an edge in pixels
  */
 public void setEdgeSize(int size) {
   mDragHelper.setEdgeSize(size);
 }
Пример #28
0
 /**
  * Enable edge tracking for the selected edges of the parent view. The callback's
  *
  * <p>methods will only be invoked for edges for which edge tracking has been enabled.
  *
  * @param edgeFlags Combination of edge flags describing the edges to watch
  * @see #EDGE_LEFT
  * @see #EDGE_RIGHT
  * @see #EDGE_BOTTOM
  */
 public void setEdgeTrackingEnabled(int edgeFlags) {
   mEdgeFlag = edgeFlags;
   mDragHelper.setEdgeTrackingEnabled(mEdgeFlag);
 }
Пример #29
0
 /**
  * Sets the sensitivity of the NavigationLayout.
  *
  * @param context The application context.
  * @param sensitivity value between 0 and 1, the final value for touchSlop =
  *     ViewConfiguration.getScaledTouchSlop * (1 / s);
  */
 public void setSensitivity(Context context, float sensitivity) {
   mDragHelper.setSensitivity(context, sensitivity);
 }