Skip to content

Instantly share code, notes, and snippets.

@LeoAndo
Created October 11, 2023 09:33
Show Gist options
  • Save LeoAndo/1630ce19e6c813f01f94dc558c4e3b22 to your computer and use it in GitHub Desktop.
Save LeoAndo/1630ce19e6c813f01f94dc558c4e3b22 to your computer and use it in GitHub Desktop.
[Android] Springアニメーション用のImageView
package xxxx; // TODO パッケージ名は自分の環境に合わせてください
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatImageView;
import androidx.dynamicanimation.animation.DynamicAnimation;
import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
import java.util.concurrent.atomic.AtomicReference;
public class SpringImageView extends AppCompatImageView {
private static final String TAG = "SpringImageView";
private SpringAnimation xAnim;
private SpringAnimation yAnim;
private static final float STIFFNESS = SpringForce.STIFFNESS_LOW;
private static final float DAMPING_RATIO = SpringForce.DAMPING_RATIO_HIGH_BOUNCY;
private OnSpringAnimationListener listener;
public SpringImageView(@NonNull final Context context, @Nullable final AttributeSet attrs) {
this(context, attrs, 0);
}
@SuppressLint("ClickableViewAccessibility")
public SpringImageView(@NonNull final Context context, @Nullable final AttributeSet attrs, final int defStyleAttr) {
super(context, attrs, defStyleAttr);
final AppCompatImageView img = this;
// ビューの初期位置が確定したら、X軸およびY軸アニメーションを作成する
getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
xAnim = createSpringAnimation(
img, SpringAnimation.X, img.getX(), STIFFNESS, DAMPING_RATIO);
yAnim = createSpringAnimation(
img, SpringAnimation.Y, img.getY(), STIFFNESS, DAMPING_RATIO);
img.getViewTreeObserver().removeOnGlobalLayoutListener(this);
// Registering the update listener
xAnim.addEndListener((animation, canceled, value, velocity) -> {
Log.d(TAG, "canceled: " + canceled + " value: " + value + " velocity: " + velocity);
if (listener != null) {
listener.onAnimationEnd(canceled);
}
});
}
});
final AtomicReference<Float> dX = new AtomicReference<>(0.0f);
final AtomicReference<Float> dY = new AtomicReference<>(0.0f);
this.setOnTouchListener((view, event) -> {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
// ビューの左上隅とタッチポイントの差をキャプチャする
dX.set(view.getX() - event.getRawX());
dY.set(view.getY() - event.getRawY());
// アニメーションをキャンセルして、前のアニメーション中にビューを取得できるようにする
xAnim.cancel();
yAnim.cancel();
break;
case MotionEvent.ACTION_MOVE:
// ViewのLayoutParamsを変更する.
img.animate()
.x(event.getRawX() + dX.get())
.y(event.getRawY() + dY.get())
.setDuration(0)
.start();
break;
case MotionEvent.ACTION_UP:
xAnim.start();
yAnim.start();
break;
}
return true;
});
}
/**
* Springアニメーションのイベントリスナー登録
*
* @param listener Springアニメーションのイベントリスナー {@link OnSpringAnimationListener}
*/
public void setOnSpringAnimationListener(final OnSpringAnimationListener listener) {
this.listener = listener;
}
/**
* Springアニメーションのイベントをフックするためのリスナー
*/
public interface OnSpringAnimationListener {
/**
* アニメーションが終了したときに呼ばれる
*
* @param canceled true: アニメーションがキャンセルされた
*/
void onAnimationEnd(final boolean canceled);
}
/**
* Springアニメーション(バネ)の生成
*
* @param view アニメーションされるView
* @param property {@link DynamicAnimation.ViewProperty} を指定する
* @param finalPosition スプリングの最終位置. これは、アニメーションの開始前に設定する必要がある。
* @param stiffness ばねの非負の剛性定数
* @param dampingRatio ばねの減衰比、非負でなければいけない(0.0以上を指定すること)
* @return {@link SpringAnimation}インスタンス
*/
private SpringAnimation createSpringAnimation(
@NonNull final View view,
@NonNull final DynamicAnimation.ViewProperty property,
final float finalPosition,
final float stiffness,
final float dampingRatio) {
final SpringAnimation animation = new SpringAnimation(view, property);
final SpringForce spring = new SpringForce(finalPosition);
spring.setStiffness(stiffness);
spring.setDampingRatio(dampingRatio);
animation.setSpring(spring);
return animation;
}
}
@LeoAndo
Copy link
Author

LeoAndo commented Oct 11, 2023

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment