[android] fix: PlacePage animations.

This commit is contained in:
a.marchuk 2015-08-02 13:25:21 +03:00 committed by Alex Zolotarev
parent a2a8235e40
commit f0d84b21ca
15 changed files with 245 additions and 652 deletions

View file

@ -37,7 +37,7 @@
android:layout_width="360dp"
android:layout_height="match_parent"
android:layout_below="@+id/fl__routing"
placePage:animationType="leftFull"/>
placePage:animationType="left"/>
<com.mapswithme.maps.widget.FadeView
android:id="@+id/fade_view"

View file

@ -35,7 +35,7 @@
android:layout_below="@id/fl__routing"
android:layout_alignWithParentIfMissing="true"
android:layout_margin="@dimen/margin_base"
placePage:animationType="leftTop"/>
placePage:animationType="left"/>
<com.mapswithme.maps.widget.FadeView
android:id="@+id/fade_view"

View file

@ -1,65 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:placePage="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="bottom">
<FrameLayout
android:id="@+id/map_fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<include
android:id="@+id/toolbar_search"
layout="@layout/toolbar_with_search"
android:layout_width="@dimen/panel_width"
android:layout_height="?attr/actionBarSize"
android:layout_margin="@dimen/margin_base"/>
<FrameLayout
android:id="@+id/fl__routing"
style="@style/MwmWidget.Floating.Panel"
android:layout_width="@dimen/panel_width"
android:layout_height="@dimen/routing_pp_height"
android:layout_below="@+id/toolbar_search"
android:layout_marginTop="@dimen/margin_base"
android:layout_marginLeft="@dimen/margin_base">
<include layout="@layout/map_routing_full"/>
</FrameLayout>
<include
android:id="@+id/navigation_buttons"
layout="@layout/map_navigation_buttons"/>
<com.mapswithme.maps.widget.placepage.PlacePageView
android:id="@+id/info_box"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
placePage:animationType="bottom"/>
<com.mapswithme.maps.widget.FadeView
android:id="@+id/fade_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black"
android:visibility="gone"/>
<FrameLayout
android:id="@+id/fragment_container"
android:layout_width="@dimen/floating_panel_width"
android:layout_height="match_parent"
android:padding="@dimen/margin_base"
android:clipToPadding="false"/>
<com.mapswithme.maps.widget.BottomButtonsLayout
android:id="@+id/map_bottom_buttons"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:padding="@dimen/margin_quarter"/>
</RelativeLayout>

View file

@ -34,7 +34,7 @@
android:layout_margin="@dimen/margin_base"
android:layout_below="@id/fl__routing"
android:layout_alignWithParentIfMissing="true"
placePage:animationType="leftTop"/>
placePage:animationType="left"/>
<com.mapswithme.maps.widget.FadeView
android:id="@+id/fade_view"

View file

@ -1,39 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<include
android:id="@+id/pp__preview"
layout="@layout/place_page_preview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/pp__buttons"/>
<include
android:id="@+id/pp__details_frame"
layout="@layout/place_page_details"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/pp__buttons"
android:layout_marginTop="56dp"/>
<View
android:id="@+id/view_bottom_white"
android:layout_width="match_parent"
android:layout_height="@dimen/place_page_buttons_height"
android:layout_alignParentBottom="true"
android:background="@color/bg_top_panels"
android:visibility="gone"/>
<include
android:id="@+id/pp__buttons"
layout="@layout/place_page_buttons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"/>
<include
android:id="@+id/toolbar_layout"
layout="@layout/toolbar_elevated"
android:visibility="gone"/>
</merge>

View file

@ -1,23 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
<include
android:id="@+id/pp__preview"
layout="@layout/place_page_preview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/pp__buttons"/>
<include
android:id="@+id/pp__details_frame"
layout="@layout/place_page_details"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/pp__buttons"
android:layout_marginTop="56dp"/>
<View
android:id="@+id/view_bottom_white"
android:layout_width="match_parent"
android:layout_height="@dimen/place_page_buttons_height"
android:layout_alignParentBottom="true"
android:background="@color/bg_top_panels"
android:orientation="vertical">
<include
android:id="@+id/pp__preview"
layout="@layout/place_page_preview"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<include android:id="@+id/pp__details_frame"
layout="@layout/place_page_details"/>
</LinearLayout>
android:visibility="gone"/>
<include
android:id="@+id/pp__buttons"
@ -26,4 +31,9 @@
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"/>
<include
android:id="@+id/toolbar_layout"
layout="@layout/toolbar_elevated"
android:visibility="gone"/>
</merge>

View file

@ -10,9 +10,7 @@
<declare-styleable name="PlacePageView">
<attr name="animationType" format="enum">
<enum name="bottom" value="0"/>
<enum name="top" value="1"/>
<enum name="leftTop" value="2"/>
<enum name="leftFull" value="3"/>
<enum name="left" value="1"/>
</attr>
</declare-styleable>

