Android使用自定义View实现正弦波·波动效果

本文介绍如何在Android中使用自定义View绘制正弦波动画,包括两条交叉变换的正弦曲线,适用于设备连接等待动画。通过调整参数,可以改变波长、频率和移动速度。
公司项目需求,需要做一个设备连接等待的动画,就是有2条正弦曲线,交叉变换,还有倒计时等。

实现思路:1、使用自定义View画静态的正弦曲线;
                  2、使曲线动起来;


废话不多说,先上效果图:

怎么样,效果还行吧 ~~~///(^v^)\\\~~~


实现步骤:1、自定义View
package com.example.waveline.view;

import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AnticipateInterpolator;
import android.view.animation.AnticipateOvershootInterpolator;
import android.view.animation.BounceInterpolator;
import android.view.animation.CycleInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.LinearInterpolator;
import android.view.animation.PathInterpolator;

import com.example.waveline.R;

/**
 * 正弦曲线
 * Created by chao on 16/10/28.
 */
public class WaveLineView extends View {
    private static final int DEF_HEIGHT = 60;
    private Paint waveFirstPaint;
    private Paint waveSecondPaint;
    private float waveFirstAmplifier;
    private float waveSecondAmplifier;
    private float waveFirstFrequency;
    private float waveSecondFrequency;
    private float waveFirstPhase;
    private float waveSecondPhase;
    private int waveLineFirstWidth;
    private int waveLineSecondWidth;
    private int viewWidth;
    private float viewCenterY;
    private int waveFirstColor;
    private int waveSecondColor;

    public WaveLineView(Context context) {
        this(context, null);
    }

    public WaveLineView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public WaveLineView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        waveFirstColor = Color.parseColor("#fefefe");//第一条线颜色
        waveSecondColor = Color.parseColor("#eeeeee");//第二条线颜色

        waveLineFirstWidth = 14;//第一条线的宽度,即粗细
        waveLineSecondWidth = 7;//第二条线的宽度,即粗细

        waveFirstAmplifier = 60.0f;//第一条线的振幅
        waveSecondAmplifier = 20.0f;//第二条线的振幅

        waveFirstPhase = 45.0f;//第一条线的相位,初始X轴偏移
        waveSecondPhase = 45.0f;//第二条线的相位,初始X轴偏移

        waveFirstFrequency = 0.8f;//第一条线的频率,可改变波长
        waveSecondFrequency = 1.0f;//第二条线的频率,可改变波长

        initTools();
    }

    private void initTools() {
        waveFirstPaint = new Paint();
        waveFirstPaint.setColor(waveFirstColor);
        waveFirstPaint.setAntiAlias(true);
        waveFirstPaint.setStyle(Paint.Style.FILL);
        waveFirstPaint.setStrokeJoin(Paint.Join.ROUND);
        waveFirstPaint.setStrokeCap(Paint.Cap.ROUND);
        waveFirstPaint.setStrokeWidth(waveLineFirstWidth);

        waveSecondPaint = new Paint();
        waveSecondPaint.setColor(waveSecondColor);
        waveSecondPaint.setAntiAlias(true);
        waveSecondPaint.setStyle(Paint.Style.FILL);
        waveSecondPaint.setStrokeJoin(Paint.Join.ROUND);
        waveSecondPaint.setStrokeCap(Paint.Cap.ROUND);
        waveSecondPaint.setStrokeWidth(waveLineSecondWidth);
    }

    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        for (int i = 0; i < viewWidth - 1; i++) {
            canvas.drawLine((float) i, viewCenterY - waveFirstAmplifier * (float) (Math.sin(waveFirstPhase * 2 * (float) Math.PI / 360.0f + 2 * Math.PI * waveFirstFrequency * i / viewWidth)), (float) (i + 1), viewCenterY - waveFirstAmplifier * (float) (Math.sin(waveFirstPhase * 2 * (float) Math.PI / 360.0f + 2 * Math.PI * waveFirstFrequency * (i + 1) / viewWidth)), waveFirstPaint);
            canvas.drawLine((float) i, viewCenterY - waveSecondAmplifier * (float) (Math.sin(-waveSecondPhase * 2 * (float) Math.PI / 360.0f + 2 * Math.PI * waveSecondFrequency * i / viewWidth)), (float) (i + 1), viewCenterY - waveSecondAmplifier * (float) (Math.sin(-waveSecondPhase * 2 * (float) Math.PI / 360.0f + 2 * Math.PI * waveSecondFrequency * (i + 1) / viewWidth)), waveSecondPaint);
        }
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        viewWidth = w;
        viewCenterY = h / 2;
        waveFirstAmplifier = (waveFirstAmplifier * 2 > h) ? (h / 2) : waveFirstAmplifier;
        waveSecondAmplifier = (waveSecondAmplifier * 2 > h) ? (h / 2) : waveSecondAmplifier;
        waveAnim();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int heightMeasureMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightMeaure;

        if (heightMeasureMode == MeasureSpec.AT_MOST || heightMeasureMode == MeasureSpec.UNSPECIFIED) {
            heightMeaure = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, DEF_HEIGHT, getResources().getDisplayMetrics());
            heightMeasureSpec = MeasureSpec.makeMeasureSpec(heightMeaure, MeasureSpec.EXACTLY);
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    public void waveAnim() {
        ValueAnimator valueAnimator = ValueAnimator.ofFloat(0F, 1.F);
        valueAnimator.setDuration(800);//控制移动快慢,值越小越快
        valueAnimator.setRepeatMode(ValueAnimator.RESTART);//重新启动
        valueAnimator.setRepeatCount(ValueAnimator.INFINITE);//无限重复
        valueAnimator.setInterpolator(new LinearInterpolator());//速率变化
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                Float aFloat = Float.valueOf(animation.getAnimatedValue().toString());
                waveFirstPhase = 360.F * aFloat;
                waveSecondPhase = 360.F * aFloat;
                invalidate();
            }
        });
        valueAnimator.start();
    }
}

2、在布局中使用自定义的View
<com.xxx.WaveLineView
            android:id="@+id/mWaveLineView"
            android:layout_width="145dp"
            android:layout_height="145dp"
            android:layout_centerInParent="true"/>

3、打开Activity中就能看到效果了!



说明:
无需做其他设置,自定义View中已经实现好了逻辑!
如果要改变波长、频率、移动快慢等,自己看代码,中间都有注释。
如果不想硬编码,可以把参数写入样式中,然后在自定义View中引入样式,具体请自行百度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值