android - 如何在android中的 Canvas 上应用线条的旋转动画

标签 android xamarin xamarin.android

我已经完成了它的工作代码,但问题是每当我改变旋转角度时,它总是从第一个点开始,而不是从上次旋转结束的点开始。

我想要这样的动画。 https://drive.google.com/file/d/1Qx0MBu-77JIlQTByqGTyD-KtGKOB8naG/view?usp=sharing

我用canvas画了圆和线。我用了viewpager。如果我滑动 viewpager,饼图就会旋转

到目前为止我做了什么。动画时总是从零开始:https://drive.google.com/file/d/12mmAUOeY77jAlj_GmM3Ymcx5m34vli3X/view?usp=sharing 我已经完成了以下代码:

public class PieView : View
{
    int w, h, pl, pr, pt, pb, usableWidth, usableHeight, radius, cx, cy, 
    lineLenght;
    Paint paint;
    public Canvas canvas;
    public float firstLineangle = 0;
    public float secondLineangle = 40;
    public float thirdLineangle = 120;
    float currentAngle,maxAngle;

    public override void Draw(Canvas canvas)
    {
        base.Draw(canvas);
        w = Width;
        h = Height;
        pl = PaddingLeft;
        pr = PaddingRight;
        pt = PaddingTop;
        pb = PaddingBottom;
        this.canvas = canvas;
        usableWidth = w - (pl + pr);
        usableHeight = h - (pt + pb);

        radius = Math.Min(usableWidth, usableHeight) / 2;
        cx = pl + (usableWidth / 2);
        cy = pt + (usableHeight / 2);

        lineLenght = radius - (pl * 2) - (pr * 2);
        paint = new Paint();
        paint.Color = Android.Graphics.Color.White;
        paint.SetStyle(Paint.Style.Stroke);
        paint.StrokeWidth = 5;
        canvas.DrawCircle(cx, cy, radius - 5, paint);

        Drawline(canvas, firstLineangle);
        Drawline(canvas, secondLineangle);
        Drawline(canvas, thirdLineangle);

        PostInvalidateDelayed(500);
        Invalidate();
    }

    public void Drawline(Canvas canvas, float angle)
    {
        float displacedAngle = angle - 90;
        float x = cx + ((float)Math.Cos(degreesToRadians(displacedAngle)) * (radius - 5)); //convert angle to radians for x and y coordinates
        float y = cy + ((float)Math.Sin(degreesToRadians(displacedAngle)) * (radius - 5));
        canvas.DrawLine(cx, cy, x, y, paint); //draw a line from center point back to the point
    }

    public double degreesToRadians(double degrees)
    {
        return (degrees * Math.PI) / 180;
    }
}

public class PieAnimation  : Android.Views.Animations.Animation
{
    private PieView pieView;

    private float firstLineangle;
    private float secondLineangle;
    private float thirdLineangle;

    public PieAnimation(PieView pieView, float firstLineangle,float secondLineangle,float thirdLineangle)
    {
        this.pieView = pieView;
        this.firstLineangle = firstLineangle;
        this.secondLineangle = secondLineangle;
        this.thirdLineangle = thirdLineangle;
    }

    protected override void ApplyTransformation(float interpolatedTime, Transformation t)
    {
        pieView.firstLineangle = 0 + ((firstLineangle) * interpolatedTime);
        pieView.secondLineangle = 0 + ((secondLineangle) * interpolatedTime);
        pieView.thirdLineangle = 0 + ((thirdLineangle) * interpolatedTime);
        pieView.RequestLayout();
    }
}

public class TourPager : Java.Lang.Object, ViewPager.IOnPageChangeListener, ViewPager.IPageTransformer
{

    private ViewPager mViewPager;

    private float mLastOffset;
    public TourView _context;

    public TourPager(ViewPager viewpager, TourView context)
    {
        mViewPager = viewpager;
        viewpager.AddOnPageChangeListener(this);
        _context = context;
    }

    public void OnPageSelected(int position)
    {

        if (position == 0)
        {
            PieAnimation animation = new PieAnimation(_context._pieView, 0, 40, 120);
            animation.Duration = (1000);
            _context._pieView.StartAnimation(animation);
        }
        if (position==1)
        {
            PieAnimation animation = new PieAnimation(_context._pieView, 100, 140, 200);
            animation.Duration=(1000);
            _context._pieView.StartAnimation(animation);
        }
        if(position==2)
        {
            PieAnimation animation = new PieAnimation(_context._pieView, 180, 270, 10);
            animation.Duration = (1000);
            _context._pieView.StartAnimation(animation);
        }
   }

最佳答案

我更新了 PieView 类,使其可以使用 SaveCurrentAngles() 函数保存当前角度。 PieAnimation 构造函数调用此函数来保存上一个动画结束时的角度(如果有的话)。我还更新了 PieAnimationApplyTransformation() 函数以进行准确计算。这样,即使您将直接目标角度作为动画的参数,您也应该能够实现累积动画。这是更新后的代码:

public class PieView : View
{
    int w, h, pl, pr, pt, pb, usableWidth, usableHeight, radius, cx, cy, lineLenght;
    Paint paint;
    public Canvas canvas;
    public float prevFirstLineAngle = 0;
    public float prevSecondLineAngle = 0;
    public float prevThirdLineAngle = 0;
    public float firstLineAngle = 0;
    public float secondLineAngle = 40;
    public float thirdLineAngle = 120;
    float currentAngle, maxAngle;