View file

@ -1,5 +1,6 @@
package com.mapswithme.maps.widget.placepage;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.v4.view.GestureDetectorCompat;
import android.view.MotionEvent;
@ -8,6 +9,7 @@ import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.ScrollView;
import com.mapswithme.maps.MWMApplication;
import com.mapswithme.maps.R;
import com.mapswithme.maps.bookmarks.data.MapObject;
import com.mapswithme.maps.widget.placepage.PlacePageView.State;
@ -17,8 +19,8 @@ import com.mapswithme.maps.widget.placepage.PlacePageView.State;
*/
public abstract class BasePlacePageAnimationController
{
protected static final int SHORT_ANIM_DURATION = 200;
protected static final int LONG_ANIM_DURATION = 400;
protected static final int DURATION = MWMApplication.get().getResources().getInteger(R.integer.anim_duration_default);
protected static final boolean NO_ANIMATION = (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB);
protected State mState = State.HIDDEN;
@ -35,9 +37,6 @@ public abstract class BasePlacePageAnimationController
protected float mDownCoord;
protected float mTouchSlop;
// Visibility
// TODO consider removal
protected boolean mIsPreviewVisible;
protected boolean mIsPlacePageVisible;
protected OnVisibilityChangedListener mVisibilityChangedListener;
public interface OnVisibilityChangedListener
@ -47,7 +46,7 @@ public abstract class BasePlacePageAnimationController
void onPlacePageVisibilityChanged(boolean isVisible);
}
abstract void initGestureDetector();
protected abstract void initGestureDetector();
public BasePlacePageAnimationController(@NonNull PlacePageView placePage)
{
@ -65,20 +64,18 @@ public abstract class BasePlacePageAnimationController
public void setState(State state, MapObject.MapObjectType type)
{
State newState;
State newState = state;
if (type == MapObject.MapObjectType.BOOKMARK && state == State.DETAILS)
newState = State.BOOKMARK;
else
newState = state;
if (newState != mState)
{
animateStateChange(mState, newState);
onStateChanged(mState, newState);
mState = newState;
}
}
abstract void animateStateChange(State currentState, State newState);
protected abstract void onStateChanged(State currentState, State newState);
public State getState()
{
@ -90,19 +87,19 @@ public abstract class BasePlacePageAnimationController
mVisibilityChangedListener = listener;
}
abstract boolean onInterceptTouchEvent(MotionEvent event);
protected abstract boolean onInterceptTouchEvent(MotionEvent event);
protected boolean onTouchEvent(@NonNull MotionEvent event)
{
return mGestureDetector.onTouchEvent(event);
}
protected void notifyVisibilityListener()
protected void finishAnimation(boolean previewShown, boolean ppShown)
{
if (mVisibilityChangedListener != null)
{
mVisibilityChangedListener.onPreviewVisibilityChanged(mIsPreviewVisible);
mVisibilityChangedListener.onPlacePageVisibilityChanged(mIsPlacePageVisible);
mVisibilityChangedListener.onPreviewVisibilityChanged(previewShown);
mVisibilityChangedListener.onPlacePageVisibilityChanged(ppShown);
}
}
}

View file

