This repository has been archived by the owner on Feb 9, 2023. It is now read-only.
forked from google/hover
-
Notifications
You must be signed in to change notification settings - Fork 2
[CD-51] Close pop with gesture, add animation #32
Merged
Merged
Changes from 24 commits
Commits
Show all changes
25 commits
Select commit
Hold shift + click to select a range
98869a1
Add ExitView show/hide animation
realwind2048 8755b79
Add show/hide Animation test for ExitView
realwind2048 71b041e
Set new exitZone
realwind2048 98fcadb
Add TODO
realwind2048 b980abd
Add TODO
realwind2048 293ae30
Add Doc position calculation
realwind2048 551d2be
Add calculation
realwind2048 1a5d18b
Add center align test code
realwind2048 d9f665e
Improve touch UX
realwind2048 3f57a72
Add TODOs
realwind2048 28e8391
Polish exit Animation
realwind2048 95b4d35
Polish code
realwind2048 74d97a4
Add HandleDrop
realwind2048 836366e
Resolve TODO
realwind2048 9d1a905
Add initExitIconViewStatus
realwind2048 8db94a7
Remove unused import
realwind2048 e3f6baa
Apply review
realwind2048 726fda2
Apply design review: allow setting pop icon location on left bottom a…
realwind2048 009a224
Polish code
realwind2048 2fed293
Apply review: improve readability
realwind2048 15d7663
Apply design review: adjust min MIN_TAB_VERTICAL_POSITION to fix cutt…
realwind2048 3f43375
polish code
realwind2048 fbfdb83
Apply review: improve readability
realwind2048 d1c6976
Add missing commits
realwind2048 524ac14
Apply review: remove unused code
realwind2048 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,14 +15,20 @@ | |
*/ | ||
package io.mattcarroll.hover; | ||
|
||
import android.animation.Animator; | ||
import android.animation.ObjectAnimator; | ||
import android.animation.PropertyValuesHolder; | ||
import android.content.Context; | ||
import android.graphics.Point; | ||
import android.graphics.Rect; | ||
import android.support.annotation.NonNull; | ||
import android.support.annotation.Nullable; | ||
import android.support.v4.view.animation.PathInterpolatorCompat; | ||
import android.util.AttributeSet; | ||
import android.util.Log; | ||
import android.view.LayoutInflater; | ||
import android.view.View; | ||
import android.view.ViewGroup; | ||
import android.view.animation.Interpolator; | ||
import android.widget.RelativeLayout; | ||
|
||
/** | ||
|
@@ -32,8 +38,28 @@ class ExitView extends RelativeLayout { | |
|
||
private static final String TAG = "ExitView"; | ||
|
||
private static final int FADE_DURATION = 250; | ||
private static final int SHOW_HIDE_DURATION = 250; | ||
private static final float EXIT_ICON_DEFAULT_SCALE_X = 1.0f; | ||
private static final float EXIT_ICON_DEFAULT_SCALE_Y = 1.0f; | ||
private static final float EXIT_ICON_TARGET_SCALE_X = 1.2f; | ||
private static final float EXIT_ICON_TARGET_SCALE_Y = 1.2f; | ||
private static final float EXIT_ICON_DEFAULT_ROTATION = 0f; | ||
private static final float EXIT_ICON_TARGET_ROTATION = 90f; | ||
private static final float EXIT_ICON_DEFAULT_ALPHA = 0.6f; | ||
private static final float EXIT_ICON_TARGET_ALPHA = 0.75f; | ||
private static final float EXIT_VIEW_DEFAULT_ALPHA = 0f; | ||
private static final float EXIT_VIEW_TARGET_ALPHA = 1.0f; | ||
private static final float EXIT_VIEW_DEFAULT_Y = 800f; | ||
private static final float EXIT_VIEW_TARGET_Y = 0f; | ||
|
||
private int mExitRadiusInPx; | ||
private View mExitIcon; | ||
private View mExitGradient; | ||
private ViewGroup mVgExit; | ||
private ObjectAnimator mShowEnterAnimation = null; | ||
private ObjectAnimator mShowExitAnimation = null; | ||
private boolean mIsShowing = false; | ||
|
||
public ExitView(@NonNull Context context) { | ||
this(context, null); | ||
|
@@ -48,15 +74,89 @@ private void init() { | |
LayoutInflater.from(getContext()).inflate(R.layout.view_hover_menu_exit, this, true); | ||
|
||
mExitIcon = findViewById(R.id.view_exit); | ||
|
||
mVgExit = findViewById(R.id.vg_exit); | ||
mExitGradient = findViewById(R.id.view_exit_gradient); | ||
mExitRadiusInPx = getResources().getDimensionPixelSize(R.dimen.hover_exit_radius); | ||
mExitIcon.setAlpha(EXIT_ICON_DEFAULT_ALPHA); | ||
|
||
setAnimations(); | ||
} | ||
|
||
private Interpolator getExitViewInterpolator() { | ||
return PathInterpolatorCompat.create(0.75f, 0f, 0.25f, 1f); | ||
} | ||
|
||
public boolean isInExitZone(@NonNull Point position) { | ||
Point exitCenter = getExitZoneCenter(); | ||
double distanceToExit = calculateDistance(position, exitCenter); | ||
Log.d(TAG, "Drop point: " + position + ", Exit center: " + exitCenter + ", Distance: " + distanceToExit); | ||
return distanceToExit <= mExitRadiusInPx; | ||
private void setAnimations() { | ||
PropertyValuesHolder showEnterAnimationScaleX = PropertyValuesHolder.ofFloat("scaleX", EXIT_ICON_DEFAULT_SCALE_X, EXIT_ICON_TARGET_SCALE_X); | ||
PropertyValuesHolder showEnterAnimationScaleY = PropertyValuesHolder.ofFloat("scaleY", EXIT_ICON_DEFAULT_SCALE_Y, EXIT_ICON_TARGET_SCALE_Y); | ||
PropertyValuesHolder showEnterAnimationRotate = PropertyValuesHolder.ofFloat("rotation", EXIT_ICON_DEFAULT_ROTATION, EXIT_ICON_TARGET_ROTATION); | ||
PropertyValuesHolder showEnterAnimationAlpha = PropertyValuesHolder.ofFloat("alpha", EXIT_ICON_DEFAULT_ALPHA, EXIT_ICON_TARGET_ALPHA); | ||
mShowEnterAnimation = ObjectAnimator.ofPropertyValuesHolder(mExitIcon, showEnterAnimationScaleX, showEnterAnimationScaleY, showEnterAnimationRotate, showEnterAnimationAlpha); | ||
mShowEnterAnimation.setDuration(SHOW_HIDE_DURATION); | ||
mShowEnterAnimation.setInterpolator(getExitViewInterpolator()); | ||
mShowEnterAnimation.addListener(new Animator.AnimatorListener() { | ||
@Override | ||
public void onAnimationStart(Animator animator) { | ||
initExitIconViewStatus(); | ||
} | ||
|
||
@Override | ||
public void onAnimationEnd(Animator animator) { | ||
} | ||
|
||
@Override | ||
public void onAnimationCancel(Animator animator) { | ||
initExitIconViewStatus(); | ||
} | ||
|
||
@Override | ||
public void onAnimationRepeat(Animator animator) { | ||
} | ||
}); | ||
|
||
PropertyValuesHolder showExitAnimationScaleX = PropertyValuesHolder.ofFloat("scaleX", EXIT_ICON_TARGET_SCALE_X, EXIT_ICON_DEFAULT_SCALE_X); | ||
PropertyValuesHolder showExitAnimationScaleY = PropertyValuesHolder.ofFloat("scaleY", EXIT_ICON_TARGET_SCALE_Y, EXIT_ICON_DEFAULT_SCALE_Y); | ||
PropertyValuesHolder showExitAnimationRotate = PropertyValuesHolder.ofFloat("rotation", EXIT_ICON_TARGET_ROTATION, EXIT_ICON_DEFAULT_ROTATION); | ||
PropertyValuesHolder showExitAnimationAlpha = PropertyValuesHolder.ofFloat("alpha", EXIT_ICON_TARGET_ALPHA, EXIT_ICON_DEFAULT_ALPHA); | ||
mShowExitAnimation = ObjectAnimator.ofPropertyValuesHolder(mExitIcon, showExitAnimationScaleX, showExitAnimationScaleY, showExitAnimationRotate, showExitAnimationAlpha); | ||
mShowExitAnimation.setDuration(SHOW_HIDE_DURATION); | ||
mShowExitAnimation.setInterpolator(getExitViewInterpolator()); | ||
} | ||
|
||
private void initExitIconViewStatus() { | ||
mExitIcon.setScaleY(EXIT_ICON_DEFAULT_SCALE_Y); | ||
mExitIcon.setScaleX(EXIT_ICON_DEFAULT_SCALE_X); | ||
mExitIcon.setRotation(EXIT_ICON_DEFAULT_ROTATION); | ||
} | ||
|
||
public boolean isInExitZone(@NonNull Point position, @NonNull Point screenSize) { | ||
int exitXExcludeThresholdLeft = screenSize.x / 10; | ||
int exitXExcludeThresholdRight = screenSize.x * 9 / 10; | ||
|
||
Rect exitArea = new Rect( | ||
0 - mExitIcon.getWidth(), | ||
screenSize.y * 4 / 6, | ||
screenSize.x + mExitIcon.getWidth(), | ||
screenSize.y + mExitIcon.getHeight() | ||
); | ||
|
||
Rect excludedXExitAreaLeft = new Rect( | ||
0 - mExitIcon.getWidth(), | ||
screenSize.y * 4 / 6, | ||
exitXExcludeThresholdLeft, | ||
screenSize.y - mExitIcon.getHeight() / 2 | ||
); | ||
|
||
Rect excludedXExitAreaRight = new Rect( | ||
exitXExcludeThresholdRight, | ||
screenSize.y * 4 / 6, | ||
screenSize.x + mExitIcon.getWidth(), | ||
screenSize.y - mExitIcon.getHeight() / 2 | ||
); | ||
|
||
return exitArea.contains(position.x, position.y) | ||
&& !excludedXExitAreaLeft.contains(position.x, position.y) | ||
&& !excludedXExitAreaRight.contains(position.x, position.y); | ||
} | ||
|
||
private Point getExitZoneCenter() { | ||
|
@@ -71,4 +171,70 @@ private double calculateDistance(@NonNull Point p1, @NonNull Point p2) { | |
Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 method도 위치가 옮겨져서 사용을 안하는 것 같네요 |
||
); | ||
} | ||
|
||
public void showEnterAnimation() { | ||
if (mShowEnterAnimation != null && !mShowEnterAnimation.isRunning() && !mIsShowing) { | ||
mShowEnterAnimation.start(); | ||
mIsShowing = true; | ||
} | ||
} | ||
|
||
public void showExitAnimation() { | ||
if (mShowExitAnimation != null && !mShowExitAnimation.isRunning() && mIsShowing) { | ||
mShowExitAnimation.start(); | ||
mIsShowing = false; | ||
} | ||
} | ||
|
||
public void show() { | ||
resetExitButtonAnimation(); | ||
|
||
ObjectAnimator exitGradientAnimator = ObjectAnimator.ofFloat(mExitGradient, "alpha", EXIT_VIEW_TARGET_ALPHA); | ||
exitGradientAnimator.setDuration(FADE_DURATION); | ||
exitGradientAnimator.setInterpolator(getExitViewInterpolator()); | ||
exitGradientAnimator.start(); | ||
|
||
ObjectAnimator vgExitAnimator = ObjectAnimator.ofFloat(mVgExit, "y", EXIT_VIEW_DEFAULT_Y, EXIT_VIEW_TARGET_Y); | ||
vgExitAnimator.setDuration(FADE_DURATION); | ||
vgExitAnimator.setInterpolator(getExitViewInterpolator()); | ||
vgExitAnimator.start(); | ||
|
||
setVisibility(VISIBLE); | ||
} | ||
|
||
public void resetExitButtonAnimation() { | ||
mIsShowing = false; | ||
initExitIconViewStatus(); | ||
} | ||
|
||
public void hide() { | ||
ObjectAnimator vgExitAnimator = ObjectAnimator.ofFloat(mVgExit, "y", EXIT_VIEW_TARGET_Y, EXIT_VIEW_DEFAULT_Y); | ||
vgExitAnimator.setDuration(FADE_DURATION); | ||
vgExitAnimator.setInterpolator(getExitViewInterpolator()); | ||
vgExitAnimator.start(); | ||
|
||
ObjectAnimator exitGradientAnimator = ObjectAnimator.ofFloat(mExitGradient, "alpha", EXIT_VIEW_DEFAULT_ALPHA); | ||
exitGradientAnimator.setDuration(FADE_DURATION); | ||
exitGradientAnimator.setInterpolator(getExitViewInterpolator()); | ||
exitGradientAnimator.start(); | ||
|
||
exitGradientAnimator.addListener(new Animator.AnimatorListener() { | ||
@Override | ||
public void onAnimationStart(Animator animation) { | ||
} | ||
|
||
@Override | ||
public void onAnimationEnd(Animator animation) { | ||
setVisibility(GONE); | ||
} | ||
|
||
@Override | ||
public void onAnimationCancel(Animator animation) { | ||
} | ||
|
||
@Override | ||
public void onAnimationRepeat(Animator animation) { | ||
} | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isInExitZone method가 생기면서 사용을 안하는 것 같은데 없애도 되지 않을까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
제거했습니다