diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..08226ec --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index af0bbdd..703e5d4 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -5,7 +5,7 @@ - + diff --git a/aimatedprogresslib/src/main/java/com/app/aimatedprogresslib/AnimatedLoadingIndicator.java b/aimatedprogresslib/src/main/java/com/app/aimatedprogresslib/AnimatedLoadingIndicator.java new file mode 100644 index 0000000..8576e24 --- /dev/null +++ b/aimatedprogresslib/src/main/java/com/app/aimatedprogresslib/AnimatedLoadingIndicator.java @@ -0,0 +1,455 @@ +package com.app.aimatedprogresslib; + +import android.annotation.TargetApi; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Rect; +import android.graphics.drawable.Animatable; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.view.View; +import android.view.animation.AnimationUtils; +import com.app.aimatedprogresslib.Indicators.Indicator; + +/* + * Created by Yash on 22/2/17. + */ + +public class AnimatedLoadingIndicator extends View +{ + private static final ProgressBallMultipleIndicator DEFAULT_INDICATOR = new ProgressBallMultipleIndicator(); + + private static final int MIN_SHOW_TIME = 500; // ms + private static final int MIN_DELAY = 500; // ms + + private long mStartTime = -1; + + private boolean mPostedHide = false; + + private boolean mPostedShow = false; + + private boolean mDismissed = false; + + private final Runnable mDelayedHide = new Runnable() + { + @Override + public void run() + { + mPostedHide = false; + mStartTime = -1; + setVisibility(View.GONE); + } + }; + + private final Runnable mDelayedShow = new Runnable() + { + @Override + public void run() + { + mPostedShow = false; + if (!mDismissed) + { + mStartTime = System.currentTimeMillis(); + setVisibility(View.VISIBLE); + } + } + }; + + int mMinWidth; + int mMaxWidth; + int mMinHeight; + int mMaxHeight; + + private Indicator mIndicator; + private int mIndicatorColor; + + private boolean mShouldStartAnimationDrawable; + + public AnimatedLoadingIndicator(Context context) + { + super(context); + init(context, null,0,0); + } + + public AnimatedLoadingIndicator(Context context, AttributeSet attrs) + { + super(context, attrs); + init(context, attrs,0, R.style.AnimatedLoadingIndicatorView); + } + + public AnimatedLoadingIndicator(Context context, AttributeSet attrs, int defStyleAttr) + { + super(context, attrs, defStyleAttr); + init(context, attrs,defStyleAttr, R.style.AnimatedLoadingIndicatorView); + } + + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + public AnimatedLoadingIndicator(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) + { + super(context, attrs, defStyleAttr, defStyleRes); + init(context,attrs,defStyleAttr,R.style.AnimatedLoadingIndicatorView); + } + + private void init(Context context,AttributeSet attrs,int defStyleAttr, int defStyleRes) + { + mMinWidth = 24; + mMaxWidth = 48; + mMinHeight = 24; + mMaxHeight = 48; + + final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AnimatedLoadingIndicatorView, defStyleAttr, defStyleRes); + + mMinWidth = a.getDimensionPixelSize(R.styleable.AnimatedLoadingIndicatorView_minWidth, mMinWidth); + mMaxWidth = a.getDimensionPixelSize(R.styleable.AnimatedLoadingIndicatorView_maxWidth, mMaxWidth); + mMinHeight = a.getDimensionPixelSize(R.styleable.AnimatedLoadingIndicatorView_minHeight, mMinHeight); + mMaxHeight = a.getDimensionPixelSize(R.styleable.AnimatedLoadingIndicatorView_maxHeight, mMaxHeight); + String indicatorName =a.getString(R.styleable.AnimatedLoadingIndicatorView_indicatorName); + mIndicatorColor = a.getColor(R.styleable.AnimatedLoadingIndicatorView_indicatorColor, Color.WHITE); + setIndicator(indicatorName); + if (mIndicator==null) + { + setIndicator(DEFAULT_INDICATOR); + } + a.recycle(); + } + + public Indicator getIndicator() + { + return mIndicator; + } + + public void setIndicator(Indicator d) + { + if (mIndicator != d) + { + if (mIndicator != null) + { + mIndicator.setCallback(null); + unscheduleDrawable(mIndicator); + } + + mIndicator = d; + + setIndicatorColor(mIndicatorColor); + if (d != null) + { + d.setCallback(this); + } + + postInvalidate(); + } + } + + + /** + * setIndicatorColor(0xFF00FF00) + * or + * setIndicatorColor(Color.BLUE) + * or + * setIndicatorColor(Color.parseColor("#FF4081")) + * or + * setIndicatorColor(0xFF00FF00) + * or + * setIndicatorColor(getResources().getColor(android.R.color.black)) + */ + public void setIndicatorColor(int color) + { + this.mIndicatorColor=color; + mIndicator.setColor(color); + } + + public void setIndicator(String indicatorName) + { + if (TextUtils.isEmpty(indicatorName)) + { + return; + } + StringBuilder drawableClassName=new StringBuilder(); + if (!indicatorName.contains(".")) + { + String defaultPackageName=getClass().getPackage().getName(); + drawableClassName.append(defaultPackageName) + .append(".indicators") + .append("."); + } + drawableClassName.append(indicatorName); + try + { + Class drawableClass = Class.forName(drawableClassName.toString()); + Indicator indicator = (Indicator) drawableClass.newInstance(); + setIndicator(indicator); + } + catch (Exception e) + { + e.printStackTrace(); + } + } + + public void smoothToShow() + { + startAnimation(AnimationUtils.loadAnimation(getContext(),android.R.anim.fade_in)); + setVisibility(VISIBLE); + } + + public void smoothToHide() + { + startAnimation(AnimationUtils.loadAnimation(getContext(),android.R.anim.fade_out)); + setVisibility(GONE); + } + + public void hide() + { + mDismissed = true; + removeCallbacks(mDelayedShow); + long diff = System.currentTimeMillis() - mStartTime; + if (diff >= MIN_SHOW_TIME || mStartTime == -1) + { + setVisibility(View.GONE); + } + else + { + if (!mPostedHide) + { + postDelayed(mDelayedHide, MIN_SHOW_TIME - diff); + mPostedHide = true; + } + } + } + + public void show() + { + mStartTime = -1; + mDismissed = false; + removeCallbacks(mDelayedHide); + if (!mPostedShow) + { + postDelayed(mDelayedShow, MIN_DELAY); + mPostedShow = true; + } + } + + @Override + protected boolean verifyDrawable(Drawable who) + { + return who == mIndicator || super.verifyDrawable(who); + } + + void startAnimation() + { + if (getVisibility() != VISIBLE) + { + return; + } + + if (mIndicator instanceof Animatable) + { + mShouldStartAnimationDrawable = true; + } + postInvalidate(); + } + + void stopAnimation() + { + if (mIndicator instanceof Animatable) + { + mIndicator.stop(); + mShouldStartAnimationDrawable = false; + } + postInvalidate(); + } + + @Override + public void setVisibility(int v) + { + if (getVisibility() != v) + { + super.setVisibility(v); + if (v == GONE || v == INVISIBLE) + { + stopAnimation(); + } + else + { + startAnimation(); + } + } + } + + @Override + protected void onVisibilityChanged( View changedView, int visibility) + { + super.onVisibilityChanged(changedView, visibility); + if (visibility == GONE || visibility == INVISIBLE) + { + stopAnimation(); + } + else + { + startAnimation(); + } + } + + @Override + public void invalidateDrawable( Drawable dr) + { + if (verifyDrawable(dr)) + { + final Rect dirty = dr.getBounds(); + final int scrollX = getScrollX() + getPaddingLeft(); + final int scrollY = getScrollY() + getPaddingTop(); + + invalidate(dirty.left + scrollX, dirty.top + scrollY, dirty.right + scrollX, dirty.bottom + scrollY); + } + else + { + super.invalidateDrawable(dr); + } + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) + { + updateDrawableBounds(w, h); + } + + private void updateDrawableBounds(int w, int h) + { + w -= getPaddingRight() + getPaddingLeft(); + h -= getPaddingTop() + getPaddingBottom(); + + int right = w; + int bottom = h; + int top = 0; + int left = 0; + + if (mIndicator != null) + { + final int intrinsicWidth = mIndicator.getIntrinsicWidth(); + final int intrinsicHeight = mIndicator.getIntrinsicHeight(); + final float intrinsicAspect = (float) intrinsicWidth / intrinsicHeight; + final float boundAspect = (float) w / h; + if (intrinsicAspect != boundAspect) + { + if (boundAspect > intrinsicAspect) + { + final int width = (int) (h * intrinsicAspect); + left = (w - width) / 2; + right = left + width; + } + else + { + final int height = (int) (w * (1 / intrinsicAspect)); + top = (h - height) / 2; + bottom = top + height; + } + } + mIndicator.setBounds(left, top, right, bottom); + } + } + + @Override + protected synchronized void onDraw(Canvas canvas) + { + super.onDraw(canvas); + drawTrack(canvas); + } + + void drawTrack(Canvas canvas) + { + final Drawable d = mIndicator; + if (d != null) + { + final int saveCount = canvas.save(); + + canvas.translate(getPaddingLeft(), getPaddingTop()); + + d.draw(canvas); + canvas.restoreToCount(saveCount); + + if (mShouldStartAnimationDrawable && d instanceof Animatable) + { + ((Animatable) d).start(); + mShouldStartAnimationDrawable = false; + } + } + } + + @Override + protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) + { + int dw = 0; + int dh = 0; + + final Drawable d = mIndicator; + if (d != null) + { + dw = Math.max(mMinWidth, Math.min(mMaxWidth, d.getIntrinsicWidth())); + dh = Math.max(mMinHeight, Math.min(mMaxHeight, d.getIntrinsicHeight())); + } + + updateDrawableState(); + + dw += getPaddingLeft() + getPaddingRight(); + dh += getPaddingTop() + getPaddingBottom(); + + final int measuredWidth = resolveSizeAndState(dw, widthMeasureSpec, 0); + final int measuredHeight = resolveSizeAndState(dh, heightMeasureSpec, 0); + setMeasuredDimension(measuredWidth, measuredHeight); + } + + @Override + protected void drawableStateChanged() + { + super.drawableStateChanged(); + updateDrawableState(); + } + + private void updateDrawableState() + { + final int[] state = getDrawableState(); + if (mIndicator != null && mIndicator.isStateful()) + { + mIndicator.setState(state); + } + } + + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + @Override + public void drawableHotspotChanged(float x, float y) + { + super.drawableHotspotChanged(x, y); + + if (mIndicator != null) + { + mIndicator.setHotspot(x, y); + } + } + + @Override + protected void onAttachedToWindow() + { + super.onAttachedToWindow(); + startAnimation(); + removeCallbacks(); + } + + @Override + protected void onDetachedFromWindow() + { + stopAnimation(); + + super.onDetachedFromWindow(); + removeCallbacks(); + } + + private void removeCallbacks() + { + removeCallbacks(mDelayedHide); + removeCallbacks(mDelayedShow); + } + +} \ No newline at end of file diff --git a/aimatedprogresslib/src/main/java/com/app/aimatedprogresslib/Indicators/Indicator.java b/aimatedprogresslib/src/main/java/com/app/aimatedprogresslib/Indicators/Indicator.java new file mode 100644 index 0000000..8124969 --- /dev/null +++ b/aimatedprogresslib/src/main/java/com/app/aimatedprogresslib/Indicators/Indicator.java @@ -0,0 +1,214 @@ +package com.app.aimatedprogresslib.Indicators; + +import android.animation.ValueAnimator; +import android.annotation.SuppressLint; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.drawable.Animatable; +import android.graphics.drawable.Drawable; + +import java.util.ArrayList; +import java.util.HashMap; + +/* + * Created by Yash on 22/2/17. + */ + +public abstract class Indicator extends Drawable implements Animatable +{ + private HashMap mUpdateListeners=new HashMap<>(); + + private ArrayList mAnimators; + private int alpha = 255; + private static final Rect ZERO_BOUNDS_RECT = new Rect(); + private Rect drawBounds = ZERO_BOUNDS_RECT; + + private boolean mHasAnimators; + + private Paint mPaint=new Paint(); + + public Indicator() + { + mPaint.setColor(Color.WHITE); + mPaint.setStyle(Paint.Style.FILL); + mPaint.setAntiAlias(true); + } + + public int getColor() { + return mPaint.getColor(); + } + + public void setColor(int color) { + mPaint.setColor(color); + } + + @Override + public void setAlpha(int alpha) { + this.alpha = alpha; + } + + @Override + public int getAlpha() { + return alpha; + } + + @Override + public int getOpacity() { + return PixelFormat.OPAQUE; + } + + @Override + public void setColorFilter(ColorFilter colorFilter) { + + } + + @Override + public void draw(Canvas canvas) { + draw(canvas,mPaint); + } + + public abstract void draw(Canvas canvas, Paint paint); + + public abstract ArrayList onCreateAnimators(); + + @Override + public void start() { + ensureAnimators(); + + if (mAnimators == null) { + return; + } + + // If the animators has not ended, do nothing. + if (isStarted()) { + return; + } + startAnimators(); + invalidateSelf(); + } + + private void startAnimators() + { + for (int i = 0; i < mAnimators.size(); i++) + { + ValueAnimator animator = mAnimators.get(i); + + ValueAnimator.AnimatorUpdateListener updateListener=mUpdateListeners.get(animator); + if (updateListener!=null) + { + animator.addUpdateListener(updateListener); + } + + animator.start(); + } + } + + @SuppressLint("NewApi") + private void stopAnimators() + { + if (mAnimators!=null) + { + for (ValueAnimator animator : mAnimators) + { + if (animator != null && animator.isStarted()) + { + animator.removeAllUpdateListeners(); + animator.end(); + } + } + } + } + + private void ensureAnimators() + { + if (!mHasAnimators) + { + mAnimators = onCreateAnimators(); + mHasAnimators = true; + } + } + + @Override + public void stop() + { + stopAnimators(); + } + + @SuppressLint("NewApi") + private boolean isStarted() + { + for (ValueAnimator animator : mAnimators) + { + return animator.isStarted(); + } + return false; + } + + @Override + public boolean isRunning() { + for (ValueAnimator animator : mAnimators) { + return animator.isRunning(); + } + return false; + } + + /** + * Your should use this to add AnimatorUpdateListener when + * create animator , otherwise , animator doesn't work when + * the animation restart . + */ + public void addUpdateListener(ValueAnimator animator, ValueAnimator.AnimatorUpdateListener updateListener){ + mUpdateListeners.put(animator,updateListener); + } + + @Override + protected void onBoundsChange(Rect bounds) { + super.onBoundsChange(bounds); + setDrawBounds(bounds); + } + + public void setDrawBounds(Rect drawBounds) { + setDrawBounds(drawBounds.left, drawBounds.top, drawBounds.right, drawBounds.bottom); + } + + public void setDrawBounds(int left, int top, int right, int bottom) { + this.drawBounds = new Rect(left, top, right, bottom); + } + + public void postInvalidate(){ + invalidateSelf(); + } + + public Rect getDrawBounds() { + return drawBounds; + } + + public int getWidth(){ + return drawBounds.width(); + } + + public int getHeight(){ + return drawBounds.height(); + } + + public int centerX(){ + return drawBounds.centerX(); + } + + public int centerY(){ + return drawBounds.centerY(); + } + + public float exactCenterX(){ + return drawBounds.exactCenterX(); + } + + public float exactCenterY(){ + return drawBounds.exactCenterY(); + } + +} \ No newline at end of file diff --git a/aimatedprogresslib/src/main/java/com/app/aimatedprogresslib/ProgressBallMultipleIndicator.java b/aimatedprogresslib/src/main/java/com/app/aimatedprogresslib/ProgressBallMultipleIndicator.java new file mode 100644 index 0000000..4861f43 --- /dev/null +++ b/aimatedprogresslib/src/main/java/com/app/aimatedprogresslib/ProgressBallMultipleIndicator.java @@ -0,0 +1,81 @@ +package com.app.aimatedprogresslib; + +/* + * Created by Yash on 03/08/17. + */ + +import android.animation.ValueAnimator; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.view.animation.LinearInterpolator; +import com.app.aimatedprogresslib.Indicators.Indicator; + +import java.util.ArrayList; + +/* + * Created by Yash on 21/3/17. + */ + +class ProgressBallMultipleIndicator extends Indicator +{ + + private float[] scaleFloats=new float[]{1,1,1}; + private int[] alphaInts=new int[]{255,255,255}; + + @Override + public void draw(Canvas canvas, Paint paint) + { + float circleSpacing = 4; + for (int i = 0; i < 3; i++) + { + paint.setAlpha(alphaInts[i]); + canvas.scale(scaleFloats[i],scaleFloats[i],getWidth()/2,getHeight()/2); + canvas.drawCircle(getWidth()/2,getHeight()/2,getWidth()/2-circleSpacing,paint); + } + } + + @Override + public ArrayList onCreateAnimators() + { + ArrayList animators=new ArrayList<>(); + long[] delays=new long[]{0, 200, 400}; + for (int i = 0; i < 3; i++) + { + final int index=i; + ValueAnimator scaleAnim=ValueAnimator.ofFloat(0,1); + scaleAnim.setInterpolator(new LinearInterpolator()); + scaleAnim.setDuration(2000); + scaleAnim.setRepeatCount(-1); + addUpdateListener(scaleAnim,new ValueAnimator.AnimatorUpdateListener() + { + @Override + public void onAnimationUpdate(ValueAnimator animation) + { + scaleFloats[index] = (float) animation.getAnimatedValue(); + postInvalidate(); + } + }); + scaleAnim.setStartDelay(delays[i]); + + ValueAnimator alphaAnim=ValueAnimator.ofInt(255,0); + alphaAnim.setInterpolator(new LinearInterpolator()); + alphaAnim.setDuration(2000); + alphaAnim.setRepeatCount(-1); + addUpdateListener(alphaAnim,new ValueAnimator.AnimatorUpdateListener() + { + @Override + public void onAnimationUpdate(ValueAnimator animation) + { + alphaInts[index] = (int) animation.getAnimatedValue(); + postInvalidate(); + } + }); + scaleAnim.setStartDelay(delays[i]); + + animators.add(scaleAnim); + animators.add(alphaAnim); + } + return animators; + } + +} diff --git a/aimatedprogresslib/src/main/res/layout/custom_dialog_progress.xml b/aimatedprogresslib/src/main/res/layout/custom_dialog_progress.xml new file mode 100644 index 0000000..f40cfd6 --- /dev/null +++ b/aimatedprogresslib/src/main/res/layout/custom_dialog_progress.xml @@ -0,0 +1,28 @@ + + + + + + + + \ No newline at end of file diff --git a/aimatedprogresslib/src/main/res/values/attrs.xml b/aimatedprogresslib/src/main/res/values/attrs.xml new file mode 100644 index 0000000..51d9145 --- /dev/null +++ b/aimatedprogresslib/src/main/res/values/attrs.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/aimatedprogresslib/src/main/res/values/strings.xml b/aimatedprogresslib/src/main/res/values/strings.xml index 94b12c6..48a19c0 100644 --- a/aimatedprogresslib/src/main/res/values/strings.xml +++ b/aimatedprogresslib/src/main/res/values/strings.xml @@ -1,3 +1,4 @@ AimatedProgressLib + Loading… diff --git a/aimatedprogresslib/src/main/res/values/styles.xml b/aimatedprogresslib/src/main/res/values/styles.xml new file mode 100644 index 0000000..1311ca3 --- /dev/null +++ b/aimatedprogresslib/src/main/res/values/styles.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index eeeb9eb..d4874bf 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -32,4 +32,7 @@ dependencies { testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test:runner:1.2.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' + + implementation project(':aimatedprogresslib') + } diff --git a/app/src/main/java/com/app/animatedloadingindicator/MainActivity.kt b/app/src/main/java/com/app/animatedloadingindicator/MainActivity.kt index 9497c15..a00d736 100644 --- a/app/src/main/java/com/app/animatedloadingindicator/MainActivity.kt +++ b/app/src/main/java/com/app/animatedloadingindicator/MainActivity.kt @@ -1,12 +1,23 @@ package com.app.animatedloadingindicator +import android.app.Dialog +import android.graphics.Color +import android.graphics.drawable.ColorDrawable import androidx.appcompat.app.AppCompatActivity import android.os.Bundle +import android.view.Window class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) + + val progressDialog = Dialog(this); + progressDialog.requestWindowFeature(Window.FEATURE_NO_TITLE); + progressDialog.setContentView(R.layout.custom_dialog_progress); + progressDialog.window!!.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)); + progressDialog.setCancelable(false); + progressDialog.show() } }