directory
Use GestureDetector or VelocityTracker to gain speed
Initial property Settings for FlingAnimation
Initial property Settings for FlingAnimation
FlingAnimation animation configuration
Some key points of FlingAnimation
The sample code
FlingAnimation is a Fling effect animation, which is an inertial animation when the fingertips leave the screen. By setting an initial property value and a speed value, you can output a gradually decreasing property value. Finally, the minimum value, maximum value and minimum visible value are set as the stop condition. Note that the unit of speed is Pixel/second.
Use GestureDetector or VelocityTracker to gain speed
First, you can get the velocities VelocityX and VelocityY in the listener API from the monitor Fling action using GestureDetector, and use the FlingAnimation in the onFling callback, like this
public void init(a){
GestureDetector gestureDetector = new GestureDetector(this.new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
//TODO FlingAnimation here
//FlingAnimation fling = new FlingAnimation(target, DynamicAnimation.TRANSLATION_X);
//fling.setStartVelocity(velocityX)
// .start();
return false; }}); }@Override
public boolean onTouchEvent(MotionEvent event){
gestureDetector.onTouchEvent(event);
return super.onTouchEvent(event)
}
Copy the code
Or get the speed from VelocityTracker, like this
@Override
public boolean onTouchEvent(MotionEvent event) {
// Sliding speed
int index = event.getActionIndex();
int action = event.getActionMasked();
int pointerId = event.getPointerId(index);
switch (action){
case MotionEvent.ACTION_DOWN:
if(velocityTracker==null){
velocityTracker = VelocityTracker.obtain();
}else{
velocityTracker.clear();
}
velocityTracker.addMovement(event);
break;
case MotionEvent.ACTION_MOVE:
velocityTracker.addMovement(event);
velocityTracker.computeCurrentVelocity(1000);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
float velocityX = velocityTracker.getXVelocity(pointerId);
float velocityY = velocityTracker.getYVelocity(pointerId);
//TODO FlingAnimation here
//FlingAnimation fling = new FlingAnimation(target, DynamicAnimation.TRANSLATION_X);
//fling.setStartVelocity(velocityX)
// .start();
velocityTracker.recycle();
velocityTracker=null;
break;
}
gestureDetectorCompat.onTouchEvent(event);
return true;
}
Copy the code
Initial property Settings for FlingAnimation
The Fling animation has an initial speed value and an initial attribute. If the other attributes have default values, you can not set them.
The initial property, getValue of FloatPropertyCompat is where FlingAnimation gets the initial property value, and setValue is the callback for FlingAnimation to set the property value after the animation. The properties are as follows
FlingAnimation fling = new FlingAnimation(target, new FloatPropertyCompat<View>(AStrName) {
@Override
public float getValue(View object) {
// Return the change to implement
// For example, target.gettranslationX () is the translationx distance of the current target
return startValue;
}
@Override
public void setValue(View object, float value) {
// Change the attribute value based on startValue
Target.settranslationx (value);}});Copy the code
In fact, Google has already written in DynamicAnimation a number of common FloatProperty properties that can be used directly, for example
public abstract class DynamicAnimation<T extends DynamicAnimation<T>>
implements AnimationHandler.AnimationFrameCallback {
public abstract static class ViewProperty extends FloatPropertyCompat<View> {
private ViewProperty(String name) {
super(name); }}public static final ViewProperty TRANSLATION_X = new ViewProperty("translationX") {
@Override
public void setValue(View view, float value) {
view.setTranslationX(value);
}
@Override
public float getValue(View view) {
returnview.getTranslationX(); }}; ./** * View's translationX property. */
public static final ViewProperty TRANSLATION_X = new ViewProperty("translationX") {.../** * View's translationY property. */
public static final ViewProperty TRANSLATION_Y = new ViewProperty("translationY") {.../** * View's translationZ property. */
public static final ViewProperty TRANSLATION_Z = new ViewProperty("translationZ") {.../** * View's scaleX property. */
public static final ViewProperty SCALE_X = new ViewProperty("scaleX") {.../** * View's scaleY property. */
public static final ViewProperty SCALE_Y = new ViewProperty("scaleY") {.../** * View's rotation property. */
public static final ViewProperty ROTATION = new ViewProperty("rotation") {.../** * View's rotationX property. */
public static final ViewProperty ROTATION_X = new ViewProperty("rotationX") {.../** * View's rotationY property. */
public static final ViewProperty ROTATION_Y = new ViewProperty("rotationY") {.../** * View's x property. */
public static final ViewProperty X = new ViewProperty("x") {
/** * View's y property. */
public static final ViewProperty Y = new ViewProperty("y") {.../** * View's z property. */
public static final ViewProperty Z = new ViewProperty("z") {.../** * View's alpha property. */
public static final ViewProperty ALPHA = new ViewProperty("alpha") {...// Properties below are not RenderThread compatible
/** * View's scrollX property. */
public static final ViewProperty SCROLL_X = new ViewProperty("scrollX") {.../** * View's scrollY property. */
public static final ViewProperty SCROLL_Y = new ViewProperty("scrollY") {...Copy the code
FlingAnimation animation configuration
flingAnimation.setStartVelocity(velocityX)// Initial velocity
.setStartValue(target.getTranslationX())// The initial value, which overrides the getValue in propety
.setMinValue(target.getTranslationX()-500)// The animation stops when the value reaches the minimum
.setMaxValue(target.getTranslationX()+500)// The animation stops when the value reaches its maximum
.setMinimumVisibleChange(100)// Reach the minimum change visible, which is used to determine if it is still, and then stop the animation
.setFriction(1f)// The greater the friction, the faster the static
.addEndListener(endListener)// Animation status update
.addUpdateListener(updateListener)// Update the animation values
.start();/ / start
Copy the code
Some key points of FlingAnimation
- FlingAnimation. SetStartValue (target. GetTranslationX ()) / / initial value, setting the getValue will cover FloatPropertyCompat value here
- FlingAnimation. AddUpdateListener (updateListener)/update/animation values, in FloatPropertyCompat setValue value, you can see in DynamicAnimation source code
/**DynamicAnimation * Updates the property value through the corresponding setter. */
void setPropertyValue(float value) {
mProperty.setValue(mTarget, value);
for (int i = 0; i < mUpdateListeners.size(); i++) {
if(mUpdateListeners.get(i) ! =null) {
mUpdateListeners.get(i).onAnimationUpdate(this, mValue, mVelocity);
}
}
removeNullEntries(mUpdateListeners);
}
Copy the code
The sample code
package com.gyso.developerapplication.touchAndinput;
import androidx.appcompat.app.AppCompatActivity;
import androidx.dynamicanimation.animation.DynamicAnimation;
import androidx.dynamicanimation.animation.FlingAnimation;
import androidx.dynamicanimation.animation.FloatPropertyCompat;
import android.graphics.PointF;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.TextView;
import com.gyso.developerapplication.databinding.ActivityFlingBinding;
public class FlingActivity extends AppCompatActivity {
private static final String TAG = FlingActivity.class.getSimpleName();
TextView target;
PointF deltaMove = new PointF();
VelocityTracker velocityTracker;
private FlingAnimation flingX;
private FlingAnimation flingY;
private float minFlingVelocity;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityFlingBinding binding = ActivityFlingBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
target = binding.flingTestTv;
ViewConfiguration vc = ViewConfiguration.get(this);
minFlingVelocity = vc.getScaledMinimumFlingVelocity();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// Sliding speed
int index = event.getActionIndex();
int action = event.getActionMasked();
int pointerId = event.getPointerId(index);
switch (action){
case MotionEvent.ACTION_DOWN:
if(flingX! =null){
flingX.cancel();
}
if(flingY! =null){
flingY.cancel();
}
if(velocityTracker==null){
velocityTracker = VelocityTracker.obtain();
}else{
velocityTracker.clear();
}
velocityTracker.addMovement(event);
break;
case MotionEvent.ACTION_MOVE:
// Follow the finger
float distanceX = event.getRawX() - deltaMove.x;
float distanceY = event.getRawY() - deltaMove.y;
target.setTranslationX(target.getTranslationX()+distanceX);
target.setTranslationY(target.getTranslationY()+distanceY);
// Speed calculation
velocityTracker.addMovement(event);
velocityTracker.computeCurrentVelocity(1000);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
float velocityX = velocityTracker.getXVelocity(pointerId);
float velocityY = velocityTracker.getYVelocity(pointerId);
//TODO FlingAnimation
startFlingAnimation(velocityX,velocityY);
//startSampleFlingAnimation(velocityX, velocityY)
velocityTracker.recycle();
velocityTracker=null;
break;
}
deltaMove.set(event.getRawX(),event.getRawY());
return true;
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
return this.onTouchEvent(ev);
}
/**
* sample fling animation
* @param velocityX vx
* @param velocityY vy
*/
public void startSampleFlingAnimation(float velocityX, float velocityY){
new FlingAnimation(target, DynamicAnimation.TRANSLATION_X)
.setStartVelocity(velocityX)
.start();
new FlingAnimation(target, DynamicAnimation.TRANSLATION_Y)
.setStartVelocity(velocityY)
.start();
}
/**
* start fling animation
* @param velocityX vx
* @param velocityY vy
*/
public void startFlingAnimation(float velocityX, float velocityY) {
if(flingX! =null){
flingX.cancel();
}
if(flingY! =null){
flingY.cancel();
}
flingX = new FlingAnimation(target, new FloatPropertyCompat<View>("") {
@Override
public float getValue(View object) {
return target.getTranslationX();
}
@Override
public void setValue(View object, float value) { target.setTranslationX(value); }}); flingX.setStartVelocity(velocityX) .addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() {
@Override
public void onAnimationUpdate(DynamicAnimation animation, float value, float velocity) {
float leftNow = target.getLeft()+target.getTranslationX();
float right = target.getLeft()+target.getWidth()+target.getTranslationX();
boolean leftBounce = leftNow<0 && velocity<0 ;
boolean rightBounce = right >((View)target.getParent()).getRight() && velocity>0;
if(leftBounce || rightBounce){
flingX.setStartVelocity(-velocity);
}
}
})
.start();
flingY = new FlingAnimation(target, new FloatPropertyCompat<View>("") {
@Override
public float getValue(View object) {
return object.getTranslationY();
}
@Override
public void setValue(View object, float value) { object.setTranslationY(value); }}); flingY.setStartVelocity(velocityY) .addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() {
@Override
public void onAnimationUpdate(DynamicAnimation animation, float value, float velocity) {
float topNow = target.getTop()+target.getTranslationY();
float bottomNow = target.getTop()+target.getHeight()+target.getTranslationY();
boolean topBounce = topNow<0 && velocity<0;
boolean bottomBounce = bottomNow >((View)target.getParent()).getBottom() && velocity>0;
if(topBounce || bottomBounce){ flingY.setStartVelocity(-velocity); } } }) .start(); }}Copy the code