From 1b0318655067c3a68350f71506c341e0f0cd434c Mon Sep 17 00:00:00 2001 From: Eudy Contreras Date: Wed, 6 Feb 2019 17:25:51 +0100 Subject: [PATCH] Updates and Apis --- .../rippleeffect/MainActivity.kt | 10 +- app/src/main/res/layout/activity_main.xml | 12 +- .../rippleeffectlib/Property.java | 28 ++++ .../rippleeffectlib/particles/Particle.java | 21 ++- .../particles/ParticleRipple.java | 2 +- .../rippleeffectlib/views/RippleView.java | 141 ++++++++++++++---- 6 files changed, 175 insertions(+), 39 deletions(-) create mode 100644 rippleeffectlib/src/main/java/com/eudycontreras/rippleeffectlib/Property.java diff --git a/app/src/main/java/com/eudycontreras/rippleeffect/MainActivity.kt b/app/src/main/java/com/eudycontreras/rippleeffect/MainActivity.kt index 3745857..f508d84 100644 --- a/app/src/main/java/com/eudycontreras/rippleeffect/MainActivity.kt +++ b/app/src/main/java/com/eudycontreras/rippleeffect/MainActivity.kt @@ -38,6 +38,7 @@ class MainActivity : AppCompatActivity() { ripple.rippleRepeats = RippleView.INFINITE_REPEATS ripple.rippleDuration = 2000 ripple.rippleStrokeWidth = 10f + ripple.offsetY = DimensionUtility.convertPixelsToDp(this,10f) } override fun onResume() { @@ -55,7 +56,7 @@ class MainActivity : AppCompatActivity() { Handler().postDelayed({ someElementContainer.animate() .setInterpolator(interpolatorOut) - .translationZ(DimensionUtility.convertDpToPixel(this,DimensionUtility.convertPixelsToDp(this,8f))) + .translationZ(DimensionUtility.convertDpToPixel(this, DimensionUtility.convertPixelsToDp(this,8f))) .scaleY(1f) .scaleX(1f) .setDuration(150L) @@ -63,8 +64,10 @@ class MainActivity : AppCompatActivity() { override fun onAnimationRepeat(p0: Animator?) { } override fun onAnimationEnd(p0: Animator?) { - ripple.setTarget(someElementContainer, 2.45f, 0.43f) - ripple.startRippleAnimation(1000) + if(!ripple.isAnimationRunning){ + ripple.setTarget(someElementContainer, 2.45f, 0.43f) + ripple.startRippleAnimation(1000) + } } override fun onAnimationCancel(p0: Animator?) {} @@ -116,6 +119,7 @@ class MainActivity : AppCompatActivity() { MotionEvent.ACTION_CANCEL -> { someElementContainer.animate() .setInterpolator(interpolatorOut) + .setListener(null) .translationZ(DimensionUtility.convertDpToPixel(this,8f)) .scaleY(1f) .scaleX(1f) diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 3d6b334..f12d80f 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -9,16 +9,26 @@ android:id="@+id/root" tools:context=".MainActivity"> + + + app:layout_constraintTop_toBottomOf="@id/spaceOne"> Note: Unlicensed private property of the author and creator + * unauthorized use of this class outside of the Ripple Effect project + * by the author may result on legal prosecution. + *

+ * Created by Eudy Contreras + * + * @author Eudy Contreras + * @version 1.0 + * @since 2018-03-31 + */ +public class Property { + private T value; + + public Property(T value) { + this.value = value; + } + + public T getValue() { + return value; + } + + public void setValue(T value) { + this.value = value; + } +} diff --git a/rippleeffectlib/src/main/java/com/eudycontreras/rippleeffectlib/particles/Particle.java b/rippleeffectlib/src/main/java/com/eudycontreras/rippleeffectlib/particles/Particle.java index 5032f49..908c761 100644 --- a/rippleeffectlib/src/main/java/com/eudycontreras/rippleeffectlib/particles/Particle.java +++ b/rippleeffectlib/src/main/java/com/eudycontreras/rippleeffectlib/particles/Particle.java @@ -47,6 +47,7 @@ public abstract class Particle { protected boolean fade = true; protected boolean shrink = true; protected boolean checkBounds = false; + protected boolean alwaysAlive = false; protected Bounds bounds; protected Paint paint; @@ -130,10 +131,14 @@ public float checkDistanceTo(Particle particle) { } public boolean isAlive() { - if(bounds != null) { - return (!checkBounds || bounds.inRange(centerX, centerY, (radius * 2))) && (lifeSpan > 0) && (radius > 0) && (opacity > 0); - } - return lifeSpan > 0; + if(alwaysAlive){ + return true; + }else{ + if(bounds != null) { + return (!checkBounds || bounds.inRange(centerX, centerY, (radius * 2))) && (lifeSpan > 0) && (radius > 0) && (opacity > 0); + } + return lifeSpan > 0; + } } public Paint getPaint() { @@ -313,6 +318,14 @@ public void setCheckBounds(boolean checkBounds) { this.checkBounds = checkBounds; } + public boolean isAlwaysAlive() { + return alwaysAlive; + } + + public void setAlwaysAlive(boolean alwaysAlive) { + this.alwaysAlive = alwaysAlive; + } + public void setSpacing(float spacing) { this.spacing = spacing; } diff --git a/rippleeffectlib/src/main/java/com/eudycontreras/rippleeffectlib/particles/ParticleRipple.java b/rippleeffectlib/src/main/java/com/eudycontreras/rippleeffectlib/particles/ParticleRipple.java index 7d30d69..03cae40 100644 --- a/rippleeffectlib/src/main/java/com/eudycontreras/rippleeffectlib/particles/ParticleRipple.java +++ b/rippleeffectlib/src/main/java/com/eudycontreras/rippleeffectlib/particles/ParticleRipple.java @@ -116,7 +116,7 @@ public void update(float duration, float time) { @Override public boolean isAlive() { - return opacity > 0f && (radius > 0 || width > 0 || height > 0); + return (opacity > 0f && (radius > 0 || width > 0 || height > 0)) || alwaysAlive; } public void draw(Canvas canvas){ diff --git a/rippleeffectlib/src/main/java/com/eudycontreras/rippleeffectlib/views/RippleView.java b/rippleeffectlib/src/main/java/com/eudycontreras/rippleeffectlib/views/RippleView.java index eae1c58..43813a6 100644 --- a/rippleeffectlib/src/main/java/com/eudycontreras/rippleeffectlib/views/RippleView.java +++ b/rippleeffectlib/src/main/java/com/eudycontreras/rippleeffectlib/views/RippleView.java @@ -12,13 +12,18 @@ import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; +import android.view.ViewParent; import android.view.animation.AccelerateDecelerateInterpolator; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; import android.view.animation.LinearInterpolator; +import android.widget.FrameLayout; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; import androidx.annotation.NonNull; import androidx.constraintlayout.widget.ConstraintLayout; import com.eudycontreras.rippleeffectlib.Bounds; +import com.eudycontreras.rippleeffectlib.Property; import com.eudycontreras.rippleeffectlib.R; import com.eudycontreras.rippleeffectlib.particles.ParticleRipple; import com.eudycontreras.rippleeffectlib.utilities.ColorUtility; @@ -75,6 +80,9 @@ public class RippleView extends View { private float centerX = Integer.MIN_VALUE; private float centerY = Integer.MIN_VALUE; + private float offsetX = 0f; + private float offsetY = 0f; + private float rippleMinWidth; private float rippleMinHeight; @@ -95,11 +103,11 @@ public class RippleView extends View { private long revealDuration = 300; private long concealDuration = 300; - private boolean useColorInterpolation; - private boolean showBorderStroke; - private boolean animationRunning; - private boolean autoStartRipple; - private boolean cleanUpAfter; + private boolean useColorInterpolation = false; + private boolean showBorderStroke = false; + private boolean animationRunning = false; + private boolean autoStartRipple = false; + private boolean cleanUpAfter = false; private ParticleRipple[] ripples; private ArrayList animators; @@ -109,6 +117,7 @@ public class RippleView extends View { private Runnable runLater; private ViewDrawListener listener; + private Handler handler; private AnimatorSet animatorSet; private ViewGroup parent; private Bounds bounds; @@ -176,6 +185,8 @@ private void initialize() { color = new ColorUtility.SoulColor(); + handler = new Handler(); + animatorSet = new AnimatorSet(); animators = new ArrayList<>(); } @@ -267,9 +278,12 @@ private void initializeRipple() { ripple.setColorStart(colorStart); ripple.setColorEnd(colorEnd); ripple.setType(rippleType); - ripple.setCenterX(centerX); - ripple.setCenterY(centerY); + ripple.setX(rippleX + offsetX); + ripple.setY(rippleY + offsetY); + ripple.setCenterX(centerX + offsetX); + ripple.setCenterY(centerY + offsetY); ripple.setVisible(true); + ripple.setAlwaysAlive(true); ripple.init(); ripples[i] = ripple; @@ -297,10 +311,10 @@ private void initializeRipple() { ripples[index].setMaxRadius(rippleMaxRadius); ripples[index].setClipRadius(rippleClipRadius); ripples[index].setStrokeWidth(rippleStrokeWidth); - ripples[index].setCenterX(centerX); - ripples[index].setCenterY(centerY); - ripples[index].setX(rippleX); - ripples[index].setY(rippleY); + ripples[index].setCenterX(centerX + offsetX); + ripples[index].setCenterY(centerY + offsetY); + ripples[index].setX(rippleX + offsetX); + ripples[index].setY(rippleY + offsetY); ripples[index].setMinWidth(rippleMinWidth); ripples[index].setMinHeight(rippleMinHeight); ripples[index].setMaxWidth(rippleMaxWidth); @@ -336,16 +350,15 @@ public void startRippleAnimation(int rippleDelay) { } public void startRippleAnimation(int rippleDelay, Interpolator interpolator) { - new Handler().postDelayed(()-> { + handler.postDelayed(()-> { animatorSet.end(); animatorSet.cancel(); - if(!animationRunning){ - animatorSet = new AnimatorSet(); - animatorSet.setInterpolator(interpolator); - animatorSet.playTogether(animators); - animatorSet.start(); - animationRunning=true; - } + animatorSet = new AnimatorSet(); + animatorSet.setInterpolator(interpolator); + animatorSet.playTogether(animators); + animatorSet.start(); + animationRunning=true; + }, rippleDelay); } @@ -473,10 +486,10 @@ protected void onDraw(Canvas canvas) { ripple.setMaxRadius(rippleMaxRadius); ripple.setClipRadius(rippleClipRadius); ripple.setStrokeWidth(rippleStrokeWidth); - ripple.setCenterX(centerX); - ripple.setCenterY(centerY); - ripple.setX(rippleX); - ripple.setY(rippleY); + ripple.setX(rippleX + offsetX); + ripple.setY(rippleY + offsetY); + ripple.setCenterX(centerX + offsetX); + ripple.setCenterY(centerY + offsetY); ripple.setMaxWidth(rippleMaxWidth); ripple.setMaxHeight(rippleMaxHeight); ripple.setMinWidth(rippleMinWidth); @@ -530,16 +543,32 @@ public void setTarget(View view, float widthRatio, float heightRatio, float radi parent.removeView(this); parent.addView(this); - setLayoutParams(new ConstraintLayout.LayoutParams(ConstraintLayout.LayoutParams.MATCH_PARENT, ConstraintLayout.LayoutParams.MATCH_PARENT)); + if(getLayoutParams() instanceof ConstraintLayout.LayoutParams){ + setLayoutParams(new ConstraintLayout.LayoutParams(ConstraintLayout.LayoutParams.MATCH_PARENT, ConstraintLayout.LayoutParams.MATCH_PARENT)); + }else if (getLayoutParams() instanceof LinearLayout.LayoutParams){ + setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT)); + }else if (getLayoutParams() instanceof FrameLayout.LayoutParams){ + setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT)); + }else if (getLayoutParams() instanceof RelativeLayout.LayoutParams){ + setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT)); + }else{ + setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + } + + int[] locationView = new int[2]; + int[] locationParent = new int[2]; + + view.getLocationOnScreen(locationView); + parent.getLocationOnScreen(locationParent); - int[] location = new int[2]; - view.getLocationOnScreen(location); + locationView[0] = locationView[0] - getCalculatedOffsetX(parent); + locationView[1] = locationView[1] - getCalculatedOffsetY(parent); - centerX = (location[0] + view.getWidth() / 2f); - centerY = (location[1] + view.getHeight() / 2f) - DimensionUtility.convertDpToPixel(getContext(), 24) ; + centerX = (locationView[0] + view.getWidth() / 2f); + centerY = (locationView[1] + view.getHeight() / 2f) - DimensionUtility.convertDpToPixel(getContext(), 24) ; - rippleX = (location[0] + view.getWidth() / 2f); - rippleY = (location[1] + view.getHeight() / 2f) - DimensionUtility.convertDpToPixel(getContext(), 24) ; + rippleX = (locationView[0] + view.getWidth() / 2f); + rippleY = (locationView[1] + view.getHeight() / 2f) - DimensionUtility.convertDpToPixel(getContext(), 24) ; rippleMinWidth = view.getWidth(); rippleMinHeight = view.getHeight(); @@ -555,6 +584,58 @@ public void setTarget(View view, float widthRatio, float heightRatio, float radi setTranslationZ(view.getTranslationZ()-1f); } + private int getCalculatedOffsetY(ViewGroup parent) { + Property property = new Property<>(parent.getTop()); + + //getCalculatedOffsetY(parent.getParent(), property); + + return property.getValue(); + } + + private int getCalculatedOffsetX(ViewGroup parent) { + Property property = new Property<>(parent.getLeft()); + + //getCalculatedOffsetX(parent.getParent(), property); + + return property.getValue(); + } + + private void getCalculatedOffsetY(ViewParent parent, Property offset) { + if(parent instanceof ViewGroup){ + ViewGroup group = (ViewGroup) parent; + offset.setValue(offset.getValue()+group.getTop()); + if(group.getParent() != null){ + getCalculatedOffsetY(group.getParent(), offset); + } + } + } + + private void getCalculatedOffsetX(ViewParent parent, Property offset) { + if(parent instanceof ViewGroup){ + ViewGroup group = (ViewGroup) parent; + offset.setValue(offset.getValue()+group.getLeft()); + if(group.getParent() != null){ + getCalculatedOffsetX(group.getParent(), offset); + } + } + } + + public void setOffsetX(float offsetX){ + this.offsetX = offsetX; + } + + public void setOffsetY(float offsetY){ + this.offsetY = offsetY; + } + + public float getOffsetX() { + return offsetX; + } + + public float getOffsetY() { + return offsetY; + } + public void setOnEnd(Runnable onEnd) { this.onEnd = onEnd; }