Init
This commit is contained in:
commit
52209017a3
198 files changed
+25167
No files matched your search
@@ -0,0 +1,317 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.RectF;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.view.ViewCompat;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.Interpolator;
|
||||
import android.view.animation.LinearInterpolator;
|
||||
|
||||
import com.hippo.anani.PathInterpolator;
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.yorozuya.ViewUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
// Base on android.graphics.drawable.MaterialProgressDrawable in L preview
|
||||
public class ProgressView extends View {
|
||||
|
||||
private static final Interpolator TRIM_START_INTERPOLATOR;
|
||||
private static final Interpolator TRIM_END_INTERPOLATOR;
|
||||
private static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
|
||||
|
||||
static {
|
||||
Path trimStartPath = new Path();
|
||||
trimStartPath.moveTo(0.0f, 0.0f);
|
||||
trimStartPath.lineTo(0.5f, 0.0f);
|
||||
trimStartPath.cubicTo(0.7f, 0.0f, 0.6f, 1f, 1f, 1f);
|
||||
TRIM_START_INTERPOLATOR = PathInterpolator.build(trimStartPath);
|
||||
|
||||
Path trimEndPath = new Path();
|
||||
trimEndPath.moveTo(0.0f, 0.0f);
|
||||
trimEndPath.cubicTo(0.2f, 0.0f, 0.1f, 1f, 0.5f, 1f);
|
||||
trimEndPath.lineTo(1f, 1f);
|
||||
TRIM_END_INTERPOLATOR = PathInterpolator.build(trimEndPath);
|
||||
}
|
||||
|
||||
private final ArrayList<Animator> mAnimators = new ArrayList<>();
|
||||
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private final RectF mRectF = new RectF();
|
||||
|
||||
private boolean mIndeterminate;
|
||||
|
||||
private float mTrimStart = 0.0f;
|
||||
private float mTrimEnd = 0.0f;
|
||||
private float mTrimOffset = 0.0f;
|
||||
private float mTrimRotation = 0.0f;
|
||||
|
||||
// It is a trick to avoid first sight stuck. Get it from ProgressBar
|
||||
private boolean mShouldStartAnimationDrawable = false;
|
||||
|
||||
public ProgressView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init(context, attrs);
|
||||
}
|
||||
|
||||
public ProgressView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init(context, attrs);
|
||||
}
|
||||
|
||||
private void init(Context context, AttributeSet attrs) {
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ProgressView);
|
||||
int color = a.getColor(R.styleable.ProgressView_color, Color.BLACK);
|
||||
mPaint.setColor(color);
|
||||
mPaint.setStrokeCap(Paint.Cap.SQUARE);
|
||||
mPaint.setStrokeJoin(Paint.Join.MITER);
|
||||
mPaint.setStyle(Paint.Style.STROKE);
|
||||
mIndeterminate = a.getBoolean(R.styleable.ProgressView_indeterminate, true);
|
||||
setProgress(a.getFloat(R.styleable.ProgressView_progress, 0f));
|
||||
a.recycle();
|
||||
|
||||
setupAnimators();
|
||||
}
|
||||
|
||||
private void setupAnimators() {
|
||||
ObjectAnimator trimStart = ObjectAnimator.ofFloat(this, "trimStart", 0.0f, 0.75f);
|
||||
trimStart.setDuration(1333L);
|
||||
trimStart.setInterpolator(TRIM_START_INTERPOLATOR);
|
||||
trimStart.setRepeatCount(Animation.INFINITE);
|
||||
|
||||
ObjectAnimator trimEnd = ObjectAnimator.ofFloat(this, "trimEnd", 0.0f, 0.75f);
|
||||
trimEnd.setDuration(1333L);
|
||||
trimEnd.setInterpolator(TRIM_END_INTERPOLATOR);
|
||||
trimEnd.setRepeatCount(Animation.INFINITE);
|
||||
|
||||
ObjectAnimator trimOffset = ObjectAnimator.ofFloat(this, "trimOffset", 0.0f, 0.25f);
|
||||
trimOffset.setDuration(1333L);
|
||||
trimOffset.setInterpolator(LINEAR_INTERPOLATOR);
|
||||
trimOffset.setRepeatCount(Animation.INFINITE);
|
||||
|
||||
ObjectAnimator trimRotation = ObjectAnimator.ofFloat(this, "trimRotation", 0.0f, 720.0f);
|
||||
trimRotation.setDuration(6665L);
|
||||
trimRotation.setInterpolator(LINEAR_INTERPOLATOR);
|
||||
trimRotation.setRepeatCount(Animation.INFINITE);
|
||||
|
||||
mAnimators.add(trimStart);
|
||||
mAnimators.add(trimEnd);
|
||||
mAnimators.add(trimOffset);
|
||||
mAnimators.add(trimRotation);
|
||||
}
|
||||
|
||||
private void startAnimation() {
|
||||
mShouldStartAnimationDrawable = true;
|
||||
postInvalidate();
|
||||
}
|
||||
|
||||
private void startAnimationActually() {
|
||||
ArrayList<Animator> animators = mAnimators;
|
||||
int N = animators.size();
|
||||
for (int i = 0; i < N; i++) {
|
||||
Animator animator = animators.get(i);
|
||||
if (!animator.isRunning()) {
|
||||
animator.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void stopAnimation() {
|
||||
mShouldStartAnimationDrawable = false;
|
||||
ArrayList<Animator> animators = mAnimators;
|
||||
int N = animators.size();
|
||||
for (int i = 0; i < N; i++) {
|
||||
animators.get(i).cancel();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isRunning() {
|
||||
ArrayList<Animator> animators = mAnimators;
|
||||
int N = animators.size();
|
||||
for (int i = 0; i < N; i++) {
|
||||
Animator animator = animators.get(i);
|
||||
if (animator.isRunning()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public float getTrimStart() {
|
||||
return mTrimStart;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void setTrimStart(float trimStart) {
|
||||
mTrimStart = trimStart;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public float getTrimEnd() {
|
||||
return mTrimEnd;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void setTrimEnd(float trimEnd) {
|
||||
mTrimEnd = trimEnd;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public float getTrimOffset() {
|
||||
return mTrimOffset;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void setTrimOffset(float trimOffset) {
|
||||
mTrimOffset = trimOffset;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public float getTrimRotation() {
|
||||
return mTrimRotation;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void setTrimRotation(float trimRotation) {
|
||||
mTrimRotation = trimRotation;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
if (mIndeterminate && getVisibility() == VISIBLE) {
|
||||
startAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
if (mIndeterminate) {
|
||||
stopAnimation();
|
||||
}
|
||||
// This should come after stopAnimation(), otherwise an invalidate message remains in the
|
||||
// queue, which can prevent the entire view hierarchy from being GC'ed during a rotation
|
||||
super.onDetachedFromWindow();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setVisibility(int v) {
|
||||
if (getVisibility() != v) {
|
||||
super.setVisibility(v);
|
||||
|
||||
if (mIndeterminate) {
|
||||
if (v == GONE || v == INVISIBLE) {
|
||||
stopAnimation();
|
||||
} else if (ViewCompat.isAttachedToWindow(this)) {
|
||||
startAnimation();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onVisibilityChanged(@NonNull View changedView, int visibility) {
|
||||
super.onVisibilityChanged(changedView, visibility);
|
||||
|
||||
if (mIndeterminate && ViewCompat.isAttachedToWindow(this)) {
|
||||
if (visibility == GONE || visibility == INVISIBLE) {
|
||||
stopAnimation();
|
||||
} else if (ViewCompat.isAttachedToWindow(this)) {
|
||||
startAnimation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setColor(int color) {
|
||||
mPaint.setColor(color);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setIndeterminate(boolean indeterminate) {
|
||||
if (mIndeterminate != indeterminate) {
|
||||
mIndeterminate = indeterminate;
|
||||
if (indeterminate) {
|
||||
if (isShown() && ViewCompat.isAttachedToWindow(this)) {
|
||||
startAnimation();
|
||||
}
|
||||
} else {
|
||||
stopAnimation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isIndeterminate() {
|
||||
return mIndeterminate;
|
||||
}
|
||||
|
||||
public void setProgress(float progress) {
|
||||
if (!mIndeterminate) {
|
||||
mTrimStart = 0f;
|
||||
mTrimEnd = progress;
|
||||
mTrimOffset = 0f;
|
||||
mTrimRotation = 0f;
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
setMeasuredDimension(ViewUtils.getSuitableSize(getSuggestedMinimumWidth(), widthMeasureSpec),
|
||||
ViewUtils.getSuitableSize(getSuggestedMinimumHeight(), heightMeasureSpec));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||
mPaint.setStrokeWidth(Math.min(w, h) / 12.0f);
|
||||
mRectF.set(0, 0, w, h);
|
||||
mRectF.inset(w / 48.0f * 5.0f, h / 48.0f * 5.0f);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
int saved = canvas.save();
|
||||
canvas.rotate(mTrimRotation, mRectF.centerX(), mRectF.centerY());
|
||||
|
||||
float startAngle = (mTrimStart + mTrimOffset) * 360.0f - 90;
|
||||
float sweepAngle = (mTrimEnd - mTrimStart) * 360.0f;
|
||||
canvas.drawArc(mRectF, startAngle, sweepAngle, false, mPaint);
|
||||
|
||||
canvas.restoreToCount(saved);
|
||||
|
||||
if (mShouldStartAnimationDrawable) {
|
||||
mShouldStartAnimationDrawable = false;
|
||||
startAnimationActually();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user