Use my own reveal stuff
This commit is contained in:
1 parent
e6367055fb
commit
19ebd4c28f
10 files changed
+229
-774
No files matched your search
@@ -38,6 +38,7 @@ import android.widget.EditText;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.hippo.reveal.ViewAnimationUtils;
|
||||
import com.hippo.easyrecyclerview.EasyRecyclerView;
|
||||
import com.hippo.easyrecyclerview.LinearDividerItemDecoration;
|
||||
import com.hippo.ehviewer.EhApplication;
|
||||
@@ -63,9 +64,6 @@ import com.hippo.yorozuya.LayoutUtils;
|
||||
import com.hippo.yorozuya.SimpleAnimatorListener;
|
||||
import com.hippo.yorozuya.ViewUtils;
|
||||
|
||||
import io.codetail.animation.SupportAnimator;
|
||||
import io.codetail.animation.ViewAnimationUtils;
|
||||
|
||||
public final class GalleryCommentsScene extends ToolbarScene
|
||||
implements EasyRecyclerView.OnItemClickListener,
|
||||
EasyRecyclerView.OnItemLongClickListener, View.OnClickListener {
|
||||
@@ -276,12 +274,11 @@ public final class GalleryCommentsScene extends ToolbarScene
|
||||
mEditPanel.setVisibility(View.VISIBLE);
|
||||
int halfW = mEditPanel.getWidth() / 2;
|
||||
int halfH = mEditPanel.getHeight() / 2;
|
||||
SupportAnimator animator = ViewAnimationUtils.createCircularReveal(mEditPanel, halfW, halfH, 0,
|
||||
(float) Math.hypot(halfW, halfH));
|
||||
animator.setDuration(300L);
|
||||
animator.addListener(new SupportAnimator.SimpleAnimatorListener() {
|
||||
Animator animator = ViewAnimationUtils.createCircularReveal(mEditPanel, halfW, halfH, 0,
|
||||
(float) Math.hypot(halfW, halfH)).setDuration(300L);
|
||||
animator.addListener(new SimpleAnimatorListener() {
|
||||
@Override
|
||||
public void onAnimationEnd() {
|
||||
public void onAnimationEnd(Animator a) {
|
||||
mInAnimation = false;
|
||||
}
|
||||
});
|
||||
@@ -311,12 +308,11 @@ public final class GalleryCommentsScene extends ToolbarScene
|
||||
mInAnimation = true;
|
||||
int halfW = mEditPanel.getWidth() / 2;
|
||||
int halfH = mEditPanel.getHeight() / 2;
|
||||
SupportAnimator animator = ViewAnimationUtils.createCircularReveal(mEditPanel, halfW, halfH,
|
||||
(float) Math.hypot(halfW, halfH), 0.0f);
|
||||
animator.setDuration(300L);
|
||||
animator.addListener(new SupportAnimator.SimpleAnimatorListener() {
|
||||
Animator animator = ViewAnimationUtils.createCircularReveal(mEditPanel, halfW, halfH,
|
||||
(float) Math.hypot(halfW, halfH), 0.0f).setDuration(300L);
|
||||
animator.addListener(new SimpleAnimatorListener() {
|
||||
@Override
|
||||
public void onAnimationEnd() {
|
||||
public void onAnimationEnd(Animator a) {
|
||||
mEditPanel.setVisibility(View.GONE);
|
||||
mFab.setVisibility(View.VISIBLE);
|
||||
int fabStartX = mEditPanel.getLeft() + (mEditPanel.getWidth() / 2) - (mFab.getWidth() / 2);
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.reveal;
|
||||
|
||||
public interface Reveal {
|
||||
|
||||
void setRevealEnable(boolean enable);
|
||||
|
||||
void setReveal(int centerX, int centerY, float radius);
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.reveal;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Path;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
public class RevealLinearLayout extends LinearLayout implements Reveal {
|
||||
|
||||
private final Path mRevealPath = new Path();
|
||||
private boolean mReveal;
|
||||
private int mCenterX;
|
||||
private int mCenterY;
|
||||
private float mRadius;
|
||||
|
||||
public RevealLinearLayout(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public RevealLinearLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public RevealLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
if (!ViewAnimationUtils.API_SUPPORT_CIRCULAR_REVEAL) {
|
||||
setWillNotDraw(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRevealEnable(boolean enable) {
|
||||
mReveal = enable;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReveal(int centerX, int centerY, float radius) {
|
||||
mCenterX = centerX;
|
||||
mCenterY = centerY;
|
||||
mRadius = radius;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas) {
|
||||
boolean reveal = mReveal;
|
||||
int saveCount = 0;
|
||||
|
||||
if (reveal) {
|
||||
saveCount = canvas.save();
|
||||
Path path = mRevealPath;
|
||||
path.reset();
|
||||
path.addCircle(mCenterX, mCenterY, mRadius, Path.Direction.CW);
|
||||
canvas.clipPath(path);
|
||||
}
|
||||
|
||||
super.draw(canvas);
|
||||
|
||||
if (reveal) {
|
||||
canvas.restoreToCount(saveCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.reveal;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.annotation.TargetApi;
|
||||
import android.os.Build;
|
||||
import android.view.View;
|
||||
|
||||
import com.hippo.yorozuya.SimpleAnimatorListener;
|
||||
|
||||
public final class ViewAnimationUtils {
|
||||
private ViewAnimationUtils() {}
|
||||
|
||||
public static final boolean API_SUPPORT_CIRCULAR_REVEAL =
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
|
||||
// http://developer.android.com/guide/topics/graphics/hardware-accel.html#unsupported
|
||||
public static final boolean API_SUPPORT_CANVAS_CLIP_PATH =
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2;
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
public static Animator createCircularReveal(View view,
|
||||
int centerX, int centerY, float startRadius, float endRadius) {
|
||||
if (API_SUPPORT_CIRCULAR_REVEAL) {
|
||||
return android.view.ViewAnimationUtils.createCircularReveal(
|
||||
view, centerX, centerY, startRadius, endRadius);
|
||||
} else if (view instanceof Reveal){
|
||||
return createRevealAnimator((Reveal) view, centerX, centerY,
|
||||
startRadius, endRadius);
|
||||
} else {
|
||||
throw new IllegalStateException("Only View implements CircularReveal or" +
|
||||
" api >= 21 can create circular reveal");
|
||||
}
|
||||
}
|
||||
|
||||
private static Animator createRevealAnimator(Reveal reveal, int centerX, int centerY,
|
||||
float startRadius, float endRadius) {
|
||||
ValueAnimator animator = ValueAnimator.ofFloat(startRadius, endRadius);
|
||||
animator.addUpdateListener(new RevealAnimatorUpdateListener(reveal, centerX, centerY));
|
||||
animator.addListener(new RevealAnimatorListener(reveal));
|
||||
return animator;
|
||||
}
|
||||
|
||||
private static class RevealAnimatorUpdateListener
|
||||
implements ValueAnimator.AnimatorUpdateListener {
|
||||
|
||||
private final Reveal mReveal;
|
||||
private final int mCenterX;
|
||||
private final int mCenterY;
|
||||
|
||||
public RevealAnimatorUpdateListener(Reveal reveal, int centerX, int centerY) {
|
||||
mReveal = reveal;
|
||||
mCenterX = centerX;
|
||||
mCenterY = centerY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
Object value = animation.getAnimatedValue();
|
||||
if (value instanceof Float) {
|
||||
mReveal.setReveal(mCenterX, mCenterY, (Float) value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class RevealAnimatorListener extends SimpleAnimatorListener {
|
||||
|
||||
private final Reveal mReveal;
|
||||
private final View mView;
|
||||
|
||||
public RevealAnimatorListener(Reveal reveal) {
|
||||
mReveal = reveal;
|
||||
mView = (View) reveal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
if (!API_SUPPORT_CANVAS_CLIP_PATH) {
|
||||
mView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
|
||||
}
|
||||
mReveal.setRevealEnable(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
mReveal.setRevealEnable(false);
|
||||
if (!API_SUPPORT_CANVAS_CLIP_PATH) {
|
||||
mView.setLayerType(View.LAYER_TYPE_NONE, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,147 +0,0 @@
|
||||
package io.codetail.animation;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.graphics.Rect;
|
||||
import android.util.Property;
|
||||
import android.view.View;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public interface RevealAnimator{
|
||||
|
||||
RevealRadius CLIP_RADIUS = new RevealRadius();
|
||||
|
||||
/**
|
||||
* Listen when animation start/end/cancel
|
||||
* and setup view for it
|
||||
*/
|
||||
void onRevealAnimationStart();
|
||||
void onRevealAnimationEnd();
|
||||
void onRevealAnimationCancel();
|
||||
|
||||
/**
|
||||
* Used with animator to animate view clipping
|
||||
*
|
||||
* @param value clip radius
|
||||
*/
|
||||
void setRevealRadius(float value);
|
||||
|
||||
/**
|
||||
* Used with animator to animate view clipping
|
||||
*
|
||||
* @return current radius
|
||||
*/
|
||||
float getRevealRadius();
|
||||
|
||||
/**
|
||||
* Invalidate certain rectangle
|
||||
*
|
||||
* @param bounds bounds to redraw
|
||||
* @see View#invalidate(Rect)
|
||||
*/
|
||||
void invalidate(Rect bounds);
|
||||
|
||||
/**
|
||||
* {@link ViewAnimationUtils#createCircularReveal(View, int, int, float, float)} is
|
||||
* called it creates new {@link io.codetail.animation.RevealAnimator.RevealInfo}
|
||||
* and attaches to parent, here is necessary data about animation
|
||||
*
|
||||
* @param info reveal information
|
||||
*
|
||||
* @see RevealAnimator.RevealInfo
|
||||
*/
|
||||
void attachRevealInfo(RevealInfo info);
|
||||
|
||||
/**
|
||||
* Returns new {@link SupportAnimator} that plays
|
||||
* reversed animation of current one
|
||||
*
|
||||
* This method might be temporary, you should call
|
||||
* {@link SupportAnimator#reverse()} instead
|
||||
*
|
||||
* @hide
|
||||
* @return reverse {@link SupportAnimator}
|
||||
*
|
||||
* @see SupportAnimator#reverse()
|
||||
*/
|
||||
SupportAnimator startReverseAnimation();
|
||||
|
||||
class RevealInfo{
|
||||
public final int centerX;
|
||||
public final int centerY;
|
||||
public final float startRadius;
|
||||
public final float endRadius;
|
||||
public final WeakReference<View> target;
|
||||
|
||||
public RevealInfo(int centerX, int centerY, float startRadius, float endRadius,
|
||||
WeakReference<View> target) {
|
||||
this.centerX = centerX;
|
||||
this.centerY = centerY;
|
||||
this.startRadius = startRadius;
|
||||
this.endRadius = endRadius;
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
public View getTarget(){
|
||||
return target.get();
|
||||
}
|
||||
|
||||
public boolean hasTarget(){
|
||||
return getTarget() != null;
|
||||
}
|
||||
}
|
||||
|
||||
class RevealFinishedIceCreamSandwich extends AnimatorListenerAdapter {
|
||||
WeakReference<RevealAnimator> mReference;
|
||||
int mFeaturedLayerType;
|
||||
int mLayerType;
|
||||
|
||||
RevealFinishedIceCreamSandwich(RevealAnimator target, int layerType) {
|
||||
mReference = new WeakReference<>(target);
|
||||
mLayerType = ((View) target).getLayerType();
|
||||
mFeaturedLayerType = layerType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
RevealAnimator target = mReference.get();
|
||||
((View) target).setLayerType(mFeaturedLayerType, null);
|
||||
target.onRevealAnimationStart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
RevealAnimator target = mReference.get();
|
||||
((View) target).setLayerType(mLayerType, null);
|
||||
target.onRevealAnimationCancel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
RevealAnimator target = mReference.get();
|
||||
((View) target).setLayerType(mLayerType, null);
|
||||
target.onRevealAnimationEnd();
|
||||
}
|
||||
}
|
||||
|
||||
class RevealRadius extends Property<RevealAnimator, Float> {
|
||||
|
||||
public RevealRadius() {
|
||||
super(Float.class, "revealRadius");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(RevealAnimator object, Float value) {
|
||||
object.setRevealRadius(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(RevealAnimator object) {
|
||||
return object.getRevealRadius();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,186 +0,0 @@
|
||||
package io.codetail.animation;
|
||||
|
||||
import android.animation.Animator;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
public abstract class SupportAnimator extends Animator{
|
||||
|
||||
WeakReference<RevealAnimator> mTarget;
|
||||
|
||||
public SupportAnimator(RevealAnimator target) {
|
||||
mTarget = new WeakReference<>(target);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if using native android animation framework, otherwise is
|
||||
* nineoldandroids
|
||||
*/
|
||||
public abstract boolean isNativeAnimator();
|
||||
|
||||
/**
|
||||
* @return depends from {@link android.os.Build.VERSION} if sdk version
|
||||
* {@link android.os.Build.VERSION_CODES#LOLLIPOP} and greater will return
|
||||
* {@link android.animation.Animator}
|
||||
*/
|
||||
public abstract Object get();
|
||||
|
||||
/**
|
||||
* Starts this animation. If the animation has a nonzero startDelay, the animation will start
|
||||
* running after that delay elapses. A non-delayed animation will have its initial
|
||||
* value(s) set immediately, followed by calls to
|
||||
* {@link android.animation.Animator.AnimatorListener#onAnimationStart(android.animation.Animator)}
|
||||
* for any listeners of this animator.
|
||||
*
|
||||
* <p>The animation started by calling this method will be run on the thread that called
|
||||
* this method. This thread should have a Looper on it (a runtime exception will be thrown if
|
||||
* this is not the case). Also, if the animation will animate
|
||||
* properties of objects in the view hierarchy, then the calling thread should be the UI
|
||||
* thread for that view hierarchy.</p>
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public abstract void start();
|
||||
|
||||
|
||||
/**
|
||||
* Adds a listener to the set of listeners that are sent events through the life of an
|
||||
* animation, such as start, repeat, and end.
|
||||
*
|
||||
* @param listener the listener to be added to the current set of listeners for this animation.
|
||||
*/
|
||||
public abstract void addListener(AnimatorListener listener);
|
||||
|
||||
|
||||
/**
|
||||
* Returns whether this Animator is currently running (having been started and gone past any
|
||||
* initial startDelay period and not yet ended).
|
||||
*
|
||||
* @return Whether the Animator is running.
|
||||
*/
|
||||
@Override
|
||||
public abstract boolean isRunning();
|
||||
|
||||
|
||||
/**
|
||||
* Cancels the animation. Unlike {@link #end()}, <code>cancel()</code> causes the animation to
|
||||
* stop in its tracks, sending an
|
||||
* {@link AnimatorListener#onAnimationCancel()} to
|
||||
* its listeners, followed by an
|
||||
* {@link AnimatorListener#onAnimationEnd()} message.
|
||||
*
|
||||
* <p>This method must be called on the thread that is running the animation.</p>
|
||||
*/
|
||||
@Override
|
||||
public abstract void cancel();
|
||||
|
||||
/**
|
||||
* Ends the animation. This causes the animation to assign the end value of the property being
|
||||
* animated, then calling the
|
||||
* {@link AnimatorListener#onAnimationEnd()} method on
|
||||
* its listeners.
|
||||
*
|
||||
* <p>This method must be called on the thread that is running the animation.</p>
|
||||
*/
|
||||
@Override
|
||||
public void end() {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method tells the object to use appropriate information to extract
|
||||
* starting values for the animation. For example, a AnimatorSet object will pass
|
||||
* this call to its child objects to tell them to set up the values. A
|
||||
* ObjectAnimator object will use the information it has about its target object
|
||||
* and PropertyValuesHolder objects to get the start values for its properties.
|
||||
* A ValueAnimator object will ignore the request since it does not have enough
|
||||
* information (such as a target object) to gather these values.
|
||||
*/
|
||||
@Override
|
||||
public void setupStartValues() {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method tells the object to use appropriate information to extract
|
||||
* ending values for the animation. For example, a AnimatorSet object will pass
|
||||
* this call to its child objects to tell them to set up the values. A
|
||||
* ObjectAnimator object will use the information it has about its target object
|
||||
* and PropertyValuesHolder objects to get the start values for its properties.
|
||||
* A ValueAnimator object will ignore the request since it does not have enough
|
||||
* information (such as a target object) to gather these values.
|
||||
*/
|
||||
@Override
|
||||
public void setupEndValues() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Experimental feature
|
||||
*/
|
||||
public SupportAnimator reverse() {
|
||||
if(isRunning()){
|
||||
return null;
|
||||
}
|
||||
|
||||
RevealAnimator target = mTarget.get();
|
||||
if(target != null){
|
||||
return target.startReverseAnimation();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>An animation listener receives notifications from an animation.
|
||||
* Notifications indicate animation related events, such as the end or the
|
||||
* repetition of the animation.</p>
|
||||
*/
|
||||
public interface AnimatorListener {
|
||||
/**
|
||||
* <p>Notifies the start of the animation.</p>
|
||||
*/
|
||||
void onAnimationStart();
|
||||
|
||||
/**
|
||||
* <p>Notifies the end of the animation. This callback is not invoked
|
||||
* for animations with repeat count set to INFINITE.</p>
|
||||
*/
|
||||
void onAnimationEnd();
|
||||
|
||||
/**
|
||||
* <p>Notifies the cancellation of the animation. This callback is not invoked
|
||||
* for animations with repeat count set to INFINITE.</p>
|
||||
*/
|
||||
void onAnimationCancel();
|
||||
|
||||
/**
|
||||
* <p>Notifies the repetition of the animation.</p>
|
||||
*/
|
||||
void onAnimationRepeat();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Provides default implementation for AnimatorListener.</p>
|
||||
*/
|
||||
public static abstract class SimpleAnimatorListener implements AnimatorListener {
|
||||
|
||||
@Override
|
||||
public void onAnimationStart() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,154 +0,0 @@
|
||||
package io.codetail.animation;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.TimeInterpolator;
|
||||
import android.annotation.TargetApi;
|
||||
import android.os.Build;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||
final class SupportAnimatorImpl extends SupportAnimator{
|
||||
|
||||
WeakReference<Animator> mAnimator;
|
||||
|
||||
SupportAnimatorImpl(Animator animator, RevealAnimator target) {
|
||||
super(target);
|
||||
mAnimator = new WeakReference<>(animator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNativeAnimator() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get() {
|
||||
return mAnimator.get();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
Animator a = mAnimator.get();
|
||||
if(a != null) {
|
||||
a.start();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Animator setDuration(long duration) {
|
||||
Animator a = mAnimator.get();
|
||||
if(a != null) {
|
||||
a.setDuration(duration);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInterpolator(TimeInterpolator value) {
|
||||
Animator a = mAnimator.get();
|
||||
if(a != null) {
|
||||
a.setInterpolator(value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(final AnimatorListener listener) {
|
||||
Animator a = mAnimator.get();
|
||||
if(a == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(listener == null){
|
||||
a.addListener(null);
|
||||
return;
|
||||
}
|
||||
|
||||
a.addListener(new Animator.AnimatorListener() {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
listener.onAnimationStart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
listener.onAnimationEnd();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
listener.onAnimationCancel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(Animator animation) {
|
||||
listener.onAnimationRepeat();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
Animator a = mAnimator.get();
|
||||
return a != null && a.isRunning();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
Animator a = mAnimator.get();
|
||||
if(a != null){
|
||||
a.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void end() {
|
||||
Animator a = mAnimator.get();
|
||||
if(a != null){
|
||||
a.end();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getStartDelay() {
|
||||
Animator a = mAnimator.get();
|
||||
if(a != null){
|
||||
return a.getStartDelay();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStartDelay(long startDelay) {
|
||||
Animator a = mAnimator.get();
|
||||
if(a != null){
|
||||
a.setStartDelay(startDelay);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getDuration() {
|
||||
Animator a = mAnimator.get();
|
||||
if(a != null){
|
||||
return a.getDuration();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupStartValues() {
|
||||
Animator a = mAnimator.get();
|
||||
if(a != null){
|
||||
a.setupStartValues();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupEndValues() {
|
||||
Animator a = mAnimator.get();
|
||||
if(a != null){
|
||||
a.setupEndValues();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,157 +0,0 @@
|
||||
package io.codetail.animation;
|
||||
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.annotation.TargetApi;
|
||||
import android.os.Build;
|
||||
import android.view.View;
|
||||
import android.view.animation.AccelerateDecelerateInterpolator;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import io.codetail.animation.RevealAnimator.RevealInfo;
|
||||
|
||||
import static android.os.Build.VERSION.SDK_INT;
|
||||
import static android.os.Build.VERSION_CODES.LOLLIPOP;
|
||||
import static io.codetail.animation.RevealAnimator.CLIP_RADIUS;
|
||||
|
||||
public class ViewAnimationUtils {
|
||||
|
||||
private final static boolean LOLLIPOP_PLUS = SDK_INT >= LOLLIPOP;
|
||||
|
||||
public static final int SCALE_UP_DURATION = 500;
|
||||
|
||||
/**
|
||||
* Returns an Animator which can animate a clipping circle.
|
||||
* <p>
|
||||
* Any shadow cast by the View will respect the circular clip from this animator.
|
||||
* <p>
|
||||
* Only a single non-rectangular clip can be applied on a View at any time.
|
||||
* Views clipped by a circular reveal animation take priority over
|
||||
* {@link android.view.View#setClipToOutline(boolean) View Outline clipping}.
|
||||
* <p>
|
||||
* Note that the animation returned here is a one-shot animation. It cannot
|
||||
* be re-used, and once started it cannot be paused or resumed.
|
||||
*
|
||||
* @param view The View will be clipped to the animating circle.
|
||||
* @param centerX The x coordinate of the center of the animating circle.
|
||||
* @param centerY The y coordinate of the center of the animating circle.
|
||||
* @param startRadius The starting radius of the animating circle.
|
||||
* @param endRadius The ending radius of the animating circle.
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
public static SupportAnimator createCircularReveal(View view,
|
||||
int centerX, int centerY,
|
||||
float startRadius, float endRadius) {
|
||||
|
||||
return createCircularReveal(view, centerX, centerY, startRadius, endRadius, View.LAYER_TYPE_SOFTWARE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an Animator which can animate a clipping circle.
|
||||
* <p>
|
||||
* Any shadow cast by the View will respect the circular clip from this animator.
|
||||
* <p>
|
||||
* Only a single non-rectangular clip can be applied on a View at any time.
|
||||
* Views clipped by a circular reveal animation take priority over
|
||||
* {@link android.view.View#setClipToOutline(boolean) View Outline clipping}.
|
||||
* <p>
|
||||
* Note that the animation returned here is a one-shot animation. It cannot
|
||||
* be re-used, and once started it cannot be paused or resumed.
|
||||
*
|
||||
* @param view The View will be clipped to the animating circle.
|
||||
* @param centerX The x coordinate of the center of the animating circle.
|
||||
* @param centerY The y coordinate of the center of the animating circle.
|
||||
* @param startRadius The starting radius of the animating circle.
|
||||
* @param endRadius The ending radius of the animating circle.
|
||||
*
|
||||
* @param layerType View layer type {@link View#LAYER_TYPE_HARDWARE} or {@link View#LAYER_TYPE_SOFTWARE}
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
public static SupportAnimator createCircularReveal(View view,
|
||||
int centerX, int centerY,
|
||||
float startRadius, float endRadius, int layerType) {
|
||||
|
||||
if(!(view instanceof RevealAnimator)){
|
||||
throw new IllegalArgumentException("View must be inside RevealFrameLayout or RevealLinearLayout.");
|
||||
}
|
||||
|
||||
RevealAnimator revealLayout = (RevealAnimator) view;
|
||||
revealLayout.attachRevealInfo(new RevealInfo(centerX, centerY, startRadius, endRadius,
|
||||
new WeakReference<>(view)));
|
||||
|
||||
if(LOLLIPOP_PLUS){
|
||||
return new SupportAnimatorImpl(android.view.ViewAnimationUtils
|
||||
.createCircularReveal(view, centerX, centerY, startRadius, endRadius), revealLayout);
|
||||
}
|
||||
|
||||
ObjectAnimator reveal = ObjectAnimator.ofFloat(revealLayout, CLIP_RADIUS, startRadius, endRadius);
|
||||
reveal.addListener(new RevealAnimator.RevealFinishedIceCreamSandwich(revealLayout, layerType));
|
||||
return new SupportAnimatorImpl(reveal, revealLayout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lifting view
|
||||
*
|
||||
* @param view The animation target
|
||||
* @param baseRotation initial Rotation X in 3D space
|
||||
* @param fromY initial Y position of view
|
||||
* @param duration aniamtion duration
|
||||
* @param startDelay start delay before animation begin
|
||||
*/
|
||||
@Deprecated
|
||||
public static void liftingFromBottom(View view, float baseRotation, float fromY, int duration, int startDelay){
|
||||
view.setRotationX(baseRotation);
|
||||
view.setTranslationY(fromY);
|
||||
|
||||
view.animate()
|
||||
.setInterpolator(new AccelerateDecelerateInterpolator())
|
||||
.setDuration(duration)
|
||||
.setStartDelay(startDelay)
|
||||
.rotationX(0)
|
||||
.translationY(0)
|
||||
.start();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Lifting view
|
||||
*
|
||||
* @param view The animation target
|
||||
* @param baseRotation initial Rotation X in 3D space
|
||||
* @param duration aniamtion duration
|
||||
* @param startDelay start delay before animation begin
|
||||
*/
|
||||
@Deprecated
|
||||
public static void liftingFromBottom(View view, float baseRotation, int duration, int startDelay){
|
||||
view.setRotationX(baseRotation);
|
||||
view.setTranslationY(view.getHeight() / 3);
|
||||
|
||||
view.animate().setInterpolator(new AccelerateDecelerateInterpolator())
|
||||
.setDuration(duration)
|
||||
.setStartDelay(startDelay)
|
||||
.rotationX(0)
|
||||
.translationY(0)
|
||||
.start();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Lifting view
|
||||
*
|
||||
* @param view The animation target
|
||||
* @param baseRotation initial Rotation X in 3D space
|
||||
* @param duration aniamtion duration
|
||||
*/
|
||||
@Deprecated
|
||||
public static void liftingFromBottom(View view, float baseRotation, int duration){
|
||||
view.setRotationX(baseRotation);
|
||||
view.setTranslationY(view.getHeight() / 3);
|
||||
|
||||
view.animate().setInterpolator(new AccelerateDecelerateInterpolator())
|
||||
.setDuration(duration)
|
||||
.rotationX(0)
|
||||
.translationY(0)
|
||||
.start();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
package io.codetail.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.Rect;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import io.codetail.animation.RevealAnimator;
|
||||
import io.codetail.animation.SupportAnimator;
|
||||
import io.codetail.animation.ViewAnimationUtils;
|
||||
|
||||
public class RevealLinearLayout extends LinearLayout implements RevealAnimator{
|
||||
|
||||
private final Path mRevealPath;
|
||||
private final Rect mTargetBounds = new Rect();
|
||||
private RevealInfo mRevealInfo;
|
||||
private boolean mRunning;
|
||||
private float mRadius;
|
||||
|
||||
public RevealLinearLayout(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public RevealLinearLayout(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public RevealLinearLayout(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs);
|
||||
mRevealPath = new Path();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRevealAnimationStart() {
|
||||
mRunning = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRevealAnimationEnd() {
|
||||
mRunning = false;
|
||||
invalidate(mTargetBounds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRevealAnimationCancel() {
|
||||
onRevealAnimationEnd();
|
||||
}
|
||||
|
||||
/**
|
||||
* Circle radius size
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public void setRevealRadius(float radius){
|
||||
mRadius = radius;
|
||||
mRevealInfo.getTarget().getHitRect(mTargetBounds);
|
||||
invalidate(mTargetBounds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Circle radius size
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public float getRevealRadius(){
|
||||
return mRadius;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public void attachRevealInfo(RevealInfo info) {
|
||||
mRevealInfo = info;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public SupportAnimator startReverseAnimation() {
|
||||
if(mRevealInfo != null && mRevealInfo.hasTarget() && !mRunning) {
|
||||
return ViewAnimationUtils.createCircularReveal(mRevealInfo.getTarget(),
|
||||
mRevealInfo.centerX, mRevealInfo.centerY,
|
||||
mRevealInfo.endRadius, mRevealInfo.startRadius);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
|
||||
if(mRunning && child == mRevealInfo.getTarget()){
|
||||
final int state = canvas.save();
|
||||
|
||||
mRevealPath.reset();
|
||||
mRevealPath.addCircle(mRevealInfo.centerX, mRevealInfo.centerY, mRadius, Path.Direction.CW);
|
||||
|
||||
canvas.clipPath(mRevealPath);
|
||||
|
||||
boolean isInvalided = super.drawChild(canvas, child, drawingTime);
|
||||
|
||||
canvas.restoreToCount(state);
|
||||
|
||||
return isInvalided;
|
||||
}
|
||||
|
||||
return super.drawChild(canvas, child, drawingTime);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user