    public override void Draw(Canvas canvas)
    {
        base.Draw(canvas);
        w = Width;
        h = Height;
        pl = PaddingLeft;
        pr = PaddingRight;
        pt = PaddingTop;
        pb = PaddingBottom;
        this.canvas = canvas;
        usableWidth = w - (pl + pr);
        usableHeight = h - (pt + pb);

        radius = Math.Min(usableWidth, usableHeight) / 2;
        cx = pl + (usableWidth / 2);
        cy = pt + (usableHeight / 2);

        lineLenght = radius - (pl * 2) - (pr * 2);
        paint = new Paint();
        paint.Color = Android.Graphics.Color.White;
        paint.SetStyle(Paint.Style.Stroke);
        paint.StrokeWidth = 5;
        canvas.DrawCircle(cx, cy, radius - 5, paint);

        Drawline(canvas, firstLineAngle);
        Drawline(canvas, secondLineAngle);
        Drawline(canvas, thirdLineAngle);

        PostInvalidateDelayed(500);
        Invalidate();
    }

    public void SaveCurrentAngles()
    {
        prevFirstLineAngle = this.firstLineAngle;
        prevSecondLineAngle = this.secondLineAngle;
        prevThirdLineAngle = this.thirdLineAngle;
    }

    public void Drawline(Canvas canvas, float angle)
    {
        float displacedAngle = angle - 90;
        float x = cx + ((float)Math.Cos(degreesToRadians(displacedAngle)) * (radius - 5)); //convert angle to radians for x and y coordinates
        float y = cy + ((float)Math.Sin(degreesToRadians(displacedAngle)) * (radius - 5));
        canvas.DrawLine(cx, cy, x, y, paint); //draw a line from center point back to the point
    }

    public double degreesToRadians(double degrees)
    {
        return (degrees * Math.PI) / 180;
    }
}

public class PieAnimation  : Android.Views.Animations.Animation
{
    private PieView pieView;

    private float firstLineAngle;
    private float secondLineAngle;
    private float thirdLineAngle;

    public PieAnimation(PieView pieView, float firstLineAngle, float secondLineAngle, float thirdLineAngle)
    {
        this.pieView = pieView;
        pieView.saveCurrentAngles();
        this.firstLineAngle = firstLineAngle;
        this.secondLineAngle = secondLineAngle;
        this.thirdLineAngle = thirdLineAngle;
    }

    protected override void ApplyTransformation(float interpolatedTime, Transformation t)
    {
        pieView.firstLineAngle = pieView.prevFirstLineAngle +
                ((firstLineangle - pieView.prevFirstLineAngle) * interpolatedTime);
        pieView.secondLineAngle = pieView.prevSecondLineAngle +
                ((secondLineangle - pieView.prevSecondLineAngle) * interpolatedTime);
        pieView.thirdLineAngle = pieView.prevThirdLineAngle +
                ((thirdLineangle - pieView.prevThirdLineAngle) * interpolatedTime);
        pieView.RequestLayout();
    }
}

public class TourPager : Java.Lang.Object, ViewPager.IOnPageChangeListener, ViewPager.IPageTransformer
{
    private ViewPager mViewPager;

    private float mLastOffset;
    public TourView _context;

    public TourPager(ViewPager viewpager, TourView context)
    {
        mViewPager = viewpager;
        viewpager.AddOnPageChangeListener(this);
        _context = context;
    }

    public void OnPageSelected(int position)
    {
        if (position == 0)
        {
            PieAnimation animation = new PieAnimation(_context._pieView, 0, 40, 120);
            animation.Duration = (1000);
            _context._pieView.StartAnimation(animation);
        }
        if (position==1)
        {
            PieAnimation animation = new PieAnimation(_context._pieView, 100, 140, 200);
            animation.Duration=(1000);
            _context._pieView.StartAnimation(animation);
        }
        if(position==2)
        {
            PieAnimation animation = new PieAnimation(_context._pieView, 180, 270, 10);
            animation.Duration = (1000);
            _context._pieView.StartAnimation(animation);
        }
    }
}

关于android - 如何在android中的 Canvas 上应用线条的旋转动画,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56280934/

相关文章:

java - 无静态方法 'getContext()' 无法从静态上下文中引用

ios - Xamarin/IOS/Azure - 在类型上找不到 'id' 成员

json - 如何序列化以在 F# 上使用 JSON.NET 进行流式传输?

c# - Unity List.Add 阻止 Android 上的 Sprite 更新

Java/Android 自动解析泛型类型。寻求逐步指导以了解

xamarin - 当前命名空间中不存在类型或命名空间 'App'

ios - 发出本地警报通知

xamarin - System.Data.SQLite 和 sqlite-net-pcl 的区别

c# - 拉动刷新在使用 Xamarin Forms 构建的 Android 中的 ListView 上不起作用

java - 使文本变大和变小