package com.juhabi.birds.custom; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.annotation.SuppressLint; import android.content.Context; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.view.animation.DecelerateInterpolator; import android.view.animation.LinearInterpolator; import android.widget.ImageView; import android.widget.RelativeLayout; import androidx.annotation.ColorInt; import androidx.annotation.NonNull; import com.juhabi.birds.R; import com.scwang.smart.refresh.layout.api.RefreshHeader; import com.scwang.smart.refresh.layout.api.RefreshKernel; import com.scwang.smart.refresh.layout.api.RefreshLayout; import com.scwang.smart.refresh.layout.constant.RefreshState; import com.scwang.smart.refresh.layout.constant.SpinnerStyle; /** * @author fengxiaoyang * @date 2025/7/11 * @description TODO: 描述该类的作用 */ public class CustomRefreshHeader extends RelativeLayout implements RefreshHeader { private ImageView ivRefresh; private ObjectAnimator rotateAnimator; // 用于 onMoving 中的动态效果 private float mLastPercent = 0f; // 记录当前缩放值,避免重复设置 private float mCurrentScale = 1f; public CustomRefreshHeader(Context context) { super(context); init(context); } public CustomRefreshHeader(Context context, AttributeSet attrs) { super(context, attrs); init(context); } private void init(Context context) { LayoutInflater.from(context).inflate(R.layout.view_refresh_header, this); ivRefresh = findViewById(R.id.ivRefresh); // 开启硬件加速,提升动画性能 setLayerType(LAYER_TYPE_HARDWARE, null); // 初始化 ObjectAnimator rotateAnimator = ObjectAnimator.ofFloat(ivRefresh, "rotation", 0f, 360f); rotateAnimator.setDuration(1500); rotateAnimator.setRepeatCount(ValueAnimator.INFINITE); rotateAnimator.setInterpolator(new LinearInterpolator()); } @NonNull @Override public View getView() { return this; } @SuppressLint("RestrictedApi") @Override public void onStartAnimator(@NonNull RefreshLayout layout, int height, int maxDragHeight) { if (rotateAnimator != null && !rotateAnimator.isRunning()) { rotateAnimator.start(); } } @SuppressLint("RestrictedApi") @Override public int onFinish(@NonNull RefreshLayout layout, boolean success) { if (rotateAnimator != null && rotateAnimator.isRunning()) { rotateAnimator.setInterpolator(new DecelerateInterpolator()); postDelayed(() -> { if (rotateAnimator != null) { rotateAnimator.cancel(); rotateAnimator.setInterpolator(new LinearInterpolator()); } }, 300); } // 动画过渡回正常大小 animateToNormalScale(); return 500; } /** * 平滑动画过渡回正常大小 */ private void animateToNormalScale() { if (ivRefresh == null) return; float startScale = mCurrentScale; ValueAnimator scaleAnimator = ValueAnimator.ofFloat(startScale, 1f); scaleAnimator.setDuration(300); scaleAnimator.setInterpolator(new DecelerateInterpolator()); scaleAnimator.addUpdateListener(animation -> { float value = (float) animation.getAnimatedValue(); ivRefresh.setScaleX(value); ivRefresh.setScaleY(value); mCurrentScale = value; }); scaleAnimator.start(); } // --- 必须实现的方法 --- @NonNull @Override public SpinnerStyle getSpinnerStyle() { return SpinnerStyle.Translate; // Header 跟随内容滑动 } @Override public boolean isSupportHorizontalDrag() { return false; } @SuppressLint("RestrictedApi") @Override public void setPrimaryColors(@ColorInt int... colors) {} @SuppressLint("RestrictedApi") @Override public void onInitialized(@NonNull RefreshKernel kernel, int height, int maxDragHeight) {} @SuppressLint("RestrictedApi") @Override public void onMoving(boolean isDragging, float percent, int offset, int height, int maxDragHeight) { // 只在拖动过程中处理,避免过度计算 if (percent != mLastPercent) { mLastPercent = percent; // 1. 动态缩放效果:从 0.5 放大到 1.2 // 使用 clamp 限制范围:percent 0~1 -> scale 0.5~1.2 float targetScale = 0.5f + (0.7f * Math.min(percent, 1.0f)); if (Math.abs(targetScale - mCurrentScale) > 0.01f) { mCurrentScale = targetScale; ivRefresh.setScaleX(targetScale); ivRefresh.setScaleY(targetScale); } // 2. 透明度渐变效果(可选) // ivRefresh.setAlpha(Math.min(percent * 1.5f, 1.0f)); } } @SuppressLint("RestrictedApi") @Override public void onReleased(@NonNull RefreshLayout layout, int height, int maxDragHeight) {} @SuppressLint("RestrictedApi") @Override public void onHorizontalDrag(float percentX, int offsetX, int offsetMax) {} @Override public boolean autoOpen(int duration, float dragRate, boolean animationOnly) { return false; } @SuppressLint("RestrictedApi") @Override public void onStateChanged(@NonNull RefreshLayout refreshLayout, @NonNull RefreshState oldState, @NonNull RefreshState newState) { // 状态切换时平滑恢复 if (newState == RefreshState.PullDownCanceled) { // 用户取消下拉,恢复到初始状态 animateToNormalScale(); } } }