Use RefreshLayout from jitpack
This commit is contained in:
1 parent
4e3717fa69
commit
189a95e49c
10 files changed
+8
-2651
No files matched your search
+2
-1
@@ -83,7 +83,8 @@ dependencies {
|
||||
compile 'com.android.support:appcompat-v7:23.3.0'
|
||||
compile 'com.android.support:design:23.3.0'
|
||||
compile 'com.github.amlcurran.showcaseview:library:5.4.1'
|
||||
compile 'com.github.seven332:unifile:0.1.0'
|
||||
compile 'com.github.seven332:unifile:0.1.1'
|
||||
compile 'com.github.seven332:refreshlayout:0.1.0'
|
||||
compile 'com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:0.8.7'
|
||||
compile 'org.ccil.cowan.tagsoup:tagsoup:1.2.1'
|
||||
compile 'org.jsoup:jsoup:1.8.3'
|
||||
|
||||
@@ -71,6 +71,7 @@ import com.hippo.ehviewer.ui.annotation.DrawerLifeCircle;
|
||||
import com.hippo.ehviewer.ui.annotation.ViewLifeCircle;
|
||||
import com.hippo.ehviewer.ui.annotation.WholeLifeCircle;
|
||||
import com.hippo.ehviewer.widget.SearchBar;
|
||||
import com.hippo.refreshlayout.RefreshLayout;
|
||||
import com.hippo.rippleold.RippleSalon;
|
||||
import com.hippo.scene.Announcer;
|
||||
import com.hippo.scene.SceneFragment;
|
||||
@@ -79,7 +80,6 @@ import com.hippo.util.DrawableManager;
|
||||
import com.hippo.widget.ContentLayout;
|
||||
import com.hippo.widget.FabLayout;
|
||||
import com.hippo.widget.SearchBarMover;
|
||||
import com.hippo.widget.refreshlayout.RefreshLayout;
|
||||
import com.hippo.yorozuya.AssertUtils;
|
||||
import com.hippo.yorozuya.LayoutUtils;
|
||||
import com.hippo.yorozuya.ObjectUtils;
|
||||
|
||||
@@ -76,6 +76,7 @@ import com.hippo.ehviewer.ui.CommonOperations;
|
||||
import com.hippo.ehviewer.ui.MainActivity;
|
||||
import com.hippo.ehviewer.widget.SearchBar;
|
||||
import com.hippo.ehviewer.widget.SearchLayout;
|
||||
import com.hippo.refreshlayout.RefreshLayout;
|
||||
import com.hippo.rippleold.RippleSalon;
|
||||
import com.hippo.scene.Announcer;
|
||||
import com.hippo.scene.SceneFragment;
|
||||
@@ -86,7 +87,6 @@ import com.hippo.view.ViewTransition;
|
||||
import com.hippo.widget.ContentLayout;
|
||||
import com.hippo.widget.FabLayout;
|
||||
import com.hippo.widget.SearchBarMover;
|
||||
import com.hippo.widget.refreshlayout.RefreshLayout;
|
||||
import com.hippo.yorozuya.AnimationUtils;
|
||||
import com.hippo.yorozuya.AssertUtils;
|
||||
import com.hippo.yorozuya.MathUtils;
|
||||
|
||||
@@ -36,10 +36,10 @@ import com.hippo.easyrecyclerview.FastScroller;
|
||||
import com.hippo.easyrecyclerview.HandlerDrawable;
|
||||
import com.hippo.easyrecyclerview.LayoutManagerUtils;
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.refreshlayout.RefreshLayout;
|
||||
import com.hippo.util.DrawableManager;
|
||||
import com.hippo.util.ExceptionUtils;
|
||||
import com.hippo.view.ViewTransition;
|
||||
import com.hippo.widget.refreshlayout.RefreshLayout;
|
||||
import com.hippo.yorozuya.IntIdGenerator;
|
||||
import com.hippo.yorozuya.IntList;
|
||||
import com.hippo.yorozuya.LayoutUtils;
|
||||
|
||||
@@ -1,156 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 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.widget.refreshlayout;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.RadialGradient;
|
||||
import android.graphics.Shader;
|
||||
import android.graphics.drawable.ShapeDrawable;
|
||||
import android.graphics.drawable.shapes.OvalShape;
|
||||
import android.support.annotation.ColorRes;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v4.view.ViewCompat;
|
||||
import android.view.animation.Animation;
|
||||
import android.widget.ImageView;
|
||||
|
||||
/**
|
||||
* Private class created to work around issues with AnimationListeners being
|
||||
* called before the animation is actually complete and support shadows on older
|
||||
* platforms.
|
||||
*/
|
||||
@SuppressLint("ViewConstructor")
|
||||
class CircleImageView extends ImageView {
|
||||
|
||||
private static final int KEY_SHADOW_COLOR = 0x1E000000;
|
||||
private static final int FILL_SHADOW_COLOR = 0x3D000000;
|
||||
// PX
|
||||
private static final float X_OFFSET = 0f;
|
||||
private static final float Y_OFFSET = 1.75f;
|
||||
private static final float SHADOW_RADIUS = 3.5f;
|
||||
private static final int SHADOW_ELEVATION = 4;
|
||||
|
||||
private Animation.AnimationListener mListener;
|
||||
private int mShadowRadius;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public CircleImageView(Context context, int color, final float radius) {
|
||||
super(context);
|
||||
final float density = getContext().getResources().getDisplayMetrics().density;
|
||||
final int diameter = (int) (radius * density * 2);
|
||||
final int shadowYOffset = (int) (density * Y_OFFSET);
|
||||
final int shadowXOffset = (int) (density * X_OFFSET);
|
||||
|
||||
mShadowRadius = (int) (density * SHADOW_RADIUS);
|
||||
|
||||
ShapeDrawable circle;
|
||||
if (elevationSupported()) {
|
||||
circle = new ShapeDrawable(new OvalShape());
|
||||
ViewCompat.setElevation(this, SHADOW_ELEVATION * density);
|
||||
} else {
|
||||
OvalShape oval = new OvalShadow(mShadowRadius, diameter);
|
||||
circle = new ShapeDrawable(oval);
|
||||
ViewCompat.setLayerType(this, ViewCompat.LAYER_TYPE_SOFTWARE, circle.getPaint());
|
||||
circle.getPaint().setShadowLayer(mShadowRadius, shadowXOffset, shadowYOffset,
|
||||
KEY_SHADOW_COLOR);
|
||||
final int padding = mShadowRadius;
|
||||
// set padding so the inner image sits correctly within the shadow.
|
||||
setPadding(padding, padding, padding, padding);
|
||||
}
|
||||
circle.getPaint().setColor(color);
|
||||
setBackgroundDrawable(circle);
|
||||
}
|
||||
|
||||
private boolean elevationSupported() {
|
||||
return android.os.Build.VERSION.SDK_INT >= 21;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
if (!elevationSupported()) {
|
||||
setMeasuredDimension(getMeasuredWidth() + mShadowRadius*2, getMeasuredHeight()
|
||||
+ mShadowRadius*2);
|
||||
}
|
||||
}
|
||||
|
||||
public void setAnimationListener(Animation.AnimationListener listener) {
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationStart() {
|
||||
super.onAnimationStart();
|
||||
if (mListener != null) {
|
||||
mListener.onAnimationStart(getAnimation());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd() {
|
||||
super.onAnimationEnd();
|
||||
if (mListener != null) {
|
||||
mListener.onAnimationEnd(getAnimation());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the background color of the circle image view.
|
||||
*
|
||||
* @param colorRes Id of a color resource.
|
||||
*/
|
||||
public void setBackgroundColorRes(@ColorRes int colorRes) {
|
||||
setBackgroundColor(ContextCompat.getColor(getContext(), colorRes));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBackgroundColor(int color) {
|
||||
if (getBackground() instanceof ShapeDrawable) {
|
||||
((ShapeDrawable) getBackground()).getPaint().setColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
private class OvalShadow extends OvalShape {
|
||||
private final RadialGradient mRadialGradient;
|
||||
private final Paint mShadowPaint;
|
||||
private final int mCircleDiameter;
|
||||
|
||||
public OvalShadow(int shadowRadius, int circleDiameter) {
|
||||
super();
|
||||
mShadowPaint = new Paint();
|
||||
mShadowRadius = shadowRadius;
|
||||
mCircleDiameter = circleDiameter;
|
||||
mRadialGradient = new RadialGradient(mCircleDiameter / 2, mCircleDiameter / 2,
|
||||
mShadowRadius, new int[] {
|
||||
FILL_SHADOW_COLOR, Color.TRANSPARENT
|
||||
}, null, Shader.TileMode.CLAMP);
|
||||
mShadowPaint.setShader(mRadialGradient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas, Paint paint) {
|
||||
final int viewWidth = CircleImageView.this.getWidth();
|
||||
final int viewHeight = CircleImageView.this.getHeight();
|
||||
canvas.drawCircle(viewWidth / 2, viewHeight / 2, (mCircleDiameter / 2 + mShadowRadius),
|
||||
mShadowPaint);
|
||||
canvas.drawCircle(viewWidth / 2, viewHeight / 2, (mCircleDiameter / 2), paint);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,788 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 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.widget.refreshlayout;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Paint.Style;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.drawable.Animatable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.support.annotation.IntDef;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.view.animation.FastOutSlowInInterpolator;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.View;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.Interpolator;
|
||||
import android.view.animation.LinearInterpolator;
|
||||
import android.view.animation.Transformation;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Fancy progress indicator for Material theme.
|
||||
*/
|
||||
class MaterialProgressDrawable extends Drawable implements Animatable {
|
||||
private static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
|
||||
private static final Interpolator MATERIAL_INTERPOLATOR = new FastOutSlowInInterpolator();
|
||||
|
||||
private static final float FULL_ROTATION = 1080.0f;
|
||||
@Retention(RetentionPolicy.CLASS)
|
||||
@IntDef({LARGE, DEFAULT})
|
||||
public @interface ProgressDrawableSize {}
|
||||
// Maps to ProgressBar.Large style
|
||||
static final int LARGE = 0;
|
||||
// Maps to ProgressBar default style
|
||||
static final int DEFAULT = 1;
|
||||
|
||||
// Maps to ProgressBar default style
|
||||
private static final int CIRCLE_DIAMETER = 40;
|
||||
private static final float CENTER_RADIUS = 8.75f; //should add up to 10 when + stroke_width
|
||||
private static final float STROKE_WIDTH = 2.5f;
|
||||
|
||||
// Maps to ProgressBar.Large style
|
||||
private static final int CIRCLE_DIAMETER_LARGE = 56;
|
||||
private static final float CENTER_RADIUS_LARGE = 12.5f;
|
||||
private static final float STROKE_WIDTH_LARGE = 3f;
|
||||
|
||||
private final int[] COLORS = new int[] {
|
||||
Color.BLACK
|
||||
};
|
||||
|
||||
/**
|
||||
* The value in the linear interpolator for animating the drawable at which
|
||||
* the color transition should start
|
||||
*/
|
||||
private static final float COLOR_START_DELAY_OFFSET = 0.75f;
|
||||
private static final float END_TRIM_START_DELAY_OFFSET = 0.5f;
|
||||
private static final float START_TRIM_DURATION_OFFSET = 0.5f;
|
||||
|
||||
/** The duration of a single progress spin in milliseconds. */
|
||||
private static final int ANIMATION_DURATION = 1332;
|
||||
|
||||
/** The number of points in the progress "star". */
|
||||
private static final float NUM_POINTS = 5f;
|
||||
/** The list of animators operating on this drawable. */
|
||||
private final ArrayList<Animation> mAnimators = new ArrayList<Animation>();
|
||||
|
||||
/** The indicator ring, used to manage animation state. */
|
||||
private final Ring mRing;
|
||||
|
||||
/** Canvas rotation in degrees. */
|
||||
private float mRotation;
|
||||
|
||||
/** Layout info for the arrowhead in dp */
|
||||
private static final int ARROW_WIDTH = 10;
|
||||
private static final int ARROW_HEIGHT = 5;
|
||||
private static final float ARROW_OFFSET_ANGLE = 5;
|
||||
|
||||
/** Layout info for the arrowhead for the large spinner in dp */
|
||||
private static final int ARROW_WIDTH_LARGE = 12;
|
||||
private static final int ARROW_HEIGHT_LARGE = 6;
|
||||
private static final float MAX_PROGRESS_ARC = .8f;
|
||||
|
||||
private final Resources mResources;
|
||||
private final View mParent;
|
||||
private Animation mAnimation;
|
||||
private float mRotationCount;
|
||||
private double mWidth;
|
||||
private double mHeight;
|
||||
boolean mFinishing;
|
||||
|
||||
public MaterialProgressDrawable(Context context, View parent) {
|
||||
mParent = parent;
|
||||
mResources = context.getResources();
|
||||
|
||||
mRing = new Ring(mCallback);
|
||||
mRing.setColors(COLORS);
|
||||
|
||||
updateSizes(DEFAULT);
|
||||
setupAnimators();
|
||||
}
|
||||
|
||||
private void setSizeParameters(double progressCircleWidth, double progressCircleHeight,
|
||||
double centerRadius, double strokeWidth, float arrowWidth, float arrowHeight) {
|
||||
final Ring ring = mRing;
|
||||
final DisplayMetrics metrics = mResources.getDisplayMetrics();
|
||||
final float screenDensity = metrics.density;
|
||||
|
||||
mWidth = progressCircleWidth * screenDensity;
|
||||
mHeight = progressCircleHeight * screenDensity;
|
||||
ring.setStrokeWidth((float) strokeWidth * screenDensity);
|
||||
ring.setCenterRadius(centerRadius * screenDensity);
|
||||
ring.setColorIndex(0);
|
||||
ring.setArrowDimensions(arrowWidth * screenDensity, arrowHeight * screenDensity);
|
||||
ring.setInsets((int) mWidth, (int) mHeight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the overall size for the progress spinner. This updates the radius
|
||||
* and stroke width of the ring.
|
||||
*
|
||||
* @param size One of {@link #LARGE} or
|
||||
* {@link #DEFAULT}
|
||||
*/
|
||||
public void updateSizes(@ProgressDrawableSize int size) {
|
||||
if (size == LARGE) {
|
||||
setSizeParameters(CIRCLE_DIAMETER_LARGE, CIRCLE_DIAMETER_LARGE, CENTER_RADIUS_LARGE,
|
||||
STROKE_WIDTH_LARGE, ARROW_WIDTH_LARGE, ARROW_HEIGHT_LARGE);
|
||||
} else {
|
||||
setSizeParameters(CIRCLE_DIAMETER, CIRCLE_DIAMETER, CENTER_RADIUS, STROKE_WIDTH,
|
||||
ARROW_WIDTH, ARROW_HEIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param show Set to true to display the arrowhead on the progress spinner.
|
||||
*/
|
||||
public void showArrow(boolean show) {
|
||||
mRing.setShowArrow(show);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param scale Set the scale of the arrowhead for the spinner.
|
||||
*/
|
||||
public void setArrowScale(float scale) {
|
||||
mRing.setArrowScale(scale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the start and end trim for the progress spinner arc.
|
||||
*
|
||||
* @param startAngle start angle
|
||||
* @param endAngle end angle
|
||||
*/
|
||||
public void setStartEndTrim(float startAngle, float endAngle) {
|
||||
mRing.setStartTrim(startAngle);
|
||||
mRing.setEndTrim(endAngle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the amount of rotation to apply to the progress spinner.
|
||||
*
|
||||
* @param rotation Rotation is from [0..1]
|
||||
*/
|
||||
public void setProgressRotation(float rotation) {
|
||||
mRing.setRotation(rotation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the background color of the circle image view.
|
||||
*/
|
||||
public void setBackgroundColor(int color) {
|
||||
mRing.setBackgroundColor(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the colors used in the progress animation from color resources.
|
||||
* The first color will also be the color of the bar that grows in response
|
||||
* to a user swipe gesture.
|
||||
*
|
||||
* @param colors the colors for scheme
|
||||
*/
|
||||
public void setColorSchemeColors(int... colors) {
|
||||
mRing.setColors(colors);
|
||||
mRing.setColorIndex(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntrinsicHeight() {
|
||||
return (int) mHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntrinsicWidth() {
|
||||
return (int) mWidth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Canvas c) {
|
||||
final Rect bounds = getBounds();
|
||||
final int saveCount = c.save();
|
||||
c.rotate(mRotation, bounds.exactCenterX(), bounds.exactCenterY());
|
||||
mRing.draw(c, bounds);
|
||||
c.restoreToCount(saveCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(int alpha) {
|
||||
mRing.setAlpha(alpha);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAlpha() {
|
||||
return mRing.getAlpha();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColorFilter(ColorFilter colorFilter) {
|
||||
mRing.setColorFilter(colorFilter);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
void setRotation(float rotation) {
|
||||
mRotation = rotation;
|
||||
invalidateSelf();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private float getRotation() {
|
||||
return mRotation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpacity() {
|
||||
return PixelFormat.TRANSLUCENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
final ArrayList<Animation> animators = mAnimators;
|
||||
final int N = animators.size();
|
||||
for (int i = 0; i < N; i++) {
|
||||
final Animation animator = animators.get(i);
|
||||
if (animator.hasStarted() && !animator.hasEnded()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
mAnimation.reset();
|
||||
mRing.storeOriginals();
|
||||
// Already showing some part of the ring
|
||||
if (mRing.getEndTrim() != mRing.getStartTrim()) {
|
||||
mFinishing = true;
|
||||
mAnimation.setDuration(ANIMATION_DURATION/2);
|
||||
mParent.startAnimation(mAnimation);
|
||||
} else {
|
||||
mRing.setColorIndex(0);
|
||||
mRing.resetOriginals();
|
||||
mAnimation.setDuration(ANIMATION_DURATION);
|
||||
mParent.startAnimation(mAnimation);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
mParent.clearAnimation();
|
||||
setRotation(0);
|
||||
mRing.setShowArrow(false);
|
||||
mRing.setColorIndex(0);
|
||||
mRing.resetOriginals();
|
||||
}
|
||||
|
||||
private float getMinProgressArc(Ring ring) {
|
||||
return (float) Math.toRadians(
|
||||
ring.getStrokeWidth() / (2 * Math.PI * ring.getCenterRadius()));
|
||||
}
|
||||
|
||||
// Adapted from ArgbEvaluator.java
|
||||
private int evaluateColorChange(float fraction, int startValue, int endValue) {
|
||||
int startA = (startValue >> 24) & 0xff;
|
||||
int startR = (startValue >> 16) & 0xff;
|
||||
int startG = (startValue >> 8) & 0xff;
|
||||
int startB = startValue & 0xff;
|
||||
|
||||
int endA = (endValue >> 24) & 0xff;
|
||||
int endR = (endValue >> 16) & 0xff;
|
||||
int endG = (endValue >> 8) & 0xff;
|
||||
int endB = endValue & 0xff;
|
||||
|
||||
return (startA + (int)(fraction * (endA - startA))) << 24 |
|
||||
(startR + (int)(fraction * (endR - startR))) << 16 |
|
||||
(startG + (int)(fraction * (endG - startG))) << 8 |
|
||||
(startB + (int)(fraction * (endB - startB)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the ring color if this is within the last 25% of the animation.
|
||||
* The new ring color will be a translation from the starting ring color to
|
||||
* the next color.
|
||||
*/
|
||||
private void updateRingColor(float interpolatedTime, Ring ring) {
|
||||
if (interpolatedTime > COLOR_START_DELAY_OFFSET) {
|
||||
// scale the interpolatedTime so that the full
|
||||
// transformation from 0 - 1 takes place in the
|
||||
// remaining time
|
||||
ring.setColor(evaluateColorChange((interpolatedTime - COLOR_START_DELAY_OFFSET)
|
||||
/ (1.0f - COLOR_START_DELAY_OFFSET), ring.getStartingColor(),
|
||||
ring.getNextColor()));
|
||||
}
|
||||
}
|
||||
|
||||
private void applyFinishTranslation(float interpolatedTime, Ring ring) {
|
||||
// shrink back down and complete a full rotation before
|
||||
// starting other circles
|
||||
// Rotation goes between [0..1].
|
||||
updateRingColor(interpolatedTime, ring);
|
||||
float targetRotation = (float) (Math.floor(ring.getStartingRotation() / MAX_PROGRESS_ARC)
|
||||
+ 1f);
|
||||
final float minProgressArc = getMinProgressArc(ring);
|
||||
final float startTrim = ring.getStartingStartTrim()
|
||||
+ (ring.getStartingEndTrim() - minProgressArc - ring.getStartingStartTrim())
|
||||
* interpolatedTime;
|
||||
ring.setStartTrim(startTrim);
|
||||
ring.setEndTrim(ring.getStartingEndTrim());
|
||||
final float rotation = ring.getStartingRotation()
|
||||
+ ((targetRotation - ring.getStartingRotation()) * interpolatedTime);
|
||||
ring.setRotation(rotation);
|
||||
}
|
||||
|
||||
private void setupAnimators() {
|
||||
final Ring ring = mRing;
|
||||
final Animation animation = new Animation() {
|
||||
@Override
|
||||
public void applyTransformation(float interpolatedTime, Transformation t) {
|
||||
if (mFinishing) {
|
||||
applyFinishTranslation(interpolatedTime, ring);
|
||||
} else {
|
||||
// The minProgressArc is calculated from 0 to create an
|
||||
// angle that matches the stroke width.
|
||||
final float minProgressArc = getMinProgressArc(ring);
|
||||
final float startingEndTrim = ring.getStartingEndTrim();
|
||||
final float startingTrim = ring.getStartingStartTrim();
|
||||
final float startingRotation = ring.getStartingRotation();
|
||||
|
||||
updateRingColor(interpolatedTime, ring);
|
||||
|
||||
// Moving the start trim only occurs in the first 50% of a
|
||||
// single ring animation
|
||||
if (interpolatedTime <= START_TRIM_DURATION_OFFSET) {
|
||||
// scale the interpolatedTime so that the full
|
||||
// transformation from 0 - 1 takes place in the
|
||||
// remaining time
|
||||
final float scaledTime = (interpolatedTime)
|
||||
/ (1.0f - START_TRIM_DURATION_OFFSET);
|
||||
final float startTrim = startingTrim
|
||||
+ ((MAX_PROGRESS_ARC - minProgressArc) * MATERIAL_INTERPOLATOR
|
||||
.getInterpolation(scaledTime));
|
||||
ring.setStartTrim(startTrim);
|
||||
}
|
||||
|
||||
// Moving the end trim starts after 50% of a single ring
|
||||
// animation completes
|
||||
if (interpolatedTime > END_TRIM_START_DELAY_OFFSET) {
|
||||
// scale the interpolatedTime so that the full
|
||||
// transformation from 0 - 1 takes place in the
|
||||
// remaining time
|
||||
final float minArc = MAX_PROGRESS_ARC - minProgressArc;
|
||||
float scaledTime = (interpolatedTime - START_TRIM_DURATION_OFFSET)
|
||||
/ (1.0f - START_TRIM_DURATION_OFFSET);
|
||||
final float endTrim = startingEndTrim
|
||||
+ (minArc * MATERIAL_INTERPOLATOR.getInterpolation(scaledTime));
|
||||
ring.setEndTrim(endTrim);
|
||||
}
|
||||
|
||||
final float rotation = startingRotation + (0.25f * interpolatedTime);
|
||||
ring.setRotation(rotation);
|
||||
|
||||
float groupRotation = ((FULL_ROTATION / NUM_POINTS) * interpolatedTime)
|
||||
+ (FULL_ROTATION * (mRotationCount / NUM_POINTS));
|
||||
setRotation(groupRotation);
|
||||
}
|
||||
}
|
||||
};
|
||||
animation.setRepeatCount(Animation.INFINITE);
|
||||
animation.setRepeatMode(Animation.RESTART);
|
||||
animation.setInterpolator(LINEAR_INTERPOLATOR);
|
||||
animation.setAnimationListener(new Animation.AnimationListener() {
|
||||
|
||||
@Override
|
||||
public void onAnimationStart(Animation animation) {
|
||||
mRotationCount = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animation animation) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(Animation animation) {
|
||||
ring.storeOriginals();
|
||||
ring.goToNextColor();
|
||||
ring.setStartTrim(ring.getEndTrim());
|
||||
if (mFinishing) {
|
||||
// finished closing the last ring from the swipe gesture; go
|
||||
// into progress mode
|
||||
mFinishing = false;
|
||||
animation.setDuration(ANIMATION_DURATION);
|
||||
ring.setShowArrow(false);
|
||||
} else {
|
||||
mRotationCount = (mRotationCount + 1) % (NUM_POINTS);
|
||||
}
|
||||
}
|
||||
});
|
||||
mAnimation = animation;
|
||||
}
|
||||
|
||||
private final Callback mCallback = new Callback() {
|
||||
@Override
|
||||
public void invalidateDrawable(Drawable d) {
|
||||
invalidateSelf();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scheduleDrawable(Drawable d, Runnable what, long when) {
|
||||
scheduleSelf(what, when);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unscheduleDrawable(Drawable d, Runnable what) {
|
||||
unscheduleSelf(what);
|
||||
}
|
||||
};
|
||||
|
||||
private static class Ring {
|
||||
private final RectF mTempBounds = new RectF();
|
||||
private final Paint mPaint = new Paint();
|
||||
private final Paint mArrowPaint = new Paint();
|
||||
|
||||
private final Callback mCallback;
|
||||
|
||||
private float mStartTrim = 0.0f;
|
||||
private float mEndTrim = 0.0f;
|
||||
private float mRotation = 0.0f;
|
||||
private float mStrokeWidth = 5.0f;
|
||||
private float mStrokeInset = 2.5f;
|
||||
|
||||
private int[] mColors;
|
||||
// mColorIndex represents the offset into the available mColors that the
|
||||
// progress circle should currently display. As the progress circle is
|
||||
// animating, the mColorIndex moves by one to the next available color.
|
||||
private int mColorIndex;
|
||||
private float mStartingStartTrim;
|
||||
private float mStartingEndTrim;
|
||||
private float mStartingRotation;
|
||||
private boolean mShowArrow;
|
||||
private Path mArrow;
|
||||
private float mArrowScale;
|
||||
private double mRingCenterRadius;
|
||||
private int mArrowWidth;
|
||||
private int mArrowHeight;
|
||||
private int mAlpha;
|
||||
private final Paint mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private int mBackgroundColor;
|
||||
private int mCurrentColor;
|
||||
|
||||
public Ring(Callback callback) {
|
||||
mCallback = callback;
|
||||
|
||||
mPaint.setStrokeCap(Paint.Cap.SQUARE);
|
||||
mPaint.setAntiAlias(true);
|
||||
mPaint.setStyle(Style.STROKE);
|
||||
|
||||
mArrowPaint.setStyle(Style.FILL);
|
||||
mArrowPaint.setAntiAlias(true);
|
||||
}
|
||||
|
||||
public void setBackgroundColor(int color) {
|
||||
mBackgroundColor = color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the dimensions of the arrowhead.
|
||||
*
|
||||
* @param width Width of the hypotenuse of the arrow head
|
||||
* @param height Height of the arrow point
|
||||
*/
|
||||
public void setArrowDimensions(float width, float height) {
|
||||
mArrowWidth = (int) width;
|
||||
mArrowHeight = (int) height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw the progress spinner
|
||||
*/
|
||||
public void draw(Canvas c, Rect bounds) {
|
||||
final RectF arcBounds = mTempBounds;
|
||||
arcBounds.set(bounds);
|
||||
arcBounds.inset(mStrokeInset, mStrokeInset);
|
||||
|
||||
final float startAngle = (mStartTrim + mRotation) * 360;
|
||||
final float endAngle = (mEndTrim + mRotation) * 360;
|
||||
float sweepAngle = endAngle - startAngle;
|
||||
|
||||
mPaint.setColor(mCurrentColor);
|
||||
c.drawArc(arcBounds, startAngle, sweepAngle, false, mPaint);
|
||||
|
||||
drawTriangle(c, startAngle, sweepAngle, bounds);
|
||||
|
||||
if (mAlpha < 255) {
|
||||
mCirclePaint.setColor(mBackgroundColor);
|
||||
mCirclePaint.setAlpha(255 - mAlpha);
|
||||
c.drawCircle(bounds.exactCenterX(), bounds.exactCenterY(), bounds.width() / 2,
|
||||
mCirclePaint);
|
||||
}
|
||||
}
|
||||
|
||||
private void drawTriangle(Canvas c, float startAngle, float sweepAngle, Rect bounds) {
|
||||
if (mShowArrow) {
|
||||
if (mArrow == null) {
|
||||
mArrow = new Path();
|
||||
mArrow.setFillType(Path.FillType.EVEN_ODD);
|
||||
} else {
|
||||
mArrow.reset();
|
||||
}
|
||||
|
||||
// Adjust the position of the triangle so that it is inset as
|
||||
// much as the arc, but also centered on the arc.
|
||||
float inset = (int) mStrokeInset / 2 * mArrowScale;
|
||||
float x = (float) (mRingCenterRadius * Math.cos(0) + bounds.exactCenterX());
|
||||
float y = (float) (mRingCenterRadius * Math.sin(0) + bounds.exactCenterY());
|
||||
|
||||
// Update the path each time. This works around an issue in SKIA
|
||||
// where concatenating a rotation matrix to a scale matrix
|
||||
// ignored a starting negative rotation. This appears to have
|
||||
// been fixed as of API 21.
|
||||
mArrow.moveTo(0, 0);
|
||||
mArrow.lineTo(mArrowWidth * mArrowScale, 0);
|
||||
mArrow.lineTo((mArrowWidth * mArrowScale / 2), (mArrowHeight
|
||||
* mArrowScale));
|
||||
mArrow.offset(x - inset, y);
|
||||
mArrow.close();
|
||||
// draw a triangle
|
||||
mArrowPaint.setColor(mCurrentColor);
|
||||
c.rotate(startAngle + sweepAngle - ARROW_OFFSET_ANGLE, bounds.exactCenterX(),
|
||||
bounds.exactCenterY());
|
||||
c.drawPath(mArrow, mArrowPaint);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the colors the progress spinner alternates between.
|
||||
*
|
||||
* @param colors Array of integers describing the colors. Must be non-<code>null</code>.
|
||||
*/
|
||||
public void setColors(@NonNull int[] colors) {
|
||||
mColors = colors;
|
||||
// if colors are reset, make sure to reset the color index as well
|
||||
setColorIndex(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the absolute color of the progress spinner. This is should only
|
||||
* be used when animating between current and next color when the
|
||||
* spinner is rotating.
|
||||
*
|
||||
* @param color int describing the color.
|
||||
*/
|
||||
public void setColor(int color) {
|
||||
mCurrentColor = color;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param index Index into the color array of the color to display in
|
||||
* the progress spinner.
|
||||
*/
|
||||
public void setColorIndex(int index) {
|
||||
mColorIndex = index;
|
||||
mCurrentColor = mColors[mColorIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int describing the next color the progress spinner should use when drawing.
|
||||
*/
|
||||
public int getNextColor() {
|
||||
return mColors[getNextColorIndex()];
|
||||
}
|
||||
|
||||
private int getNextColorIndex() {
|
||||
return (mColorIndex + 1) % (mColors.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Proceed to the next available ring color. This will automatically
|
||||
* wrap back to the beginning of colors.
|
||||
*/
|
||||
public void goToNextColor() {
|
||||
setColorIndex(getNextColorIndex());
|
||||
}
|
||||
|
||||
public void setColorFilter(ColorFilter filter) {
|
||||
mPaint.setColorFilter(filter);
|
||||
invalidateSelf();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param alpha Set the alpha of the progress spinner and associated arrowhead.
|
||||
*/
|
||||
public void setAlpha(int alpha) {
|
||||
mAlpha = alpha;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Current alpha of the progress spinner and arrowhead.
|
||||
*/
|
||||
public int getAlpha() {
|
||||
return mAlpha;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param strokeWidth Set the stroke width of the progress spinner in pixels.
|
||||
*/
|
||||
public void setStrokeWidth(float strokeWidth) {
|
||||
mStrokeWidth = strokeWidth;
|
||||
mPaint.setStrokeWidth(strokeWidth);
|
||||
invalidateSelf();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public float getStrokeWidth() {
|
||||
return mStrokeWidth;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void setStartTrim(float startTrim) {
|
||||
mStartTrim = startTrim;
|
||||
invalidateSelf();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public float getStartTrim() {
|
||||
return mStartTrim;
|
||||
}
|
||||
|
||||
public float getStartingStartTrim() {
|
||||
return mStartingStartTrim;
|
||||
}
|
||||
|
||||
public float getStartingEndTrim() {
|
||||
return mStartingEndTrim;
|
||||
}
|
||||
|
||||
public int getStartingColor() {
|
||||
return mColors[mColorIndex];
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void setEndTrim(float endTrim) {
|
||||
mEndTrim = endTrim;
|
||||
invalidateSelf();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public float getEndTrim() {
|
||||
return mEndTrim;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void setRotation(float rotation) {
|
||||
mRotation = rotation;
|
||||
invalidateSelf();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public float getRotation() {
|
||||
return mRotation;
|
||||
}
|
||||
|
||||
public void setInsets(int width, int height) {
|
||||
final float minEdge = (float) Math.min(width, height);
|
||||
float insets;
|
||||
if (mRingCenterRadius <= 0 || minEdge < 0) {
|
||||
insets = (float) Math.ceil(mStrokeWidth / 2.0f);
|
||||
} else {
|
||||
insets = (float) (minEdge / 2.0f - mRingCenterRadius);
|
||||
}
|
||||
mStrokeInset = insets;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public float getInsets() {
|
||||
return mStrokeInset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param centerRadius Inner radius in px of the circle the progress
|
||||
* spinner arc traces.
|
||||
*/
|
||||
public void setCenterRadius(double centerRadius) {
|
||||
mRingCenterRadius = centerRadius;
|
||||
}
|
||||
|
||||
public double getCenterRadius() {
|
||||
return mRingCenterRadius;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param show Set to true to show the arrow head on the progress spinner.
|
||||
*/
|
||||
public void setShowArrow(boolean show) {
|
||||
if (mShowArrow != show) {
|
||||
mShowArrow = show;
|
||||
invalidateSelf();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param scale Set the scale of the arrowhead for the spinner.
|
||||
*/
|
||||
public void setArrowScale(float scale) {
|
||||
if (scale != mArrowScale) {
|
||||
mArrowScale = scale;
|
||||
invalidateSelf();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The amount the progress spinner is currently rotated, between [0..1].
|
||||
*/
|
||||
public float getStartingRotation() {
|
||||
return mStartingRotation;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the start / end trim are offset to begin with, store them so that
|
||||
* animation starts from that offset.
|
||||
*/
|
||||
public void storeOriginals() {
|
||||
mStartingStartTrim = mStartTrim;
|
||||
mStartingEndTrim = mEndTrim;
|
||||
mStartingRotation = mRotation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the progress spinner to default rotation, start and end angles.
|
||||
*/
|
||||
public void resetOriginals() {
|
||||
mStartingStartTrim = 0;
|
||||
mStartingEndTrim = 0;
|
||||
mStartingRotation = 0;
|
||||
setStartTrim(0);
|
||||
setEndTrim(0);
|
||||
setRotation(0);
|
||||
}
|
||||
|
||||
private void invalidateSelf() {
|
||||
mCallback.invalidateDrawable(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,303 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 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.widget.refreshlayout;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.Region;
|
||||
import android.os.Build;
|
||||
import android.support.v4.view.ViewCompat;
|
||||
import android.support.v4.view.animation.FastOutSlowInInterpolator;
|
||||
import android.view.View;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
|
||||
/**
|
||||
* Custom progress bar that shows a cycle of colors as widening circles that
|
||||
* overdraw each other. When finished, the bar is cleared from the inside out as
|
||||
* the main cycle continues. Before running, this can also indicate how close
|
||||
* the user is to triggering something (e.g. how far they need to pull down to
|
||||
* trigger a refresh).
|
||||
*/
|
||||
final class SwipeProgressBar {
|
||||
|
||||
private static final boolean SUPPORT_CLIP_RECT_DIFFERENCE =
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2;
|
||||
|
||||
// Default progress animation colors are grays.
|
||||
private final static int COLOR1 = 0xB3000000;
|
||||
private final static int COLOR2 = 0x80000000;
|
||||
private final static int COLOR3 = 0x4d000000;
|
||||
private final static int COLOR4 = 0x1a000000;
|
||||
|
||||
// The duration of the animation cycle.
|
||||
private static final int ANIMATION_DURATION_MS = 2000;
|
||||
|
||||
// The duration of the animation to clear the bar.
|
||||
private static final int FINISH_ANIMATION_DURATION_MS = 1000;
|
||||
|
||||
// Interpolator for varying the speed of the animation.
|
||||
private static final Interpolator INTERPOLATOR = new FastOutSlowInInterpolator();
|
||||
|
||||
private final Paint mPaint = new Paint();
|
||||
private final RectF mClipRect = new RectF();
|
||||
private float mTriggerPercentage;
|
||||
private long mStartTime;
|
||||
private long mFinishTime;
|
||||
private boolean mRunning;
|
||||
|
||||
// Colors used when rendering the animation,
|
||||
private int mColor1;
|
||||
private int mColor2;
|
||||
private int mColor3;
|
||||
private int mColor4;
|
||||
private final View mParent;
|
||||
|
||||
private final Rect mBounds = new Rect();
|
||||
|
||||
public SwipeProgressBar(View parent) {
|
||||
mParent = parent;
|
||||
mColor1 = COLOR1;
|
||||
mColor2 = COLOR2;
|
||||
mColor3 = COLOR3;
|
||||
mColor4 = COLOR4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the four colors used in the progress animation. The first color will
|
||||
* also be the color of the bar that grows in response to a user swipe
|
||||
* gesture.
|
||||
*
|
||||
* @param color1 Integer representation of a color.
|
||||
* @param color2 Integer representation of a color.
|
||||
* @param color3 Integer representation of a color.
|
||||
* @param color4 Integer representation of a color.
|
||||
*/
|
||||
void setColorScheme(int color1, int color2, int color3, int color4) {
|
||||
mColor1 = color1;
|
||||
mColor2 = color2;
|
||||
mColor3 = color3;
|
||||
mColor4 = color4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the progress the user has made toward triggering the swipe
|
||||
* gesture. and use this value to update the percentage of the trigger that
|
||||
* is shown.
|
||||
*/
|
||||
void setTriggerPercentage(float triggerPercentage) {
|
||||
mTriggerPercentage = triggerPercentage;
|
||||
mStartTime = 0;
|
||||
ViewCompat.postInvalidateOnAnimation(
|
||||
mParent, mBounds.left, mBounds.top, mBounds.right, mBounds.bottom);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start showing the progress animation.
|
||||
*/
|
||||
void start() {
|
||||
if (!mRunning) {
|
||||
mTriggerPercentage = 0;
|
||||
mStartTime = AnimationUtils.currentAnimationTimeMillis();
|
||||
mRunning = true;
|
||||
mParent.postInvalidate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop showing the progress animation.
|
||||
*/
|
||||
void stop() {
|
||||
if (mRunning) {
|
||||
mTriggerPercentage = 0;
|
||||
mFinishTime = AnimationUtils.currentAnimationTimeMillis();
|
||||
mRunning = false;
|
||||
mParent.postInvalidate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Return whether the progress animation is currently running.
|
||||
*/
|
||||
boolean isRunning() {
|
||||
return mRunning || mFinishTime > 0;
|
||||
}
|
||||
|
||||
void draw(Canvas canvas) {
|
||||
// API < 18 do not support clipRect(Region.Op.DIFFERENCE).
|
||||
// So draw twice for finish animation
|
||||
if (draw(canvas, true)) {
|
||||
draw(canvas, false);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean draw(Canvas canvas, boolean first) {
|
||||
Rect bounds = mBounds;
|
||||
final int width = bounds.width();
|
||||
final int cx = bounds.centerX();
|
||||
final int cy = bounds.centerY();
|
||||
boolean drawTriggerWhileFinishing = false;
|
||||
boolean drawAgain = false;
|
||||
int restoreCount = canvas.save();
|
||||
canvas.clipRect(bounds);
|
||||
|
||||
if (mRunning || (mFinishTime > 0)) {
|
||||
long now = AnimationUtils.currentAnimationTimeMillis();
|
||||
long elapsed = (now - mStartTime) % ANIMATION_DURATION_MS;
|
||||
long iterations = (now - mStartTime) / ANIMATION_DURATION_MS;
|
||||
float rawProgress = (elapsed / (ANIMATION_DURATION_MS / 100f));
|
||||
|
||||
// If we're not running anymore, that means we're running through
|
||||
// the finish animation.
|
||||
if (!mRunning) {
|
||||
// If the finish animation is done, don't draw anything, and
|
||||
// don't repost.
|
||||
if ((now - mFinishTime) >= FINISH_ANIMATION_DURATION_MS) {
|
||||
mFinishTime = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Otherwise, use a 0 opacity alpha layer to clear the animation
|
||||
// from the inside out. This layer will prevent the circles from
|
||||
// drawing within its bounds.
|
||||
long finishElapsed = (now - mFinishTime) % FINISH_ANIMATION_DURATION_MS;
|
||||
float finishProgress = (finishElapsed / (FINISH_ANIMATION_DURATION_MS / 100f));
|
||||
float pct = (finishProgress / 100f);
|
||||
// Radius of the circle is half of the screen.
|
||||
float clearRadius = width / 2 * INTERPOLATOR.getInterpolation(pct);
|
||||
if (SUPPORT_CLIP_RECT_DIFFERENCE) {
|
||||
mClipRect.set(cx - clearRadius, bounds.top, cx + clearRadius, bounds.bottom);
|
||||
canvas.clipRect(mClipRect, Region.Op.DIFFERENCE);
|
||||
} else {
|
||||
if (first) {
|
||||
// First time left
|
||||
drawAgain = true;
|
||||
mClipRect.set(bounds.left, bounds.top, cx - clearRadius, bounds.bottom);
|
||||
} else {
|
||||
// Second time right
|
||||
mClipRect.set(cx + clearRadius, bounds.top, bounds.right, bounds.bottom);
|
||||
}
|
||||
canvas.clipRect(mClipRect);
|
||||
}
|
||||
// Only draw the trigger if there is a space in the center of
|
||||
// this refreshing view that needs to be filled in by the
|
||||
// trigger. If the progress view is just still animating, let it
|
||||
// continue animating.
|
||||
drawTriggerWhileFinishing = true;
|
||||
}
|
||||
|
||||
// First fill in with the last color that would have finished drawing.
|
||||
if (iterations == 0) {
|
||||
canvas.drawColor(mColor1);
|
||||
} else {
|
||||
if (rawProgress >= 0 && rawProgress < 25) {
|
||||
canvas.drawColor(mColor4);
|
||||
} else if (rawProgress >= 25 && rawProgress < 50) {
|
||||
canvas.drawColor(mColor1);
|
||||
} else if (rawProgress >= 50 && rawProgress < 75) {
|
||||
canvas.drawColor(mColor2);
|
||||
} else {
|
||||
canvas.drawColor(mColor3);
|
||||
}
|
||||
}
|
||||
|
||||
// Then draw up to 4 overlapping concentric circles of varying radii, based on how far
|
||||
// along we are in the cycle.
|
||||
// progress 0-50 draw mColor2
|
||||
// progress 25-75 draw mColor3
|
||||
// progress 50-100 draw mColor4
|
||||
// progress 75 (wrap to 25) draw mColor1
|
||||
if ((rawProgress >= 0 && rawProgress <= 25)) {
|
||||
float pct = (((rawProgress + 25) * 2) / 100f);
|
||||
drawCircle(canvas, cx, cy, mColor1, pct);
|
||||
}
|
||||
if (rawProgress >= 0 && rawProgress <= 50) {
|
||||
float pct = ((rawProgress * 2) / 100f);
|
||||
drawCircle(canvas, cx, cy, mColor2, pct);
|
||||
}
|
||||
if (rawProgress >= 25 && rawProgress <= 75) {
|
||||
float pct = (((rawProgress - 25) * 2) / 100f);
|
||||
drawCircle(canvas, cx, cy, mColor3, pct);
|
||||
}
|
||||
if (rawProgress >= 50 && rawProgress <= 100) {
|
||||
float pct = (((rawProgress - 50) * 2) / 100f);
|
||||
drawCircle(canvas, cx, cy, mColor4, pct);
|
||||
}
|
||||
if ((rawProgress >= 75 && rawProgress <= 100)) {
|
||||
float pct = (((rawProgress - 75) * 2) / 100f);
|
||||
drawCircle(canvas, cx, cy, mColor1, pct);
|
||||
}
|
||||
if (mTriggerPercentage > 0 && drawTriggerWhileFinishing) {
|
||||
// There is some portion of trigger to draw. Restore the canvas,
|
||||
// then draw the trigger. Otherwise, the trigger does not appear
|
||||
// until after the bar has finished animating and appears to
|
||||
// just jump in at a larger width than expected.
|
||||
canvas.restoreToCount(restoreCount);
|
||||
restoreCount = canvas.save();
|
||||
canvas.clipRect(bounds);
|
||||
drawTrigger(canvas, cx, cy);
|
||||
}
|
||||
// Keep running until we finish out the last cycle.
|
||||
ViewCompat.postInvalidateOnAnimation(
|
||||
mParent, bounds.left, bounds.top, bounds.right, bounds.bottom);
|
||||
} else {
|
||||
// Otherwise if we're in the middle of a trigger, draw that.
|
||||
if (mTriggerPercentage > 0 && mTriggerPercentage <= 1.0) {
|
||||
drawTrigger(canvas, cx, cy);
|
||||
}
|
||||
}
|
||||
canvas.restoreToCount(restoreCount);
|
||||
return drawAgain;
|
||||
}
|
||||
|
||||
private void drawTrigger(Canvas canvas, int cx, int cy) {
|
||||
mPaint.setColor(mColor1);
|
||||
canvas.drawCircle(cx, cy, cx * mTriggerPercentage, mPaint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a circle centered in the view.
|
||||
*
|
||||
* @param canvas the canvas to draw on
|
||||
* @param cx the center x coordinate
|
||||
* @param cy the center y coordinate
|
||||
* @param color the color to draw
|
||||
* @param pct the percentage of the view that the circle should cover
|
||||
*/
|
||||
private void drawCircle(Canvas canvas, float cx, float cy, int color, float pct) {
|
||||
mPaint.setColor(color);
|
||||
canvas.save();
|
||||
canvas.translate(cx, cy);
|
||||
float radiusScale = INTERPOLATOR.getInterpolation(pct);
|
||||
canvas.scale(radiusScale, radiusScale);
|
||||
canvas.drawCircle(0, 0, cx, mPaint);
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the drawing bounds of this SwipeProgressBar.
|
||||
*/
|
||||
void setBounds(int left, int top, int right, int bottom) {
|
||||
mBounds.left = left;
|
||||
mBounds.top = top;
|
||||
mBounds.right = right;
|
||||
mBounds.bottom = bottom;
|
||||
}
|
||||
}
|
||||
@@ -39,7 +39,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.hippo.widget.refreshlayout.RefreshLayout
|
||||
<com.hippo.refreshlayout.RefreshLayout
|
||||
android:id="@+id/refresh_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
@@ -50,7 +50,7 @@
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"/>
|
||||
|
||||
</com.hippo.widget.refreshlayout.RefreshLayout>
|
||||
</com.hippo.refreshlayout.RefreshLayout>
|
||||
|
||||
<com.hippo.easyrecyclerview.FastScroller
|
||||
android:id="@+id/fast_scroller"
|
||||
|
||||
+1
-1
Submodule easyrecyclerview updated: e80f9adbc8...1ab59455e2.
Reference in new issue
Block a user