@ -1,168 +0,0 @@
package com.mapswithme.maps.widget.placepage;
import android.support.annotation.NonNull;
import android.support.v4.view.GestureDetectorCompat;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import com.mapswithme.maps.Framework;
import com.mapswithme.maps.widget.placepage.PlacePageView.State;
// TODO remove this class after minSdk will be 11+
public class CompatPlacePageAnimationController extends BasePlacePageAnimationController
{
public CompatPlacePageAnimationController(@NonNull PlacePageView placePage)
{
super(placePage);
}
@Override
boolean onInterceptTouchEvent(MotionEvent event)
{
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
mIsGestureHandled = false;
mDownCoord = event.getY() - ((ViewGroup) mPreview.getParent()).getTop();
break;
case MotionEvent.ACTION_MOVE:
final float yDiff = mDownCoord - event.getY();
final float buttonsY = mButtons.getTop();
if (mDownCoord < mPreview.getTop() || mDownCoord > buttonsY ||
(mDownCoord > mFrame.getTop() && mDownCoord < buttonsY))
return false;
if (Math.abs(yDiff) > mTouchSlop)
return true;
break;
}
return false;
}
@Override
protected boolean onTouchEvent(@NonNull MotionEvent event)
{
if (mDownCoord < mPreview.getTop() || mDownCoord > mButtons.getTop())
return false;
super.onTouchEvent(event);
return true;
}
@Override
protected void initGestureDetector()
{
mGestureDetector = new GestureDetectorCompat(mPlacePage.getContext(), new GestureDetector.SimpleOnGestureListener()
{
private static final int Y_MIN = 1;
private static final int Y_MAX = 100;
private static final int X_TO_Y_SCROLL_RATIO = 2;
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)
{
final float absDistanceY = Math.abs(distanceY);
final boolean isVertical = absDistanceY > X_TO_Y_SCROLL_RATIO * Math.abs(distanceX);
final boolean isInRange = absDistanceY > Y_MIN && absDistanceY < Y_MAX;
if (isVertical && isInRange)
{
if (!mIsGestureHandled)
{
if (distanceY < 0f)
{
Framework.deactivatePopup();
mPlacePage.setState(State.HIDDEN);
}
else
mPlacePage.setState(State.DETAILS);
mIsGestureHandled = true;
}
return true;
}
return false;
}
@Override
public boolean onSingleTapConfirmed(MotionEvent e)
{
if (mDownCoord < mPreview.getTop() && mDownCoord < mFrame.getTop())
return false;
if (mPlacePage.getState() == State.PREVIEW)
mPlacePage.setState(State.DETAILS);
else
mPlacePage.setState(State.PREVIEW);
return true;
}
});
}
@Override
void animateStateChange(State currentState, State newState)
{
switch (newState)
{
case HIDDEN:
hidePlacePage();
break;
case PREVIEW:
showPreview();
break;
case BOOKMARK:
showBookmark();
break;
case DETAILS:
showDetails();
break;
}
}
protected void showPreview()
{
mPlacePage.setVisibility(View.VISIBLE);
mPreview.setVisibility(View.VISIBLE);
mFrame.setVisibility(View.GONE);
mIsPlacePageVisible = false;
mIsPreviewVisible = true;
notifyVisibilityListener();
}
protected void showDetails()
{
mPlacePage.setVisibility(View.VISIBLE);
mPreview.setVisibility(View.VISIBLE);
mFrame.setVisibility(View.VISIBLE);
mBookmarkDetails.setVisibility(View.GONE);
mIsPreviewVisible = mIsPlacePageVisible = true;
notifyVisibilityListener();
}
void showBookmark()
{
mPlacePage.setVisibility(View.VISIBLE);
mPreview.setVisibility(View.VISIBLE);
mFrame.setVisibility(View.VISIBLE);
mBookmarkDetails.setVisibility(View.VISIBLE);
mButtons.setVisibility(View.VISIBLE);
mButtons.bringToFront();
mIsPreviewVisible = mIsPlacePageVisible = true;
notifyVisibilityListener();
}
protected void hidePlacePage()
{
mPlacePage.setVisibility(View.GONE);
mIsPreviewVisible = mIsPlacePageVisible = false;
notifyVisibilityListener();
}
}

View file

@ -1,24 +0,0 @@
package com.mapswithme.maps.widget.placepage;
import android.support.annotation.NonNull;
import com.mapswithme.util.UiUtils;
import com.nineoldandroids.view.ViewHelper;
public class LeftCompatAnimationController extends LeftFullPlacePageAnimationController
{
public LeftCompatAnimationController(@NonNull PlacePageView placePage)
{
super(placePage);
}
@Override
protected void hidePlacePage()
{
ViewHelper.setTranslationX(mPlacePage, -mPlacePage.getWidth());
mPlacePage.clearAnimation(); // need clear animation to correctly hide view on pre-honeycomb devices.
UiUtils.hide(mPlacePage);
mIsPlacePageVisible = mIsPreviewVisible = false;
notifyVisibilityListener();
}
}

View file

