如何为圆周围的视图设置动画? [英] How to animate a View around a circle?

查看:96
本文介绍了如何为圆周围的视图设置动画?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在圆周上设置一个无限移动动画,以使 View 如下图所示。如何实现此目的?



此视图可以是 TextView 或任何简单或复杂的视图。



我知道我可以将视图放入 ViewGroup 并设置旋转动画,但是我不想旋转视图,因为视图的方向很重要。



解决方案

我一无所知本地执行此操作,所以我认为您最好的方法是确定动画的路径(xy坐标)并创建 Handler 以重复 postDelayed 。处理程序触发的每次迭代都只会视图翻译到下一个位置



编辑:我已经创建了一个解决方案,并通过向左和向右移动以及围成一圈进行了测试。 / p>

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;

公共类ViewPathAnimator
{
public static final int DEFAULT_DELAY = 1000/10;
public static final int DEFAULT_FRAMESKIP = 3;

私有静态处理程序处理程序;
私有静态HashMap< Integer,PathRunnable> animationViews;

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)
{
animationViews = new HashMap<>();
}

if(handler == null)
{
handler = new Handler();
}

if(animatedViews.containsKey(view.hashCode()))
{
cancel(view);
}

PathRunnable runnable = new PathRunnable(view,path,delay,frameSkip);
animationViews.put(view.hashCode(),可运行);
handler.postDelayed(可运行,延迟);
}

public static void cancel(View view)
{
if(animatedViews!= null&& handler!= null)
{
PathRunnable任务= animationViews.get(view.hashCode());
if(task!= null)
{
handler.removeCallbacks(task);
animationViews.remove(view.hashCode());
}
}
}

私有静态类PathRunnable实现Runnable
{
private WeakReference< View>视图;
Pair< Float,Float> []点;
私人int延迟;
private int frameSkip;
私有int框架;

PathRunnable(查看视图,路径路径,int延迟,int frameSkip)
{
this.view = new WeakReference<<>(view);
this.points = getPoints(path);
this.delay =延迟;
this.frameSkip = Math.max(frameSkip,0);
this.frame = 0;
}

@Override
public void run()
{
frame =(frame + frameSkip + 1)%points.length;
Pair< Float,Float>对=点[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- android中的
私有对< Float,Float> [] getPoints(Path path)
{
PathMeasure pathMeasure = new PathMeasure(path,true);
int frame =(int)pathMeasure.getLength();

Pair< Float,Float> [] pointArray = new Pair [frame];
浮点长度= pathMeasure.getLength();
浮动距离= 0f;
浮点速度=长度/ pointArray.length;
int计数器= 0;
float [] aCoordinates = new float [2];

而((距离<长度)&&(计数器< pointArray.length))
{
//从路径
pathMeasure获取点.getPosTan(distance,aCoordinates,null);
pointArray [counter] = new Pair<<>(aCoordinates [0],aCoordinates [1]);
counter ++;
距离=距离+速度;
}

return pointArray;
}
}
}

现在可以给 Graphics 动画路径,像这样

 视图视图= findViewById( R.id.text); 
Path path = new Path();
path.addCircle(0,0,100,Path.Direction.CW);

ViewPathAnimator.animate(view,path,1000/30,2);


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 or any simple or complex view.

I know i can put my view in a ViewGroup and set a rotation animation, but i don't want to rotate the view because orientation of the view is important.

解决方案

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);

这篇关于如何为圆周围的视图设置动画?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