studio ejemplo android gesture drawerlayout slidingdrawer

studio - navigation drawer android ejemplo



CustomDrawerLayout desde cuatro lados de la pantalla presenta un problema con Fling gesto y detección (1)

Parece que deberías usar la función getTranslationFor para calcular la nueva traducción para el estado.

Actualmente, solo tiene en cuenta la Altura y el desplazamiento, pero del código getTranslationFor parece que también debería considerar getLocationInYAxis .

Entonces, en lugar de esta línea:

notifyActionAndAnimateForState(LockMode.LOCK_MODE_OPEN, parent.getHeight() - mOffsetHeight, true);

prueba esta linea:

notifyActionAndAnimateForState(LockMode.LOCK_MODE_OPEN, getTranslationFor(LockMode.LOCK_MODE_OPEN), true);

Estoy tratando de crear y mejorar los proyectos SlidingDrawers existentes que pueden funcionar para los cuatro lados de la pantalla {IZQUIERDA, DERECHA, ARRIBA, ABAJO). Hay algunas bibliotecas, sin embargo, todas tienen limitaciones, complicaciones y errores. Uno de los más comunes es el AndroidSlidingUpPanel de umano, sin embargo, no me gusta esta biblioteca porque solo tiene que incluir dos diseños secundarios, y también debe tener en cuenta una disposición específica del contenido principal al cajón. Otras bibliotecas son similares, o más complicadas, o tienen errores.

Estoy cerca de completar mi versión de SlidingDrawers, me estoy enfocando en la gravedad INFERIOR. Necesito un poco de ayuda con el gesto de lanzamiento. Al hacer clic en el cajón se abrirá y se cerrará. También puedes deslizar el cajón con el dedo. Pero si abres el cajón, toda la vista cambiará más de lo que debería o de lo que debería.

¿Cómo puedo resolver esto? Por lo que puedo decir, mi matemática es correcta. El valor de traducción que estoy pasando a mi animador debe ser correcto. A continuación se muestra el trabajo que he completado. Por favor revisa este proyecto https://github.com/drxeno02/CustomDrawerLayout.git . Gracias de antemano.

Para aquellos de ustedes que quieran ver un fragmento de cómo se ve el código problemático, aquí está cómo estoy haciendo mis gestos actualmente.