@ -1,177 +0,0 @@
package com.mapswithme.maps.widget.placepage;
import android.support.annotation.NonNull;
import android.support.v4.view.GestureDetectorCompat;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
import com.mapswithme.maps.Framework;
import com.mapswithme.maps.bookmarks.data.MapObject;
import com.mapswithme.maps.widget.placepage.PlacePageView.State;
import com.mapswithme.util.UiUtils;
import com.nineoldandroids.animation.Animator;
import com.nineoldandroids.animation.ValueAnimator;
import com.nineoldandroids.view.ViewHelper;
public class LeftFloatPlacePageAnimationController extends BasePlacePageAnimationController
{
public LeftFloatPlacePageAnimationController(@NonNull PlacePageView placePage)
{
super(placePage);
}
@Override
boolean onInterceptTouchEvent(MotionEvent event)
{
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
mIsGestureHandled = false;
mDownCoord = event.getY();
break;
case MotionEvent.ACTION_MOVE:
final float yDiff = mDownCoord - event.getY();
if (mDownCoord < ViewHelper.getY(mPreview) || mDownCoord > ViewHelper.getY(mButtons) ||
(mDownCoord > ViewHelper.getY(mFrame) && mDownCoord < ViewHelper.getY(mButtons) &&
(mFrame.getHeight() != mDetailsContent.getHeight() && (mDetails.getScrollY() != 0 || yDiff > 0))))
return false;
if (Math.abs(yDiff) > mTouchSlop)
return true;
break;
}
return false;
}
@Override
protected boolean onTouchEvent(@NonNull MotionEvent event)
{
if (mDownCoord < ViewHelper.getY(mPreview) || mDownCoord > ViewHelper.getY(mButtons))
return false;
super.onTouchEvent(event);
return true;
}
@Override
protected void initGestureDetector()
{
mGestureDetector = new GestureDetectorCompat(mPlacePage.getContext(), new GestureDetector.SimpleOnGestureListener()
{
private static final int Y_MIN = 1;
private static final int Y_MAX = 100;
private static final int X_TO_Y_SCROLL_RATIO = 2;
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)
{
final boolean isVertical = Math.abs(distanceY) > X_TO_Y_SCROLL_RATIO * Math.abs(distanceX);
final boolean isInRange = Math.abs(distanceY) > Y_MIN && Math.abs(distanceY) < Y_MAX;
if (isVertical && isInRange)
{
if (!mIsGestureHandled)
{
if (distanceY < 0)
{
mPlacePage.setState(State.HIDDEN);
Framework.deactivatePopup();
}
mIsGestureHandled = true;
}
return true;
}
return false;
}
});
}
@Override
public void setState(State state, MapObject.MapObjectType type)
{
if (state == State.PREVIEW && type == MapObject.MapObjectType.BOOKMARK)
state = State.BOOKMARK;
super.setState(state, type);
}
@Override
void animateStateChange(State currentState, State newState)
{
switch (newState)
{
case HIDDEN:
hidePlacePage();
break;
case BOOKMARK:
case DETAILS:
case PREVIEW:
showPlacePage(currentState, newState);
break;
}
}
protected void showPlacePage(final State currentState, final State newState)
{
mPlacePage.setVisibility(View.VISIBLE);
mBookmarkDetails.setVisibility(newState == State.BOOKMARK ? View.VISIBLE : View.GONE);
if (currentState == State.HIDDEN)
{
ValueAnimator animator = ValueAnimator.ofFloat(mPlacePage.getHeight(), 0f);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
{
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
ViewHelper.setTranslationY(mPlacePage, (Float) animation.getAnimatedValue());
}
});
animator.addListener(new UiUtils.SimpleNineoldAnimationListener()
{
@Override
public void onAnimationEnd(Animator animation)
{
mIsPlacePageVisible = mIsPreviewVisible = true;
notifyVisibilityListener();
}
});
animator.setDuration(SHORT_ANIM_DURATION);
animator.setInterpolator(new AccelerateInterpolator());
animator.start();
}
}
protected void hidePlacePage()
{
ValueAnimator animator;
animator = ValueAnimator.ofFloat(0, mPlacePage.getHeight());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
{
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
ViewHelper.setTranslationY(mPlacePage, (Float) animation.getAnimatedValue());
}
});
animator.addListener(new UiUtils.SimpleNineoldAnimationListener()
{
@Override
public void onAnimationEnd(Animator animation)
{
mPlacePage.setVisibility(View.INVISIBLE);
mIsPlacePageVisible = mIsPreviewVisible = false;
notifyVisibilityListener();
}
});
animator.setDuration(SHORT_ANIM_DURATION);
animator.setInterpolator(new AccelerateInterpolator());
animator.start();
}
}

View file

