How to animate a View around a circle?

前端 未结 3 1774
生来不讨喜
生来不讨喜 2020-12-29 15:11

I want to set an infinite move animation around a circle to a View like picture below.How can i achieve this?

This View may be a TextView o

相关标签:
3条回答
  • 2020-12-29 15:38

    I am not aware of anything to natively do this, so I think your best approach here would be to determine the path of your animation (the xy coordinates) and create a Handler to repeatedly postDelayed. Each iteration of your handler firing will just translate the view to its next point in the path.

    Edit: I've create a solution and tested it with both moving right and left, and moving in a circle.

    ViewPathAnimator.java:

    import android.graphics.Path;
    import android.graphics.PathMeasure;
    import android.os.Handler;
    import android.util.Pair;
    import android.view.View;
    
    import java.lang.ref.WeakReference;
    import java.util.HashMap;
    
    public class ViewPathAnimator
    {
        public static final int DEFAULT_DELAY     = 1000 / 10;
        public static final int DEFAULT_FRAMESKIP = 3;
    
        private static Handler                        handler;
        private static HashMap<Integer, PathRunnable> animatedViews;
    
        public static void animate(View view, Path path)
        {
            animate(view, path, DEFAULT_DELAY, DEFAULT_FRAMESKIP);
        }
    
        public static void animate(View view, Path path, int delay)
        {
            animate(view, path, delay, DEFAULT_FRAMESKIP);
        }
    
        public static void animate(View view, Path path, int delay, int frameSkip)
        {
            if (animatedViews == null)
            {
                animatedViews = new HashMap<>();
            }
    
            if (handler == null)
            {
                handler = new Handler();
            }
    
            if (animatedViews.containsKey(view.hashCode()))
            {
                cancel(view);
            }
    
            PathRunnable runnable = new PathRunnable(view, path, delay, frameSkip);
            animatedViews.put(view.hashCode(), runnable);
            handler.postDelayed(runnable, delay);
        }
    
        public static void cancel(View view)
        {
            if (animatedViews != null && handler != null)
            {
                PathRunnable task = animatedViews.get(view.hashCode());
                if (task != null)
                {
                    handler.removeCallbacks(task);
                    animatedViews.remove(view.hashCode());
                }
            }
        }
    
        private static class PathRunnable implements Runnable
        {
            private WeakReference<View> view;
            Pair<Float, Float>[] points;
            private int delay;
            private int frameSkip;
            private int frame;
    
            PathRunnable(View view, Path path, int delay, int frameSkip)
            {
                this.view = new WeakReference<>(view);
                this.points = getPoints(path);
                this.delay = delay;
                this.frameSkip = Math.max(frameSkip, 0);
                this.frame = 0;
            }
    
            @Override
            public void run()
            {
                frame = (frame + frameSkip + 1) % points.length;
                Pair<Float, Float> pair = points[frame];
    
                View v = view.get();
                if (v != null)
                {
                    v.setTranslationX(pair.first);
                    v.setTranslationY(pair.second);
    
                    handler.postDelayed(this, delay);
                }
            }
    
            // https://stackoverflow.com/questions/7972780/how-do-i-find-all-the-points-in-a-path-in-android
            private Pair<Float, Float>[] getPoints(Path path)
            {
                PathMeasure pathMeasure = new PathMeasure(path, true);
                int         frames      = (int) pathMeasure.getLength();
    
                Pair<Float, Float>[] pointArray   = new Pair[frames];
                float                length       = pathMeasure.getLength();
                float                distance     = 0f;
                float                speed        = length / pointArray.length;
                int                  counter      = 0;
                float[]              aCoordinates = new float[2];
    
                while ((distance < length) && (counter < pointArray.length))
                {
                    // get point from the path
                    pathMeasure.getPosTan(distance, aCoordinates, null);
                    pointArray[counter] = new Pair<>(aCoordinates[0], aCoordinates[1]);
                    counter++;
                    distance = distance + speed;
                }
    
                return pointArray;
            }
        }
    }
    

    This can now be given a Graphics path to animate along, like this

    View view = findViewById(R.id.text);
    Path path = new Path();
    path.addCircle(0, 0, 100, Path.Direction.CW);
    
    ViewPathAnimator.animate(view, path, 1000/ 30, 2);
    
    0 讨论(0)
  • 2020-12-29 15:42

    The problem is solved with this solution i made that rotate the container of the view clockwise and the TextView counter clockwise :)

    The layout:

    <RelativeLayout
        android:id="@+id/cont"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="150dp"
        android:animateLayoutChanges="true"
        android:clipChildren="false">
    
        <TextView
            android:id="@+id/text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:text="M"
            android:textSize="60sp"/>
    </RelativeLayout>
    

    The animation:

        View v = findViewById(R.id.cont);
        View text = findViewById(R.id.text);
    
        int durationMillis = 10000;
    
        RotateAnimation r = new RotateAnimation(0, 360,
                Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        r.setDuration(durationMillis);
        r.setInterpolator(new LinearInterpolator());
        r.setRepeatMode(Animation.RESTART);
        r.setRepeatCount(Animation.INFINITE);
        text.startAnimation(r);
    
        RotateAnimation rC = new RotateAnimation(360, 0,
                Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        rC.setDuration(durationMillis);
        rC.setInterpolator(new LinearInterpolator());
        rC.setRepeatMode(Animation.RESTART);
        rC.setRepeatCount(Animation.INFINITE);
        v.startAnimation(rC);
    

    But if you want to move an object in other paths and looking for a general solution, checkout the @Kevin's solution(Thanks to him).

    0 讨论(0)
  • 2020-12-29 15:49

    may be ValueAnimator can help?according to the progress it anim,you can compute your path's coordinate and set it to your view?

    0 讨论(0)
提交回复
热议问题