forked from organicmaps/organicmaps
[android] Navigation buttons animation.
This commit is contained in:
parent
c5890ce4cd
commit
1167dfeba8
4 changed files with 246 additions and 223 deletions
|
@ -1174,9 +1174,6 @@ public class MwmActivity extends BaseMwmFragmentActivity
|
|||
Framework.nativeDeactivatePopup();
|
||||
mPlacePage.setMapObject(null, false);
|
||||
}
|
||||
|
||||
if (mNavAnimationController != null)
|
||||
mNavAnimationController.onPlacePageVisibilityChanged(isVisible);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1388,20 +1385,46 @@ public class MwmActivity extends BaseMwmFragmentActivity
|
|||
private void adjustMenuLineFrameVisibility()
|
||||
{
|
||||
final RoutingController controller = RoutingController.get();
|
||||
final int menuHeight = getCurrentMenu().getFrame().getHeight();
|
||||
|
||||
if (controller.isBuilt() || controller.isUberRequestHandled())
|
||||
{
|
||||
mMainMenu.showLineFrame(true);
|
||||
mMainMenu.showLineFrame(true, new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
adjustCompass(0);
|
||||
adjustRuler(0, 0);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (controller.isPlanning() || controller.isBuilding() || controller.isErrorEncountered())
|
||||
{
|
||||
mMainMenu.showLineFrame(false);
|
||||
mMainMenu.showLineFrame(false, new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
adjustCompass(menuHeight);
|
||||
adjustRuler(0, menuHeight);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
mMainMenu.showLineFrame(true);
|
||||
mMainMenu.showLineFrame(true, new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
adjustCompass(0);
|
||||
adjustRuler(0, 0);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private void setNavButtonsTopLimit(int limit)
|
||||
|
@ -1415,6 +1438,8 @@ public class MwmActivity extends BaseMwmFragmentActivity
|
|||
@Override
|
||||
public void showRoutePlan(boolean show, @Nullable Runnable completionListener)
|
||||
{
|
||||
if (mNavAnimationController != null && !mIsFragmentContainer)
|
||||
mNavAnimationController.slide(show);
|
||||
if (show)
|
||||
{
|
||||
mSearchController.hide();
|
||||
|
@ -1538,7 +1563,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
|
|||
public void animateSearchPoiTransition(@NonNull final Rect startRect,
|
||||
@Nullable final Runnable runnable)
|
||||
{
|
||||
Animations.rizeTransition(mRootView, startRect, runnable);
|
||||
Animations.riseTransition(mRootView, startRect, runnable);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
package com.mapswithme.maps;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.res.Resources;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.view.View;
|
||||
|
||||
|
@ -7,12 +10,11 @@ import com.mapswithme.maps.routing.RoutingController;
|
|||
import com.mapswithme.util.Animations;
|
||||
import com.mapswithme.util.Config;
|
||||
import com.mapswithme.util.UiUtils;
|
||||
import com.mapswithme.util.log.DebugLogger;
|
||||
|
||||
class NavigationButtonsAnimationController
|
||||
{
|
||||
private static final DebugLogger LOGGER =
|
||||
new DebugLogger(NavigationButtonsAnimationController.class.getSimpleName());
|
||||
private static final int ANIM_TOGGLE = MwmApplication.get().getResources().getInteger(R.integer.anim_slots_toggle);
|
||||
|
||||
@NonNull
|
||||
private final View mZoomIn;
|
||||
@NonNull
|
||||
|
@ -20,24 +22,207 @@ class NavigationButtonsAnimationController
|
|||
@NonNull
|
||||
private final View mMyPosition;
|
||||
|
||||
private float mBottomLimit;
|
||||
private float mTopLimit;
|
||||
private final float mMargin;
|
||||
private float mBottom;
|
||||
private float mTop;
|
||||
|
||||
private boolean mMyPosAnimate;
|
||||
private boolean mIsZoomAnimate;
|
||||
private boolean mIsMyPosAnimate;
|
||||
private boolean mIsSlideDown;
|
||||
|
||||
private final float mMenuHeight;
|
||||
|
||||
NavigationButtonsAnimationController(@NonNull View zoomIn, @NonNull View zoomOut,
|
||||
@NonNull View myPosition)
|
||||
{
|
||||
mZoomIn = zoomIn;
|
||||
mZoomOut = zoomOut;
|
||||
checkZoomButtonsVisibility();
|
||||
UiUtils.showIf(showZoomButtons(), mZoomIn, mZoomOut);
|
||||
mMyPosition = myPosition;
|
||||
calculateBottomLimit();
|
||||
Resources res = mZoomIn.getResources();
|
||||
mMargin = res.getDimension(R.dimen.margin_base_plus);
|
||||
mMenuHeight = res.getDimension(R.dimen.menu_line_height);
|
||||
calculateLimitTranslations();
|
||||
}
|
||||
|
||||
private void checkZoomButtonsVisibility()
|
||||
private void calculateLimitTranslations()
|
||||
{
|
||||
UiUtils.showIf(showZoomButtons(), mZoomIn, mZoomOut);
|
||||
mTop = mMargin;
|
||||
mMyPosition.addOnLayoutChangeListener(new View.OnLayoutChangeListener()
|
||||
{
|
||||
@Override
|
||||
public void onLayoutChange(View v, int left, int top, int right, int bottom,
|
||||
int oldLeft, int oldTop, int oldRight, int oldBottom)
|
||||
{
|
||||
mBottom = bottom + mMargin;
|
||||
mMyPosition.removeOnLayoutChangeListener(this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void setTopLimit(float limit)
|
||||
{
|
||||
mTop = limit + mMargin;
|
||||
update();
|
||||
}
|
||||
|
||||
private void fadeOutZoom()
|
||||
{
|
||||
if (mIsSlideDown)
|
||||
return;
|
||||
mIsZoomAnimate = true;
|
||||
Animations.fadeOutView(mZoomIn, new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
mZoomIn.setVisibility(View.INVISIBLE);
|
||||
mIsZoomAnimate = false;
|
||||
}
|
||||
});
|
||||
Animations.fadeOutView(mZoomOut, new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
mZoomOut.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void fadeInZoom()
|
||||
{
|
||||
mIsZoomAnimate = true;
|
||||
mZoomIn.setVisibility(View.VISIBLE);
|
||||
mZoomOut.setVisibility(View.VISIBLE);
|
||||
Animations.fadeInView(mZoomIn, new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
mIsZoomAnimate = false;
|
||||
}
|
||||
});
|
||||
Animations.fadeInView(mZoomOut, null);
|
||||
}
|
||||
|
||||
private void fadeOutMyPosition()
|
||||
{
|
||||
if (mIsSlideDown)
|
||||
return;
|
||||
|
||||
mIsMyPosAnimate = true;
|
||||
Animations.fadeOutView(mMyPosition, new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
UiUtils.invisible(mMyPosition);
|
||||
mIsMyPosAnimate = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void fadeInMyPosition()
|
||||
{
|
||||
mIsMyPosAnimate = true;
|
||||
mMyPosition.setVisibility(View.VISIBLE);
|
||||
Animations.fadeInView(mMyPosition, new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
mIsMyPosAnimate = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void onPlacePageMoved(float translationY)
|
||||
{
|
||||
if (UiUtils.isLandscape(mMyPosition.getContext()) || mBottom == 0)
|
||||
return;
|
||||
|
||||
final float amount = mZoomIn.getTranslationY() > 0 ? mMenuHeight : 0;
|
||||
final float translation = translationY - mBottom;
|
||||
update(translation <= amount ? translation : amount);
|
||||
}
|
||||
|
||||
private void update()
|
||||
{
|
||||
update(mZoomIn.getTranslationY());
|
||||
}
|
||||
|
||||
private void update(final float translation)
|
||||
{
|
||||
mMyPosition.setTranslationY(translation);
|
||||
mZoomOut.setTranslationY(translation);
|
||||
mZoomIn.setTranslationY(translation);
|
||||
if (!mIsZoomAnimate && isOverTopLimit(mZoomIn))
|
||||
{
|
||||
fadeOutZoom();
|
||||
}
|
||||
else if (!mIsZoomAnimate && satisfyTopLimit(mZoomIn))
|
||||
{
|
||||
fadeInZoom();
|
||||
}
|
||||
|
||||
if (!shouldBeHidden() && !mIsMyPosAnimate
|
||||
&& isOverTopLimit(mMyPosition))
|
||||
{
|
||||
fadeOutMyPosition();
|
||||
}
|
||||
else if (!shouldBeHidden() && !mIsMyPosAnimate
|
||||
&& satisfyTopLimit(mMyPosition))
|
||||
{
|
||||
fadeInMyPosition();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isOverTopLimit(@NonNull View view)
|
||||
{
|
||||
return view.getVisibility() == View.VISIBLE && view.getY() <= mTop;
|
||||
}
|
||||
|
||||
private boolean satisfyTopLimit(@NonNull View view)
|
||||
{
|
||||
return view.getVisibility() == View.INVISIBLE && view.getY() >= mTop;
|
||||
}
|
||||
|
||||
private boolean shouldBeHidden()
|
||||
{
|
||||
return LocationState.getMode() == LocationState.FOLLOW_AND_ROTATE
|
||||
&& (RoutingController.get().isPlanning() || RoutingController.get().isNavigating());
|
||||
}
|
||||
|
||||
void slide(boolean isDown)
|
||||
{
|
||||
if (UiUtils.isLandscape(mMyPosition.getContext())
|
||||
|| (!isDown && mZoomIn.getTranslationY() <= 0))
|
||||
return;
|
||||
|
||||
mIsSlideDown = isDown;
|
||||
|
||||
ValueAnimator animator = ValueAnimator.ofFloat(isDown ? 0 : mMenuHeight, isDown ? mMenuHeight : 0);
|
||||
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
|
||||
{
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation)
|
||||
{
|
||||
float value = (float) animation.getAnimatedValue();
|
||||
update(value);
|
||||
}
|
||||
});
|
||||
animator.addListener(new UiUtils.SimpleAnimatorListener()
|
||||
{
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation)
|
||||
{
|
||||
mIsSlideDown = false;
|
||||
update();
|
||||
}
|
||||
});
|
||||
animator.setDuration(ANIM_TOGGLE);
|
||||
animator.start();
|
||||
}
|
||||
|
||||
void disappearZoomButtons()
|
||||
|
@ -54,204 +239,8 @@ class NavigationButtonsAnimationController
|
|||
if (!showZoomButtons())
|
||||
return;
|
||||
|
||||
if (!canZoomButtonsFitInScreen())
|
||||
return;
|
||||
|
||||
Animations.appearSliding(mZoomIn, Animations.RIGHT, null);
|
||||
Animations.appearSliding(mZoomOut, Animations.RIGHT, null);
|
||||
updateZoomButtonsPosition();
|
||||
}
|
||||
|
||||
void setTopLimit(float limit)
|
||||
{
|
||||
mTopLimit = limit;
|
||||
updateZoomButtonsPosition();
|
||||
}
|
||||
|
||||
void onPlacePageVisibilityChanged(boolean isVisible)
|
||||
{
|
||||
if (isVisible)
|
||||
fadeOutZooms();
|
||||
else
|
||||
fadeInZooms();
|
||||
}
|
||||
|
||||
void onPlacePageMoved(float translationY)
|
||||
{
|
||||
if (mBottomLimit == 0)
|
||||
return;
|
||||
|
||||
float translation = translationY - mBottomLimit;
|
||||
animateMyPosition(translation <= 0 ? translation : 0);
|
||||
}
|
||||
|
||||
private void calculateBottomLimit()
|
||||
{
|
||||
mMyPosition.addOnLayoutChangeListener(new View.OnLayoutChangeListener()
|
||||
{
|
||||
@Override
|
||||
public void onLayoutChange(View v, int left, int top, int right, int bottom,
|
||||
int oldLeft, int oldTop, int oldRight, int oldBottom)
|
||||
{
|
||||
mBottomLimit = bottom;
|
||||
mMyPosition.removeOnLayoutChangeListener(this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void updateZoomButtonsPosition()
|
||||
{
|
||||
// It means that the zoom buttons fit in screen perfectly,
|
||||
// any updates of position are no needed.
|
||||
if (mZoomIn.getTop() >= mTopLimit && UiUtils.isVisible(mZoomIn))
|
||||
return;
|
||||
|
||||
// If the top limit is decreased we try to return zoom buttons at initial position.
|
||||
if (mTopLimit < mZoomIn.getTop() && tryPlaceZoomButtonsAtInitialPosition())
|
||||
{
|
||||
LOGGER.d("Zoom buttons were come back to initial position");
|
||||
return;
|
||||
}
|
||||
|
||||
// If top view overlaps the zoomIn button.
|
||||
if (mTopLimit > mZoomIn.getTop())
|
||||
{
|
||||
// We should try to pull out the zoomIn button from under the top view
|
||||
// if available space allows us doing that.
|
||||
if (tryPlaceZoomButtonsUnderTopLimit())
|
||||
return;
|
||||
|
||||
// Otherwise, we just fade out the zoom buttons
|
||||
// since there is not enough space on the screen for them.
|
||||
fadeOutZooms();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean tryPlaceZoomButtonsAtInitialPosition()
|
||||
{
|
||||
float availableSpace = mBottomLimit - mTopLimit;
|
||||
float requiredSpace = mBottomLimit - mZoomIn.getTop() - mZoomIn.getTranslationY();
|
||||
if (requiredSpace > availableSpace)
|
||||
return false;
|
||||
|
||||
mZoomIn.setTranslationY(0);
|
||||
mZoomOut.setTranslationY(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean tryPlaceZoomButtonsUnderTopLimit()
|
||||
{
|
||||
if (!canZoomButtonsFitInScreen())
|
||||
return false;
|
||||
|
||||
float requiredTranslate = mTopLimit - mZoomIn.getTop();
|
||||
mZoomIn.setTranslationY(requiredTranslate);
|
||||
mZoomOut.setTranslationY(requiredTranslate);
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean canZoomButtonsFitInScreen()
|
||||
{
|
||||
float availableSpace = mBottomLimit - mTopLimit;
|
||||
return getMinimumRequiredHeightForButtons() <= availableSpace;
|
||||
}
|
||||
|
||||
private float getMinimumRequiredHeightForButtons()
|
||||
{
|
||||
return mZoomIn.getHeight() + mZoomOut.getHeight() + mMyPosition.getHeight();
|
||||
}
|
||||
|
||||
private void fadeOutZooms()
|
||||
{
|
||||
Animations.fadeOutView(mZoomIn, new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
mZoomIn.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
});
|
||||
Animations.fadeOutView(mZoomOut, new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
mZoomOut.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void fadeInZooms()
|
||||
{
|
||||
if (!showZoomButtons())
|
||||
return;
|
||||
|
||||
if (!canZoomButtonsFitInScreen())
|
||||
return;
|
||||
|
||||
mZoomIn.setVisibility(View.VISIBLE);
|
||||
mZoomOut.setVisibility(View.VISIBLE);
|
||||
Animations.fadeInView(mZoomIn, null);
|
||||
Animations.fadeInView(mZoomOut, null);
|
||||
}
|
||||
|
||||
private void fadeOutMyPosition()
|
||||
{
|
||||
mMyPosAnimate = true;
|
||||
Animations.fadeOutView(mMyPosition, new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
UiUtils.invisible(mMyPosition);
|
||||
mMyPosAnimate = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void fadeInMyPosition()
|
||||
{
|
||||
mMyPosAnimate = true;
|
||||
mMyPosition.setVisibility(View.VISIBLE);
|
||||
Animations.fadeInView(mMyPosition, new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
mMyPosAnimate = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void animateMyPosition(float translation)
|
||||
{
|
||||
mMyPosition.setTranslationY(translation);
|
||||
if (!shouldMyPositionBeHidden() && !mMyPosAnimate
|
||||
&& isOverTopLimit(mMyPosition))
|
||||
{
|
||||
fadeOutMyPosition();
|
||||
}
|
||||
else if (!shouldMyPositionBeHidden() && !mMyPosAnimate
|
||||
&& satisfyTopLimit(mMyPosition))
|
||||
{
|
||||
fadeInMyPosition();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isOverTopLimit(@NonNull View view)
|
||||
{
|
||||
return view.getVisibility() == View.VISIBLE && view.getY() <= mTopLimit;
|
||||
}
|
||||
|
||||
private boolean satisfyTopLimit(@NonNull View view)
|
||||
{
|
||||
return view.getVisibility() == View.INVISIBLE && view.getY() >= mTopLimit;
|
||||
}
|
||||
|
||||
private boolean shouldMyPositionBeHidden()
|
||||
{
|
||||
return LocationState.getMode() == LocationState.FOLLOW_AND_ROTATE
|
||||
&& (RoutingController.get().isPlanning());
|
||||
Animations.appearSliding(mZoomIn, Animations.LEFT, null);
|
||||
Animations.appearSliding(mZoomOut, Animations.LEFT, null);
|
||||
}
|
||||
|
||||
private static boolean showZoomButtons()
|
||||
|
@ -261,6 +250,6 @@ class NavigationButtonsAnimationController
|
|||
|
||||
public void onResume()
|
||||
{
|
||||
checkZoomButtonsVisibility();
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package com.mapswithme.maps.widget.menu;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.mapswithme.maps.MwmActivity;
|
||||
|
@ -11,9 +11,9 @@ import com.mapswithme.maps.R;
|
|||
import com.mapswithme.maps.downloader.MapManager;
|
||||
import com.mapswithme.maps.downloader.UpdateInfo;
|
||||
import com.mapswithme.maps.routing.RoutingController;
|
||||
import com.mapswithme.util.Animations;
|
||||
import com.mapswithme.util.Graphics;
|
||||
import com.mapswithme.util.UiUtils;
|
||||
import ru.mail.android.mytarget.core.models.Stat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
@ -263,9 +263,9 @@ public class MainMenu extends BaseMenu
|
|||
{
|
||||
UiUtils.show(mButtonsFrame);
|
||||
expandContent = false;
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
UiUtils.showIf(state == State.MENU, mButtonsFrame);
|
||||
UiUtils.showIf(isRouting, mRoutePlanFrame);
|
||||
if (isRouting)
|
||||
|
@ -313,8 +313,17 @@ public class MainMenu extends BaseMenu
|
|||
return mAnimationTrackListener;
|
||||
}
|
||||
|
||||
public void showLineFrame(boolean show)
|
||||
public void showLineFrame(boolean show, @Nullable Runnable completion)
|
||||
{
|
||||
UiUtils.showIf(show, mLineFrame);
|
||||
if (show)
|
||||
{
|
||||
UiUtils.hide(mFrame);
|
||||
Animations.appearSliding(mFrame, Animations.BOTTOM, completion);
|
||||
}
|
||||
else
|
||||
{
|
||||
UiUtils.show(mFrame);
|
||||
Animations.disappearSliding(mFrame, Animations.BOTTOM, completion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -143,7 +143,7 @@ public final class Animations
|
|||
});
|
||||
}
|
||||
|
||||
public static void rizeTransition(@NonNull ViewGroup rootView, @NonNull final Rect startRect,
|
||||
public static void riseTransition(@NonNull ViewGroup rootView, @NonNull final Rect startRect,
|
||||
@Nullable final Runnable runnable)
|
||||
{
|
||||
Context context = rootView.getContext();
|
||||
|
|
Loading…
Add table
Reference in a new issue