@Override public boolean onInterceptTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mActivePointerId = MotionEventCompat.getPointerId(event, 0); switch (mStickTo) { case GRAVITY_BOTTOM: case GRAVITY_TOP: mInitialCoordinate = event.getY(); break; case GRAVITY_LEFT: case GRAVITY_RIGHT: mInitialCoordinate = event.getX(); break; } break; case MotionEvent.ACTION_MOVE: float coordinate = 0; switch (mStickTo) { case GRAVITY_BOTTOM: case GRAVITY_TOP: coordinate = event.getY(); break; case GRAVITY_LEFT: case GRAVITY_RIGHT: coordinate = event.getX(); break; } final int diff = (int) Math.abs(coordinate - mInitialCoordinate); // confirm that difference is enough to indicate drag action if (diff > mTouchSlop) { // start capturing events Logger.d(TAG, "drag is being captured"); return true; } break; case MotionEvent.ACTION_UP: if (!FrameworkUtils.checkIfNull(mVelocityTracker)) { mVelocityTracker.recycle(); mVelocityTracker = null; } break; } // add velocity movements if (FrameworkUtils.checkIfNull(mVelocityTracker)) { mVelocityTracker = VelocityTracker.obtain(); } mVelocityTracker.addMovement(event); return super.onInterceptTouchEvent(event); } @Override public boolean onTouchEvent(@NonNull MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN && event.getEdgeFlags() != 0) { return false; } // add velocity movements if (FrameworkUtils.checkIfNull(mVelocityTracker)) { mVelocityTracker = VelocityTracker.obtain(); } mVelocityTracker.addMovement(event); final View parent = (View) getParent(); final int coordinate; final int distance = getDistance(); final int tapCoordinate; switch (mStickTo) { case GRAVITY_BOTTOM: coordinate = (int) event.getRawY(); tapCoordinate = (int) event.getRawY(); break; case GRAVITY_LEFT: coordinate = parent.getWidth() - (int) event.getRawX(); tapCoordinate = (int) event.getRawX(); break; case GRAVITY_RIGHT: coordinate = (int) event.getRawX(); tapCoordinate = (int) event.getRawX(); break; case GRAVITY_TOP: coordinate = getRawDisplayHeight(getContext()) - (int) event.getRawY(); tapCoordinate = (int) event.getRawY(); break; // if view position is not initialized throw an error default: throw new IllegalStateException("Failed to initialize coordinates"); } switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: /* * Return the pointer identifier associated with a particular pointer data index is * this event. The identifier tells you the actual pointer number associated with * the data, accounting for individual pointers going up and down since the start * of the current gesture. */ mActivePointerId = event.getPointerId(0); switch (mStickTo) { case GRAVITY_BOTTOM: mDelta = coordinate - ((RelativeLayout.LayoutParams) getLayoutParams()).topMargin; break; case GRAVITY_LEFT: mDelta = coordinate - ((RelativeLayout.LayoutParams) getLayoutParams()).rightMargin; break; case GRAVITY_RIGHT: mDelta = coordinate - ((RelativeLayout.LayoutParams) getLayoutParams()).leftMargin; break; case GRAVITY_TOP: mDelta = coordinate - ((RelativeLayout.LayoutParams) getLayoutParams()).bottomMargin; break; } mLastCoordinate = coordinate; mPressStartTime = System.currentTimeMillis(); break; case MotionEvent.ACTION_MOVE: RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) getLayoutParams(); final int farMargin = coordinate - mDelta; final int closeMargin = distance - farMargin; switch (mStickTo) { case GRAVITY_BOTTOM: if (farMargin > distance && closeMargin > mOffsetHeight - getHeight()) { layoutParams.bottomMargin = closeMargin; layoutParams.topMargin = farMargin; } break; case GRAVITY_LEFT: if (farMargin > distance && closeMargin > mOffsetHeight - getWidth()) { layoutParams.leftMargin = closeMargin; layoutParams.rightMargin = farMargin; } break; case GRAVITY_RIGHT: if (farMargin > distance && closeMargin > mOffsetHeight - getWidth()) { layoutParams.rightMargin = closeMargin; layoutParams.leftMargin = farMargin; } break; case GRAVITY_TOP: if (farMargin > distance && closeMargin > mOffsetHeight - getHeight()) { layoutParams.topMargin = closeMargin; layoutParams.bottomMargin = farMargin; } break; } setLayoutParams(layoutParams); break; case MotionEvent.ACTION_UP: final int diff = coordinate - mLastCoordinate; final long pressDuration = System.currentTimeMillis() - mPressStartTime; switch (mStickTo) { case GRAVITY_BOTTOM: // determine if fling int relativeVelocity; final VelocityTracker velocityTracker = mVelocityTracker; velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); final int initialVelocityY = (int) VelocityTrackerCompat.getYVelocity( velocityTracker, mActivePointerId); relativeVelocity = initialVelocityY * -1; // take absolute value to have positive values final int absoluteVelocity = Math.abs(relativeVelocity); if (Math.abs(diff) > mFlingDistance && absoluteVelocity > mMinimumVelocity) { if (tapCoordinate > parent.getHeight() - mOffsetHeight && mLockMode == LockMode.LOCK_MODE_CLOSED) { notifyActionAndAnimateForState(LockMode.LOCK_MODE_OPEN, parent.getHeight() - mOffsetHeight, true); } else if (Math.abs(getRawDisplayHeight(getContext()) - tapCoordinate - getHeight()) < mOffsetHeight && mLockMode == LockMode.LOCK_MODE_OPEN) { notifyActionAndAnimateForState(LockMode.LOCK_MODE_CLOSED, parent.getHeight() - mOffsetHeight, true); } } else { if (isClicked(getContext(), diff, pressDuration)) { if (tapCoordinate > parent.getHeight() - mOffsetHeight && mLockMode == LockMode.LOCK_MODE_CLOSED) { notifyActionAndAnimateForState(LockMode.LOCK_MODE_OPEN, parent.getHeight() - mOffsetHeight, true); } else if (Math.abs(getRawDisplayHeight(getContext()) - tapCoordinate - getHeight()) < mOffsetHeight && mLockMode == LockMode.LOCK_MODE_OPEN) { notifyActionAndAnimateForState(LockMode.LOCK_MODE_CLOSED, parent.getHeight() - mOffsetHeight, true); } } else { smoothScrollToAndNotify(diff); } } break; case GRAVITY_TOP: if (isClicked(getContext(), diff, pressDuration)) { final int y = getLocationInYAxis(this); if (tapCoordinate - Math.abs(y) <= mOffsetHeight && mLockMode == LockMode.LOCK_MODE_CLOSED) { notifyActionAndAnimateForState(LockMode.LOCK_MODE_OPEN, parent.getHeight() - mOffsetHeight, true); } else if (getHeight() - (tapCoordinate - Math.abs(y)) < mOffsetHeight && mLockMode == LockMode.LOCK_MODE_OPEN) { notifyActionAndAnimateForState(LockMode.LOCK_MODE_CLOSED, parent.getHeight() - mOffsetHeight, true); } } else { smoothScrollToAndNotify(diff); } break; case GRAVITY_LEFT: if (isClicked(getContext(), diff, pressDuration)) { if (tapCoordinate <= mOffsetHeight && mLockMode == LockMode.LOCK_MODE_CLOSED) { notifyActionAndAnimateForState(LockMode.LOCK_MODE_OPEN, getWidth() - mOffsetHeight, true); } else if (tapCoordinate > getWidth() - mOffsetHeight && mLockMode == LockMode.LOCK_MODE_OPEN) { notifyActionAndAnimateForState(LockMode.LOCK_MODE_CLOSED, getWidth() - mOffsetHeight, true); } } else { smoothScrollToAndNotify(diff); } break; case GRAVITY_RIGHT: if (isClicked(getContext(), diff, pressDuration)) { if (parent.getWidth() - tapCoordinate <= mOffsetHeight && mLockMode == LockMode.LOCK_MODE_CLOSED) { notifyActionAndAnimateForState(LockMode.LOCK_MODE_OPEN, getWidth() - mOffsetHeight, true); } else if (parent.getWidth() - tapCoordinate > getWidth() - mOffsetHeight && mLockMode == LockMode.LOCK_MODE_OPEN) { notifyActionAndAnimateForState(LockMode.LOCK_MODE_CLOSED, getWidth() - mOffsetHeight, true); } } else { smoothScrollToAndNotify(diff); } break; } break; } return true; } /** * Method is used to animate the view to the given position * * @param diff */ private void smoothScrollToAndNotify(int diff) { int length = getLength(); LockMode stateToApply; if (diff > 0) { if (diff > length / 2.5) { stateToApply = LockMode.LOCK_MODE_CLOSED; notifyActionAndAnimateForState(stateToApply, getTranslationFor(stateToApply), true); } else if (mLockMode == LockMode.LOCK_MODE_OPEN) { stateToApply = LockMode.LOCK_MODE_OPEN; notifyActionAndAnimateForState(stateToApply, getTranslationFor(stateToApply), false); } } else { if (Math.abs(diff) > length / 2.5) { stateToApply = LockMode.LOCK_MODE_OPEN; notifyActionAndAnimateForState(stateToApply, getTranslationFor(stateToApply), true); } else if (mLockMode == LockMode.LOCK_MODE_CLOSED) { stateToApply = LockMode.LOCK_MODE_CLOSED; notifyActionAndAnimateForState(stateToApply, getTranslationFor(stateToApply), false); } } } /** * Method is used to retrieve dimensions meant for translation * * @param stateToApply * @return */ private int getTranslationFor(LockMode stateToApply) { switch (mStickTo) { case GRAVITY_BOTTOM: switch (stateToApply) { case LOCK_MODE_OPEN: return getHeight() - (getRawDisplayHeight(getContext()) - getLocationInYAxis(this)); case LOCK_MODE_CLOSED: return getRawDisplayHeight(getContext()) - getLocationInYAxis(this) - mOffsetHeight; } break; case GRAVITY_TOP: final int actionBarDiff = getRawDisplayHeight(getContext()) - ((View) getParent()).getHeight(); final int y = getLocationInYAxis(this) + getHeight(); switch (stateToApply) { case LOCK_MODE_OPEN: return getHeight() - y + actionBarDiff; case LOCK_MODE_CLOSED: return y - mOffsetHeight - actionBarDiff; } break; case GRAVITY_LEFT: final int x = getLocationInXAxis(this) + getWidth(); switch (stateToApply) { case LOCK_MODE_OPEN: return getWidth() - x; case LOCK_MODE_CLOSED: return x - mOffsetHeight; } break; case GRAVITY_RIGHT: switch (stateToApply) { case LOCK_MODE_OPEN: return getWidth() - (getRawDisplayWidth(getContext()) - getLocationInXAxis(this)); case LOCK_MODE_CLOSED: return getRawDisplayWidth(getContext()) - getLocationInXAxis(this) - mOffsetHeight; } break; } throw new IllegalStateException("Failed to return translation for drawer"); } /** * Method is used to perform the animations * * @param stateToApply * @param translation * @param notify */ private void notifyActionAndAnimateForState(final LockMode stateToApply, final int translation, final boolean notify) { switch (mStickTo) { case GRAVITY_BOTTOM: switch (stateToApply) { case LOCK_MODE_OPEN: animate().translationY(-translation) .setDuration(TRANSLATION_ANIM_DURATION) .setInterpolator(new DecelerateInterpolator()) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); notifyActionForState(stateToApply, notify); setTranslationY(0); } }); break; case LOCK_MODE_CLOSED: animate().translationY(translation) .setDuration(TRANSLATION_ANIM_DURATION) .setInterpolator(new DecelerateInterpolator()) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); notifyActionForState(stateToApply, notify); setTranslationY(0); } }); break; } break; case GRAVITY_TOP: switch (stateToApply) { case LOCK_MODE_OPEN: animate().translationY(translation) .setDuration(TRANSLATION_ANIM_DURATION) .setInterpolator(new DecelerateInterpolator()) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); notifyActionForState(stateToApply, notify); setTranslationY(0); } }); break; case LOCK_MODE_CLOSED: animate().translationY(-translation) .setDuration(TRANSLATION_ANIM_DURATION) .setInterpolator(new DecelerateInterpolator()) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); notifyActionForState(stateToApply, notify); setTranslationY(0); } }); break; } break; case GRAVITY_LEFT: switch (stateToApply) { case LOCK_MODE_OPEN: animate().translationX(translation) .setDuration(TRANSLATION_ANIM_DURATION) .setInterpolator(new DecelerateInterpolator()) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); notifyActionForState(stateToApply, notify); setTranslationX(0); } }); break; case LOCK_MODE_CLOSED: animate().translationX(-translation) .setDuration(TRANSLATION_ANIM_DURATION) .setInterpolator(new DecelerateInterpolator()) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); notifyActionForState(stateToApply, notify); setTranslationX(0); } }); break; } break; case GRAVITY_RIGHT: switch (stateToApply) { case LOCK_MODE_OPEN: animate().translationX(-translation) .setDuration(TRANSLATION_ANIM_DURATION) .setInterpolator(new DecelerateInterpolator()) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); notifyActionForState(stateToApply, notify); setTranslationX(0); } }); break; case LOCK_MODE_CLOSED: animate().translationX(translation) .setDuration(TRANSLATION_ANIM_DURATION) .setInterpolator(new DecelerateInterpolator()) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); notifyActionForState(stateToApply, notify); setTranslationX(0); } }); break; } break; } }

Notas adicionales: Tengo más información sobre este tema. Comenté el ACTION_MOVE para eliminar la posición del cajón que se había movido antes de la acción de lanzamiento. La animación funciona perfectamente. Creo que mi idea es correcta. Para obtener la traducción para "abrir" lo hago

getHeight() - (getRawDisplayHeight(getContext()) - getLocationInYAxis(this))

  • getHeight () es la altura del cajón
  • getRawDisplayHeight (getContext ()) es la altura de la pantalla del dispositivo
  • getLocationInYAxis (esto), cuando ACTION_MOVE está fuera de la imagen, es efectivamente (getRawDisplayHeight (getContext ()) - mOffsetHeight). En
    En este escenario deberían ser intercambiables.

Entonces, lo que queda es la cantidad de distancia necesaria para traducir. Sin embargo, una vez que el cajón ha sido arrastrado x-distance, estoy esperando que getLocationInYAxis (esto) me devuelva la posición arrastrada. Pero el cálculo está apagado.