Use my own reveal stuff

This commit is contained in:
seven332 committed 2016-03-27 18:13:35 +08:00
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);
}
}