美文网首页
用ValueAnimator绘制sin函数

用ValueAnimator绘制sin函数

作者: hliman | 来源:发表于2016-10-12 16:56 被阅读172次

    最近看到了一个贝塞尔曲线的示例,感觉一点一点绘制挺好的,想到了中学的时候老师在黑板上画sin函数的画面,想到也写这么一个程序模拟画一下,效果如下

    sin.gif

    我用的是ValueAnimator来实现这个这个变化的过程,下面是它部分的api

    ofFloat(float... values)
    Constructs and returns a ValueAnimator that animates between float values.
    构建并返回一个ValueAnimator动画之间的float值。
    
    setDuration(long duration)
    Sets the length of the animation.
    设置动画时间 以毫秒为单位
    
    setRepeatCount(int value)
    Sets how many times the animation should be repeated.
    设置动画重复次数,如果为 ValueAnimator.INFINITE 即-1则为无数次
    
    setRepeatMode(int value)
    Defines what this animation should do when it reaches the end.
    定义当动画结束时应该做的,就是重复模式,有ValueAnimator.REVERSE--反向,ValueAnimator.RESTART重新开始
    
    addUpdateListener(ValueAnimator.AnimatorUpdateListener listener)
    Adds a listener to the set of listeners that are sent update events through the life of an animation.
    为动画执行过程添加一个监听器
    
    start()
    Starts this animation.
    开始动画
    

    还有其他的就不再一一赘述了
    首先我们定义一个函数初始化 ValueAnimator

        public static final int TIME = 5 * 1000;//动画时间
        public static final int LENGTH = 3;//长度,这里表示几个π
        /**
         * 初始化valueAnimator
         */
        private void initValueAnimator() {
            valueAnimator = ValueAnimator.ofFloat(0, LENGTH);
            valueAnimator.setDuration(TIME);
            valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
            valueAnimator.setRepeatMode(ValueAnimator.RESTART);
        }
    

    接着画横纵轴就

        private float padding = 10;//边距
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            canvas.drawLine(0, getHeight() / 2, getWidth(), getHeight() / 2, linePaint);//绘制x轴
            canvas.drawLine(padding, 0, padding, getHeight(), linePaint);//绘制y轴
        }
    

    接着开始绘制函数了

         private Path sinPath;
        /**
         * 获取真实的x的值
         *
         * @param x
         * @return
         */
        public float getRealX(float x) {
            return (getWidth() - 2 * padding) / LENGTH * x + padding;//算出每一段的宽度*当前的数值+左边的padding
        }
    
        /**
         * 获取真实的y的值
         *
         * @param y
         * @return
         */
        public float getRealY(float y) {
            return ((getHeight() - padding) / 2 * (1 - y)) + padding;
        }
         
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            sinPath.moveTo(getRealX(0), getRealY(0));//最开始移动到初始化位置
            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    long playTime = valueAnimator.getCurrentPlayTime();//获取当前动画播放的时间
                    float value = (float) animation.getAnimatedValue();//获取动画当前的值
                    if (currentTime > playTime) {//如果播放完了一圈则初始化path并且移动到起始点
                        sinPath.reset();
                        sinPath.moveTo(getRealX(value), getRealY((float) Math.sin(value * Math.PI)));
                    } else {//否则在path添加下一个点
                        sinPath.lineTo(getRealX(value), getRealY((float) Math.sin(value * Math.PI)));
                    }
                    currentTime = playTime;
                    postInvalidate();
                }
            });
            valueAnimator.start();//开始动画
        }
         @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            canvas.drawText(String.valueOf(currentTime), padding, padding + 24, textPaint);//绘制左上角的文字
            canvas.drawLine(0, getHeight() / 2, getWidth(), getHeight() / 2, linePaint);//绘制x轴
            canvas.drawLine(padding, 0, padding, getHeight(), linePaint);//绘制y轴
            canvas.drawPath(sinPath, sinPaint);//绘制sin曲线
            canvas.drawCircle(getRealX((float) valueAnimator.getAnimatedValue()), getRealY((float) (Math.sin((float) valueAnimator.getAnimatedValue() * Math.PI))), 10, sinPaint);//绘制曲线上的圆
        }
    

    最后贴出初始化代码

        private long currentTime = 0;
        private Paint linePaint;
        private Paint sinPaint;
        private TextPaint textPaint;
        private ValueAnimator valueAnimator;
    
        public SinView(Context context) {
            this(context, null);
        }
    
        public SinView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public SinView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            sinPath = new Path();
            initValueAnimator();
            linePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            linePaint.setColor(Color.BLACK);
            linePaint.setStrokeWidth(5);
            linePaint.setStyle(Paint.Style.STROKE);
            sinPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            sinPaint.setColor(Color.RED);
            sinPaint.setStrokeWidth(5);
            sinPaint.setStyle(Paint.Style.STROKE);
            textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
            textPaint.setColor(Color.GREEN);
            textPaint.setTextSize(24);
        }
    
    

    差不多就完成了,可以在Activity中显示了。
    有什么不对或者不好的地方欢迎大家吐槽

    相关文章

      网友评论

          本文标题:用ValueAnimator绘制sin函数

          本文链接:https://www.haomeiwen.com/subject/fgsbyttx.html