这次是改了SmartRefreshLayout 中 根据官方提供的刷新 头,还有一些博客参考
修改源码自定义SwipeRefreshLayout样式——高仿微信朋友圈下拉刷新_u011443509的博客-CSDN博客_swiperefreshlayout 自定义动画
GitHub - wdsqjq/FengYunWeather: 风云天气是Android 平台开源天气 App,采用Kotlin、Room、OKHttp3、 协程等框架实现。
主要修改的
MaterialProgressDrawable 和 其中的 CircleImageView
public class MyCircleImageView extends ImageView {
protected static final int KEY_SHADOW_COLOR = 0x1E000000;
protected static final int FILL_SHADOW_COLOR = 0x3D000000;
// PX
protected static final float X_OFFSET = 0f;
protected static final float Y_OFFSET = 1.75f;
protected static final float SHADOW_RADIUS = 3.5f;
protected static final int SHADOW_ELEVATION = 4;
// private Animation.AnimationListener mListener;
int mShadowRadius;
public MyCircleImageView(Context context, int color) {
super(context);
final View thisView = this;
final float density = thisView.getResources().getDisplayMetrics().density;
final int shadowYOffset = (int) (density * Y_OFFSET);
final int shadowXOffset = (int) (density * X_OFFSET);
mShadowRadius = (int) (density * SHADOW_RADIUS);
ShapeDrawable circle;
if (Build.VERSION.SDK_INT >= 21) {
circle = new ShapeDrawable(new OvalShape());
thisView.setElevation(SHADOW_ELEVATION * density);
} else {
OvalShape oval = new OvalShadow(mShadowRadius);
circle = new ShapeDrawable(oval);
thisView.setLayerType(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.
thisView.setPadding(padding, padding, padding, padding);
}
// circle.getPaint().setColor(color);
// thisView.setBackground(circle);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final View thisView = this;
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (Build.VERSION.SDK_INT < 21) {
super.setMeasuredDimension(
thisView.getMeasuredWidth() + mShadowRadius * 2,
thisView.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());
// }
// }
//
// public void setBackgroundColorRes(int colorRes) {
// Context context = getContext();
// if (Build.VERSION.SDK_INT >= 23) {
// setBackgroundColor(context.getResources().getColor(colorRes, context.getTheme()));
// } else {
// //noinspection deprecation
// setBackgroundColor(context.getResources().getColor(colorRes));
// }
// }
//
@Override
public void setBackgroundColor( int color) {
final View thisView = this;
if (thisView.getBackground() instanceof ShapeDrawable) {
((ShapeDrawable) thisView.getBackground()).getPaint().setColor(color);
}
}
private class OvalShadow extends OvalShape {
private RadialGradient mRadialGradient;
private Paint mShadowPaint;
OvalShadow(int shadowRadius) {
super();
mShadowPaint = new Paint();
mShadowRadius = shadowRadius;
updateRadialGradient((int) super.rect().width());
}
@Override
protected void onResize(float width, float height) {
super.onResize(width, height);
updateRadialGradient((int) width);
}
@Override
public void draw(Canvas canvas, Paint paint) {
final View thisView = MyCircleImageView.this;
final int viewWidth = thisView.getWidth();
final int viewHeight = thisView.getHeight();
canvas.drawCircle(viewWidth / 2f, viewHeight / 2f, viewWidth / 2f, mShadowPaint);
canvas.drawCircle(viewWidth / 2f, viewHeight / 2f, viewWidth / 2f - mShadowRadius, paint);
}
private void updateRadialGradient(int diameter) {
mRadialGradient = new RadialGradient(diameter / 2f, diameter / 2f,
mShadowRadius, new int[] { FILL_SHADOW_COLOR, Color.TRANSPARENT },
null, Shader.TileMode.CLAMP);
mShadowPaint.setShader(mRadialGradient);
}
}
}
public class CustomProgressDrawable extends MaterialProgressDrawable {
// 旋转因子,调整旋转速度
private static final int ROTATION_FACTOR = 5*360;
// 加载时的动画
private Animation mAnimation;
private View mParent;
private Bitmap mBitmap ;
// 旋转角度
private float rotation;
private Paint paint;
public CustomProgressDrawable(View parent) {
super(parent);
mParent = parent;
paint = new Paint();
setupAnimation();
}
private void setupAnimation() {
// 初始化旋转动画
mAnimation = new Animation(){
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
setProgressRotation(-interpolatedTime);
}
};
mAnimation.setDuration(3000);
// 无限重复
mAnimation.setRepeatCount(Animation.INFINITE);
mAnimation.setRepeatMode(Animation.RESTART);
// 均匀转速
mAnimation.setInterpolator(new LinearInterpolator());
}
@Override
public void start() {
mParent.startAnimation(mAnimation);
}
public void setBitmap(Bitmap mBitmap) {
this.mBitmap = mBitmap;
}
@Override
public void setProgressRotation(float rotation) {
// 取负号是为了和微信保持一致,下拉时逆时针转加载时顺时针转,旋转因子是为了调整转的速度。
this.rotation = -rotation*ROTATION_FACTOR;
invalidateSelf();
}
@SuppressLint("ResourceAsColor")
@Override
public void draw(Canvas c) {
c.drawColor(android.R.color.black);
Rect bound = getBounds();
c.rotate(rotation,bound.exactCenterX(),bound.exactCenterY());
Rect src = new Rect(0,0,mBitmap.getWidth(),mBitmap.getHeight());
c.drawBitmap(mBitmap,src,bound,paint);
}
}
public class MyMaterialHeader extends SimpleComponent implements RefreshHeader {
// Maps to ProgressBar.Large style
public static final int SIZE_LARGE = 0;
// Maps to ProgressBar default style
public static final int SIZE_DEFAULT = 1;
protected static final int CIRCLE_BG_LIGHT = 0xFFFAFAFA;
protected static final float MAX_PROGRESS_ANGLE = .8f;
@VisibleForTesting
protected static final int CIRCLE_DIAMETER = 40;
@VisibleForTesting
protected static final int CIRCLE_DIAMETER_LARGE = 56;
protected boolean mFinished;
protected int mCircleDiameter;
protected MyCircleImageView mCircleView;
// protected MaterialProgressDrawable mProgress;
protected CustomProgressDrawable mProgress;
protected int mWaveHeight;
protected int mHeadHeight;
protected Path mBezierPath;
protected Paint mBezierPaint;
protected RefreshState mState;
protected boolean mShowBezierWave = false;
protected boolean mScrollableWhenRefreshing = true;
//
public MyMaterialHeader(Context context) {
this(context, null);
}
public MyMaterialHeader(Context context, AttributeSet attrs) {
super(context, attrs, 0);
mSpinnerStyle = SpinnerStyle.MatchLayout;
final View thisView = this;
final ViewGroup thisGroup = this;
thisView.setMinimumHeight(SmartUtil.dp2px(100));
// mProgress = new MaterialProgressDrawable(this);
mProgress = new CustomProgressDrawable(this);
mProgress.setBitmap(BitmapFactory.decodeResource(context.getResources(), R.drawable.rainbow_ic));
// mProgress.setBackgroundColor(CIRCLE_BG_LIGHT);
// mProgress.setAlpha(255);
// mProgress.setColorSchemeColors(0xff0099cc,0xffff4444,0xff669900,0xffaa66cc,0xffff8800);
// 这里上颜色是给图标上颜色
mCircleView = new MyCircleImageView(context, getResources().getColor(R.color.black));
mCircleView.setImageDrawable(mProgress);
// mCircleView.setAlpha(0f);
thisGroup.addView(mCircleView);
final DisplayMetrics metrics = thisView.getResources().getDisplayMetrics();
mCircleDiameter = (int) (CIRCLE_DIAMETER * metrics.density);
mBezierPath = new Path();
mBezierPaint = new Paint();
mBezierPaint.setAntiAlias(true);
mBezierPaint.setStyle(Paint.Style.FILL);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MaterialHeader);
mShowBezierWave = ta.getBoolean(R.styleable.MaterialHeader_srlShowBezierWave, mShowBezierWave);
mScrollableWhenRefreshing = ta.getBoolean(R.styleable.MaterialHeader_srlScrollableWhenRefreshing, mScrollableWhenRefreshing);
mBezierPaint.setColor(ta.getColor(R.styleable.MaterialHeader_srlPrimaryColor, 0xff11bbff));
if (ta.hasValue(R.styleable.MaterialHeader_srlShadowRadius)) {
int radius = ta.getDimensionPixelOffset(R.styleable.MaterialHeader_srlShadowRadius, 0);
int color = ta.getColor(R.styleable.MaterialHeader_mhShadowColor, 0xff000000);
mBezierPaint.setShadowLayer(radius, 0, 0, color);
thisView.setLayerType(LAYER_TYPE_SOFTWARE, null);
}
mShowBezierWave = ta.getBoolean(R.styleable.MaterialHeader_mhShowBezierWave, mShowBezierWave);
mScrollableWhenRefreshing = ta.getBoolean(R.styleable.MaterialHeader_mhScrollableWhenRefreshing, mScrollableWhenRefreshing);
if (ta.hasValue(R.styleable.MaterialHeader_mhPrimaryColor)) {
mBezierPaint.setColor(ta.getColor(R.styleable.MaterialHeader_mhPrimaryColor, 0xff11bbff));
}
if (ta.hasValue(R.styleable.MaterialHeader_mhShadowRadius)) {
int radius = ta.getDimensionPixelOffset(R.styleable.MaterialHeader_mhShadowRadius, 0);
int color = ta.getColor(R.styleable.MaterialHeader_mhShadowColor, 0xff000000);
mBezierPaint.setShadowLayer(radius, 0, 0, color);
thisView.setLayerType(LAYER_TYPE_SOFTWARE, null);
}
ta.recycle();
}
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.setMeasuredDimension(getSize(widthMeasureSpec), getSize(heightMeasureSpec));
final View circleView = mCircleView;
circleView.measure(MeasureSpec.makeMeasureSpec(mCircleDiameter, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(mCircleDiameter, MeasureSpec.EXACTLY));
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
final ViewGroup thisGroup = this;
if (thisGroup.getChildCount() == 0) {
return;
}
final View thisView = this;
final View circleView = mCircleView;
final int width = thisView.getMeasuredWidth();
int circleWidth = circleView.getMeasuredWidth();
int circleHeight = circleView.getMeasuredHeight();
if (thisView.isInEditMode() && mHeadHeight > 0) {
int circleTop = mHeadHeight - circleHeight / 2;
// circleView.layout((width / 2 - circleWidth / 2), circleTop,
// (width / 2 + circleWidth / 2), circleTop + circleHeight);
circleView.layout(100, circleTop,
circleWidth + 100, circleTop + circleHeight);
mProgress.showArrow(true);
mProgress.setStartEndTrim(0f, MAX_PROGRESS_ANGLE);
mProgress.setArrowScale(1);
circleView.setAlpha(1f);
circleView.setVisibility(VISIBLE);
} else {
// circleView.layout((width / 2 - circleWidth / 2), -circleHeight,
// (width / 2 + circleWidth / 2), 0);
circleView.layout(100, -circleHeight,
circleWidth + 100, 0);
}
}
@Override
protected void dispatchDraw(Canvas canvas) {
if (mShowBezierWave) {
//重置画笔
mBezierPath.reset();
mBezierPath.lineTo(0, mHeadHeight);
//绘制贝塞尔曲线
final View thisView = this;
mBezierPath.quadTo(thisView.getMeasuredWidth() / 2f, mHeadHeight + mWaveHeight * 1.9f, thisView.getMeasuredWidth(), mHeadHeight);
mBezierPath.lineTo(thisView.getMeasuredWidth(), 0);
canvas.drawPath(mBezierPath, mBezierPaint);
}
super.dispatchDraw(canvas);
}
//
//
@Override
public void onInitialized(@NonNull RefreshKernel kernel, int height, int maxDragHeight) {
final View thisView = this;
if (!mShowBezierWave) {
kernel.requestDefaultTranslationContentFor(this, false);
}
if (thisView.isInEditMode()) {
mWaveHeight = mHeadHeight = height / 2;
}
}
@Override
public void onMoving(boolean isDragging, float percent, int offset, int height, int maxDragHeight) {
if (mState == RefreshState.Refreshing) {
return;
}
if (mShowBezierWave) {
mHeadHeight = Math.min(offset, height);
mWaveHeight = Math.max(0, offset - height);
final View thisView = this;
thisView.postInvalidate();
}
if (isDragging || (!mProgress.isRunning() && !mFinished)) {
if (mState != RefreshState.Refreshing) {
float originalDragPercent = 1f * offset / height;
float dragPercent = Math.min(1f, Math.abs(originalDragPercent));
float adjustedPercent = (float) Math.max(dragPercent - .4, 0) * 5 / 3;
float extraOS = Math.abs(offset) - height;
float tensionSlingshotPercent = Math.max(0, Math.min(extraOS, (float) height * 2)
/ (float) height);
float tensionPercent = (float) ((tensionSlingshotPercent / 4) - Math.pow(
(tensionSlingshotPercent / 4), 2)) * 2f;
float strokeStart = adjustedPercent * .8f;
mProgress.showArrow(true);
mProgress.setStartEndTrim(0f, Math.min(MAX_PROGRESS_ANGLE, strokeStart));
mProgress.setArrowScale(Math.min(1f, adjustedPercent));
float rotation = (-0.25f + .4f * adjustedPercent + tensionPercent * 2) * .5f;
mProgress.setProgressRotation(rotation);
}
final View circleView = mCircleView;
float targetY = offset / 2f + mCircleDiameter * 3 / 4f;
// float targetY = offset / 2f + mCircleDiameter / 2f;
circleView.setTranslationY(Math.min(offset, targetY));
circleView.setAlpha(Math.min(1f, 4f * offset / mCircleDiameter));
}
}
@Override
public void onReleased(@NonNull RefreshLayout layout, int height, int maxDragHeight) {
mProgress.start();
}
@Override
public void onStateChanged(@NonNull RefreshLayout refreshLayout, @NonNull RefreshState oldState, @NonNull RefreshState newState) {
final View circleView = mCircleView;
mState = newState;
switch (newState) {
case None:
case ReleaseToRefresh:
case Refreshing:
break;
case PullDownToRefresh:
mFinished = false;
circleView.setVisibility(VISIBLE);
circleView.setTranslationY(0);
circleView.setScaleX(1);
circleView.setScaleY(1);
break;
}
}
@Override
public int onFinish(@NonNull RefreshLayout layout, boolean success) {
final View circleView = mCircleView;
mProgress.stop();
final int deltaY = -mCircleView.getBottom();
circleView.animate().setDuration(200).translationY(deltaY);
mFinished = true;
return 0;
}
@Override
@Deprecated
public void setPrimaryColors(@ColorInt int... colors) {
if (colors.length > 0) {
mBezierPaint.setColor(colors[0]);
}
}
//
//
public MyMaterialHeader setProgressBackgroundColorSchemeResource(@ColorRes int colorRes) {
final View thisView = this;
final Context context = thisView.getContext();
final int color = ContextCompat.getColor(context, colorRes);
setProgressBackgroundColorSchemeColor(color);
return this;
}
public MyMaterialHeader setProgressBackgroundColorSchemeColor(@ColorInt int color) {
final View circle = mCircleView;
circle.setBackgroundColor(color);
// mProgress.setBackgroundColor(color);
return this;
}
public MyMaterialHeader setColorSchemeColors(@ColorInt int... colors) {
mProgress.setColorSchemeColors(colors);
return this;
}
public MyMaterialHeader setColorSchemeResources(@ColorRes int... colorIds) {
final View thisView = this;
final Context context = thisView.getContext();
int[] colors = new int[colorIds.length];
for (int i = 0; i < colorIds.length; i++) {
colors[i] = ContextCompat.getColor(context, colorIds[i]);
}
return setColorSchemeColors(colors);
}
public MyMaterialHeader setSize(int size) {
if (size != SIZE_LARGE && size != SIZE_DEFAULT) {
return this;
}
final View thisView = this;
DisplayMetrics metrics = thisView.getResources().getDisplayMetrics();
if (size == SIZE_LARGE) {
mCircleDiameter = (int) (CIRCLE_DIAMETER_LARGE * metrics.density);
} else {
mCircleDiameter = (int) (CIRCLE_DIAMETER * metrics.density);
}
// force the bounds of the progress circle inside the circle view to
// update by setting it to null before updating its size and then
// re-setting it
mCircleView.setImageDrawable(null);
mProgress.updateSizes(size);
mCircleView.setImageDrawable(mProgress);
return this;
}
public MyMaterialHeader setShowBezierWave(boolean show) {
this.mShowBezierWave = show;
return this;
}
public MyMaterialHeader setScrollableWhenRefreshing(boolean scrollable) {
this.mScrollableWhenRefreshing = scrollable;
return this;
}
//
}
需要用到的图片
设置关掉回弹
//关掉回弹
mViewBinding.refresh.setEnableOverScrollBounce(false);



