Created
October 11, 2023 09:33
-
-
Save LeoAndo/1630ce19e6c813f01f94dc558c4e3b22 to your computer and use it in GitHub Desktop.
[Android] Springアニメーション用のImageView
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
参考文献
https://developer.android.com/guide/topics/graphics/spring-animation?hl=ja