@ -1,5 +1,6 @@
package com.mapswithme.maps.widget.placepage;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.os.Build;
import android.support.annotation.NonNull;
@ -14,21 +15,41 @@ import android.view.animation.Interpolator;
import android.view.animation.OvershootInterpolator;
import android.widget.LinearLayout;
import com.mapswithme.maps.Framework;
import com.mapswithme.maps.R;
import com.mapswithme.maps.widget.placepage.PlacePageView.State;
import com.mapswithme.util.UiUtils;
import com.mapswithme.util.concurrency.UiThread;
import com.nineoldandroids.animation.Animator;
import com.nineoldandroids.animation.ValueAnimator;
import com.nineoldandroids.view.ViewHelper;
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class BottomPlacePageAnimationController extends BasePlacePageAnimationController implements View.OnLayoutChangeListener
class PlacePageBottomAnimationController extends BasePlacePageAnimationController
{
private final View mViewBottomHack;
private final ViewGroup mLayoutToolbar;
public BottomPlacePageAnimationController(@NonNull PlacePageView placePage)
private final AnimationHelper mAnimationHelper = (NO_ANIMATION ? null : new AnimationHelper());
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private class AnimationHelper
{
final View.OnLayoutChangeListener mListener = 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)
{
if (mState == State.BOOKMARK && v.getId() == mFrame.getId() && top != oldTop)
{
ViewHelper.setTranslationY(mPreview, -mDetailsContent.getHeight());
refreshToolbarVisibility();
}
}
};
}
public PlacePageBottomAnimationController(@NonNull PlacePageView placePage)
{
super(placePage);
mViewBottomHack = mPlacePage.findViewById(R.id.view_bottom_white);
@ -49,7 +70,7 @@ public class BottomPlacePageAnimationController extends BasePlacePageAnimationCo
}
@Override
boolean onInterceptTouchEvent(MotionEvent event)
protected boolean onInterceptTouchEvent(MotionEvent event)
{
switch (event.getAction())
{
@ -86,7 +107,7 @@ public class BottomPlacePageAnimationController extends BasePlacePageAnimationCo
{
mGestureDetector = new GestureDetectorCompat(mPlacePage.getContext(), new GestureDetector.SimpleOnGestureListener()
{
private static final int Y_MIN = 1;
private static final int Y_MIN = 4;
private static final int Y_MAX = 100;
private static final int X_TO_Y_SCROLL_RATIO = 2;
@ -101,10 +122,7 @@ public class BottomPlacePageAnimationController extends BasePlacePageAnimationCo
if (!mIsGestureHandled)
{
if (distanceY < 0f)
{
Framework.deactivatePopup();
mPlacePage.setState(State.HIDDEN);
}
else
mPlacePage.setState(State.DETAILS);
@ -134,7 +152,7 @@ public class BottomPlacePageAnimationController extends BasePlacePageAnimationCo
}
@Override
void animateStateChange(State currentState, State newState)
protected void onStateChanged(State currentState, State newState)
{
switch (newState)
{
@ -153,20 +171,42 @@ public class BottomPlacePageAnimationController extends BasePlacePageAnimationCo
}
}
@SuppressLint("NewApi")
protected void showPreview(final State currentState)
{
mPlacePage.setVisibility(View.VISIBLE);
mPreview.setVisibility(View.VISIBLE);
mFrame.addOnLayoutChangeListener(this);
UiUtils.show(mPlacePage, mPreview);
if (mLayoutToolbar != null)
mLayoutToolbar.setVisibility(View.GONE);
UiUtils.hide(mLayoutToolbar);
if (NO_ANIMATION)
{
UiUtils.show(mViewBottomHack);
if (currentState == State.HIDDEN)
{
UiUtils.show(mViewBottomHack);
ViewHelper.setTranslationY(mPreview, 0.0f);
}
else
{
UiUtils.invisible(mBookmarkDetails);
}
UiUtils.invisible(mFrame);
finishAnimation(true, false);
return;
}
if (mAnimationHelper != null)
mFrame.addOnLayoutChangeListener(mAnimationHelper.mListener);
ValueAnimator animator;
Interpolator interpolator;
if (currentState == State.HIDDEN)
{
mViewBottomHack.setVisibility(View.GONE);
mFrame.setVisibility(View.INVISIBLE);
UiUtils.hide(mViewBottomHack);
UiUtils.invisible(mFrame);
interpolator = new OvershootInterpolator();
animator = ValueAnimator.ofFloat(mPreview.getHeight() + mButtons.getHeight(), 0f);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
@ -178,7 +218,7 @@ public class BottomPlacePageAnimationController extends BasePlacePageAnimationCo
ViewHelper.setTranslationY(mButtons, (Float) animation.getAnimatedValue());
if (animation.getAnimatedFraction() > .5f)
mViewBottomHack.setVisibility(View.VISIBLE);
UiUtils.show(mViewBottomHack);
}
});
animator.addListener(new UiUtils.SimpleNineoldAnimationListener()
@ -186,9 +226,7 @@ public class BottomPlacePageAnimationController extends BasePlacePageAnimationCo
@Override
public void onAnimationEnd(Animator animation)
{
mIsPlacePageVisible = false;
mIsPreviewVisible = true;
notifyVisibilityListener();
finishAnimation(true, false);
}
});
}
@ -211,36 +249,55 @@ public class BottomPlacePageAnimationController extends BasePlacePageAnimationCo
@Override
public void onAnimationEnd(Animator animation)
{
mFrame.setVisibility(View.INVISIBLE);
mBookmarkDetails.setVisibility(View.INVISIBLE);
mIsPlacePageVisible = false;
mIsPreviewVisible = true;
notifyVisibilityListener();
UiUtils.invisible(mFrame, mBookmarkDetails);
finishAnimation(true, false);
}
});
}
animator.setDuration(SHORT_ANIM_DURATION);
animator.setDuration(DURATION);
animator.setInterpolator(interpolator);
animator.start();
}
private void correctPreviewTranslation()
{
UiThread.runLater(new Runnable()
{
@Override
public void run()
{
ViewHelper.setTranslationY(mPreview, -mDetailsContent.getHeight());
}
});
}
private void showPreviewFrame()
{
UiUtils.show(mPlacePage, mPreview, mFrame);
if (NO_ANIMATION)
correctPreviewTranslation();
}
protected void showDetails(final State currentState)
{
mPlacePage.setVisibility(View.VISIBLE);
mPreview.setVisibility(View.VISIBLE);
mFrame.setVisibility(View.VISIBLE);
showPreviewFrame();
if (NO_ANIMATION)
{
refreshToolbarVisibility();
finishAnimation(true, true);
mDetails.scrollTo(0, 0);
UiUtils.hide(mBookmarkDetails);
return;
}
ValueAnimator animator;
final float detailsFullHeight = mDetailsContent.getHeight();
final float detailsScreenHeight = mDetails.getHeight();
final float bookmarkFullHeight = mBookmarkDetails.getHeight();
final float bookmarkScreenHeight = bookmarkFullHeight - (detailsFullHeight - detailsScreenHeight);
if (currentState == State.PREVIEW)
animator = ValueAnimator.ofFloat(detailsScreenHeight, bookmarkScreenHeight);
else
animator = ValueAnimator.ofFloat(0f, bookmarkScreenHeight);
ValueAnimator animator = ValueAnimator.ofFloat(currentState == State.PREVIEW ? detailsScreenHeight : 0,
bookmarkScreenHeight);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
{
@Override
@ -256,36 +313,35 @@ public class BottomPlacePageAnimationController extends BasePlacePageAnimationCo
public void onAnimationEnd(Animator animation)
{
refreshToolbarVisibility();
mIsPreviewVisible = mIsPlacePageVisible = true;
notifyVisibilityListener();
finishAnimation(true, true);
mDetails.scrollTo(0, 0);
mBookmarkDetails.setVisibility(View.INVISIBLE);
UiUtils.invisible(mBookmarkDetails);
}
});
animator.setDuration(SHORT_ANIM_DURATION);
animator.setDuration(DURATION);
animator.setInterpolator(new AccelerateInterpolator());
animator.start();
}
void showBookmark(final State currentState)
{
mPlacePage.setVisibility(View.VISIBLE);
mPreview.setVisibility(View.VISIBLE);
mFrame.setVisibility(View.VISIBLE);
mBookmarkDetails.setVisibility(View.VISIBLE);
UiUtils.show(mBookmarkDetails);
showPreviewFrame();
if (NO_ANIMATION)
{
refreshToolbarVisibility();
finishAnimation(true, true);
return;
}
ValueAnimator animator;
final float detailsFullHeight = mDetailsContent.getHeight();
final float detailsScreenHeight = mDetails.getHeight();
final float bookmarkHeight = mBookmarkDetails.getHeight();
final float bookmarkScreenHeight = bookmarkHeight - (detailsFullHeight - detailsScreenHeight);
if (currentState == State.DETAILS)
animator = ValueAnimator.ofFloat(bookmarkScreenHeight, 0f);
else
animator = ValueAnimator.ofFloat(detailsScreenHeight, 0f);
ValueAnimator animator = ValueAnimator.ofFloat(currentState == State.DETAILS ? bookmarkHeight - (detailsFullHeight - detailsScreenHeight)
: detailsScreenHeight, 0.0f);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
{
@Override
@ -301,31 +357,47 @@ public class BottomPlacePageAnimationController extends BasePlacePageAnimationCo
public void onAnimationEnd(Animator animation)
{
refreshToolbarVisibility();
mIsPreviewVisible = mIsPlacePageVisible = true;
notifyVisibilityListener();
finishAnimation(true, true);
}
});
animator.setDuration(SHORT_ANIM_DURATION);
animator.setDuration(DURATION);
animator.setInterpolator(new AccelerateInterpolator());
animator.start();
}
private void refreshToolbarVisibility()
protected void refreshToolbarVisibility()
{
if (mLayoutToolbar != null)
mLayoutToolbar.setVisibility(ViewHelper.getY(mFrame) < mPreview.getHeight() ? View.VISIBLE : View.GONE);
UiThread.runLater(new Runnable()
{
@Override
public void run()
{
UiUtils.showIf(ViewHelper.getY(mPreview) < 0, mLayoutToolbar);
}
});
}
@SuppressLint("NewApi")
protected void hidePlacePage()
{
UiUtils.hide(mViewBottomHack);
if (mLayoutToolbar != null)
mLayoutToolbar.setVisibility(View.GONE);
UiUtils.hide(mLayoutToolbar);
if (NO_ANIMATION)
{
UiUtils.hide(mPlacePage);
finishAnimation(false, false);
return;
}
if (mAnimationHelper != null)
mFrame.removeOnLayoutChangeListener(mAnimationHelper.mListener);
mFrame.removeOnLayoutChangeListener(this);
final float animHeight = mPlacePage.getHeight() - mPreview.getTop() - ViewHelper.getTranslationY(mPreview);
final ValueAnimator animator = ValueAnimator.ofFloat(0f, animHeight);
mViewBottomHack.setVisibility(View.GONE);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
{
@Override
@ -339,26 +411,13 @@ public class BottomPlacePageAnimationController extends BasePlacePageAnimationCo
@Override
public void onAnimationEnd(Animator animation)
{
mIsPreviewVisible = mIsPlacePageVisible = false;
mPlacePage.setVisibility(View.INVISIBLE);
mBookmarkDetails.setVisibility(View.INVISIBLE);
UiUtils.invisible(mPlacePage, mBookmarkDetails);
ViewHelper.setTranslationY(mPlacePage, 0);
notifyVisibilityListener();
finishAnimation(false, false);
}
});
animator.setDuration(SHORT_ANIM_DURATION);
animator.setDuration(DURATION);
animator.setInterpolator(new AccelerateInterpolator());
animator.start();
}
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom)
{
if (mState == State.BOOKMARK && v.getId() == mFrame.getId() && top != oldTop)
{
ViewHelper.setTranslationY(mPreview, -mDetailsContent.getHeight());
refreshToolbarVisibility();
}
}
}

View file

@ -4,7 +4,6 @@ import android.support.annotation.NonNull;
import android.support.v4.view.GestureDetectorCompat;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
import com.mapswithme.maps.bookmarks.data.MapObject;
@ -14,15 +13,15 @@ import com.nineoldandroids.animation.Animator;
import com.nineoldandroids.animation.ValueAnimator;
import com.nineoldandroids.view.ViewHelper;
public class LeftFullPlacePageAnimationController extends BasePlacePageAnimationController
class PlacePageLeftAnimationController extends BasePlacePageAnimationController
{
public LeftFullPlacePageAnimationController(@NonNull PlacePageView placePage)
public PlacePageLeftAnimationController(@NonNull PlacePageView placePage)
{
super(placePage);
}
@Override
boolean onInterceptTouchEvent(MotionEvent event)
protected boolean onInterceptTouchEvent(MotionEvent event)
{
switch (event.getAction())
{
@ -56,7 +55,7 @@ public class LeftFullPlacePageAnimationController extends BasePlacePageAnimation
{
mGestureDetector = new GestureDetectorCompat(mPlacePage.getContext(), new GestureDetector.SimpleOnGestureListener()
{
private static final int X_MIN = 1;
private static final int X_MIN = 4;
private static final int X_MAX = 100;
private static final int X_TO_Y_SCROLL_RATIO = 2;
@ -94,7 +93,7 @@ public class LeftFullPlacePageAnimationController extends BasePlacePageAnimation
}
@Override
void animateStateChange(State currentState, State newState)
protected void onStateChanged(State currentState, State newState)
{
switch (newState)
{
@ -111,39 +110,18 @@ public class LeftFullPlacePageAnimationController extends BasePlacePageAnimation
protected void showPlacePage(final State currentState, final State newState)
{
mPlacePage.setVisibility(View.VISIBLE);
mBookmarkDetails.setVisibility(newState == State.BOOKMARK ? View.VISIBLE : View.GONE);
if (currentState == State.HIDDEN)
UiUtils.show(mPlacePage);
UiUtils.showIf(newState == State.BOOKMARK, mBookmarkDetails);
if (currentState != State.HIDDEN)
return;
if (NO_ANIMATION)
{
ValueAnimator animator = ValueAnimator.ofFloat(-mPlacePage.getWidth(), 0f);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
{
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
ViewHelper.setTranslationX(mPlacePage, (Float) animation.getAnimatedValue());
}
});
animator.addListener(new UiUtils.SimpleNineoldAnimationListener()
{
@Override
public void onAnimationEnd(Animator animation)
{
mIsPlacePageVisible = mIsPreviewVisible = true;
notifyVisibilityListener();
}
});
animator.setDuration(SHORT_ANIM_DURATION);
animator.setInterpolator(new AccelerateInterpolator());
animator.start();
finishAnimation(true, true);
return;
}
}
protected void hidePlacePage()
{
ValueAnimator animator;
animator = ValueAnimator.ofFloat(0f, -mPlacePage.getWidth());
ValueAnimator animator = ValueAnimator.ofFloat(-mPlacePage.getWidth(), 0f);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
{
@Override
@ -157,13 +135,45 @@ public class LeftFullPlacePageAnimationController extends BasePlacePageAnimation
@Override
public void onAnimationEnd(Animator animation)
{
mPlacePage.setVisibility(View.INVISIBLE);
mIsPlacePageVisible = mIsPreviewVisible = false;
notifyVisibilityListener();
finishAnimation(true, true);
}
});
animator.setDuration(SHORT_ANIM_DURATION);
animator.setDuration(DURATION);
animator.setInterpolator(new AccelerateInterpolator());
animator.start();
}
protected void hidePlacePage()
{
if (NO_ANIMATION)
{
UiUtils.hide(mPlacePage);
finishAnimation(false, false);
return;
}
ValueAnimator animator;
animator = ValueAnimator.ofFloat(0.0f, -mPlacePage.getWidth());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
{
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
ViewHelper.setTranslationX(mPlacePage, (Float) animation.getAnimatedValue());
}
});
animator.addListener(new UiUtils.SimpleNineoldAnimationListener()
{
@Override
public void onAnimationEnd(Animator animation)
{
UiUtils.invisible(mPlacePage);
finishAnimation(false, false);
}
});
animator.setDuration(DURATION);
animator.setInterpolator(new AccelerateInterpolator());
animator.start();
}

View file

@ -137,13 +137,12 @@ public class PlacePageView extends RelativeLayout implements View.OnClickListene
{
super(context, attrs);
mIsLatLonDms = context.getSharedPreferences(context.getString(R.string.pref_file_name),
Context.MODE_PRIVATE).getBoolean(PREF_USE_DMS, false);
mIsLatLonDms = context.getSharedPreferences(context.getString(R.string.pref_file_name), Context.MODE_PRIVATE)
.getBoolean(PREF_USE_DMS, false);
initViews();
initAnimationController(attrs, defStyleAttr);
setVisibility(View.INVISIBLE);
UiUtils.invisible(this);
}
private void initViews()
@ -219,6 +218,9 @@ public class PlacePageView extends RelativeLayout implements View.OnClickListene
mShadowController = new ScrollViewShadowController((ObservableScrollView) mPpDetails)
.addShadow(BaseShadowController.BOTTOM, R.id.shadow_bottom)
.attach();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
setElevation(getResources().getDimensionPixelSize(R.dimen.appbar_elevation));
}
private void initAnimationController(AttributeSet attrs, int defStyleAttr)
@ -229,24 +231,12 @@ public class PlacePageView extends RelativeLayout implements View.OnClickListene
// switch with values from "animationType" from attrs.xml
switch (animationType)
{
// TODO remove hacks with api levels after app will have 11+ SDK
case 0:
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB)
mAnimationController = new CompatPlacePageAnimationController(this);
else
mAnimationController = new BottomPlacePageAnimationController(this);
mAnimationController = new PlacePageBottomAnimationController(this);
break;
case 2:
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB)
mAnimationController = new LeftCompatAnimationController(this);
else
mAnimationController = new LeftFloatPlacePageAnimationController(this);
break;
case 3:
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB)
mAnimationController = new LeftCompatAnimationController(this);
else
mAnimationController = new LeftFullPlacePageAnimationController(this);
case 1:
mAnimationController = new PlacePageLeftAnimationController(this);
break;
}
}
@ -436,13 +426,10 @@ public class PlacePageView extends RelativeLayout implements View.OnClickListene
refreshMetadataStars(mMapObject.getMetadata(Metadata.MetadataType.FMD_STARS));
final String elevation = mMapObject.getMetadata(Metadata.MetadataType.FMD_ELE);
if (!TextUtils.isEmpty(elevation))
{
mTvElevation.setVisibility(View.VISIBLE);
mTvElevation.setText(elevation);
}
if (TextUtils.isEmpty(elevation))
UiUtils.hide(mTvElevation);
else
mTvElevation.setVisibility(View.GONE);
UiUtils.setTextAndShow(mTvElevation, elevation);
}
private void refreshButtons(boolean showBackButton)
@ -476,8 +463,8 @@ public class PlacePageView extends RelativeLayout implements View.OnClickListene
if (l.hasAltitude())
builder.append(Framework.nativeFormatAltitude(l.getAltitude()));
if (l.hasSpeed())
builder.append(" ").
append(Framework.nativeFormatSpeed(l.getSpeed()));
builder.append(" ")
.append(Framework.nativeFormatSpeed(l.getSpeed()));
mTvSubtitle.setText(builder.toString());
mMapObject.setLat(l.getLatitude());
@ -508,7 +495,7 @@ public class PlacePageView extends RelativeLayout implements View.OnClickListene
mTvLatlon.setText(latLon[0] + ", " + latLon[1]);
}
private void refreshMetadataOrHide(String metadata, LinearLayout metaLayout, TextView metaTv)
private static void refreshMetadataOrHide(String metadata, LinearLayout metaLayout, TextView metaTv)
{
if (!TextUtils.isEmpty(metadata))
{

View file

@ -71,9 +71,14 @@ public final class UiUtils
v.setVisibility(View.INVISIBLE);
}
public static void showIf(boolean isShow, View... views)
public static void showIf(boolean condition, View view)
{
if (isShow)
view.setVisibility(condition ? View.VISIBLE : View.GONE);
}
public static void showIf(boolean condition, View... views)
{
if (condition)
show(views);
else
hide(views);