Android 仿苹果siri语音动效

 

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Shader;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class WaveView extends View {
    private static final String TAG = WaveView.class.getSimpleName();
    private int mWidth, mHeight;
    private Paint mPaint;
    private int MAX;
    private float amplitude = 0.3f;
    private float wAmplitude = 1f;

    private int[] COLORS = {R.color.green, R.color.blue, R.color.pink};
    private Random random;

    private static final float MAX_VOLUME = 30;
    private List<Wave> waves;

    private int[] lineColors = new int[]{0xFF111111, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF111111};
    private float[] linepositions = new float[]{0f, 0.1f, 0.9f, 1};
    private boolean running;
    private long l;

    public WaveView(Context context) {
        super(context);
        init();
    }

    public WaveView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mHeight = h;
        mWidth = w;

        MAX = h * 2 / 3;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mHeight = getMeasuredHeight();
        mWidth = getMeasuredWidth();
    }

    private Handler handler = new Handler() {

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case 1:

                    running = true;
                    waveCount = 10;
                    createWave();
                    setWaveCount(waveCount);
                    postInvalidate();
                    break;
            }
        }
    };

    public void startAnim() {
        if (!running)
            handler.sendEmptyMessageDelayed(1, 100);
    }

    private int waveCount = 10;

    private void setWaveCount(int count) {
        int size = waves.size();
        if (count > size) {
            count = size;
        }
        for (int i = 0; i < size; i++) {
            if (i < count) {
                waves.get(i).playing = true;
            } else {
                waves.get(i).playing = false;
            }
        }
    }

    public void setVolume(float volume) {
        if (volume <= 3) {
            amplitude = 0.5f;
            waveCount = 10;
            wAmplitude = 1.2f;
        } else if (volume > 3 && volume < 10) {
            amplitude = 0.7f;
            waveCount = 10;
            wAmplitude = 1;
        } else if (volume > 10 && volume < 20) {
            amplitude = 0.9f;
        } else if (volume > 20) {
            waveCount = 10;
            amplitude = 1.2f;
        }
        Log.e("AA-->", "setVolume: " + amplitude + "--" + volume);

        setWaveCount(waveCount);
    }

    public void stopAnim() {
        running = false;
        waveCount = 0;

        setWaveCount(waveCount);
    }

    private void init() {
        mPaint = new Paint();
        random = new Random();

        mPaint.setAntiAlias(true);
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD));
    }

    private void createWave() {
        if (waves == null) {
            waves = new ArrayList<>();
        }
        waves.clear();
        for (int i = 0; i < 17; i++) {
            Wave wave = new Wave();
            initAnimator(wave);
            waves.add(wave);
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        // TODO Auto-generated method stub
        super.onDraw(canvas);

        if (!running) {
            return;
        }
        l = System.currentTimeMillis();
        Log.e(TAG, "onDraw: " + l);
        drawLine(canvas);

        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD));
        for (Wave wave : waves) {
            if (wave.playing) {

                wave.draw(canvas, mPaint);
            }
        }
        Log.e(TAG, "onDraw: " + (System.currentTimeMillis() - l));
        postInvalidateDelayed(20);
    }

    private void initAnimator(final Wave waveBean) {
        ValueAnimator animator = ValueAnimator.ofInt(0, waveBean.maxHeight);
        animator.setDuration(waveBean.duration);
        animator.setInterpolator(new AccelerateDecelerateInterpolator());
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                waveBean.waveHeight = (int) animation.getAnimatedValue();
                if (waveBean.waveHeight > waveBean.maxHeight / 2) {
                    waveBean.waveHeight = waveBean.maxHeight - waveBean.waveHeight;
                }
//                Log.e("AAA-->", "initAnimator: " + waveBean.toString());
            }
        });
        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                if (waveBean.playing) {

                    waveBean.respawn();
                    initAnimator(waveBean);
                }
//                waves.remove(waveBean);
            }
        });
        animator.start();
    }

    class Wave {
        boolean playing = false;
        int maxHeight;
        int maxWidth;
        int color;
        float speed = 0.3f;
        double seed, open_class;

        int waveHeight;
        int duration;
        Paint mPaint;

        public Wave() {
            mHeight = getMeasuredHeight();
            mWidth = getMeasuredWidth();
            respawn();
        }

        public void respawn() {
            this.seed = Math.random();  // 位置
            maxWidth = (random.nextInt(mWidth / 16) + mWidth * 3 / 11);
            if (seed <= 0.2) {
                maxHeight = random.nextInt(MAX / 6) + MAX / 5;
                open_class = 2;
            } else if (seed <= 0.3 && seed > 0.2) {
                maxHeight = random.nextInt(MAX / 3) + MAX * 1 / 5;
                open_class = 3;
            } else if (seed > 0.3 && seed <= 0.7) {
                maxHeight = random.nextInt(MAX / 2) + MAX * 2 / 5;
                open_class = 3;
            } else if (seed > 0.7 && seed <= 0.8) {
                maxHeight = random.nextInt(MAX / 3) + MAX * 1 / 5;
                open_class = 3;
            } else if (seed > 0.8) {
                maxHeight = random.nextInt(MAX / 6) + MAX / 5;
                open_class = 2;
            }
            duration = random.nextInt(1000) + 1000;
            color = COLORS[random.nextInt(3)];
        }

        double equation(double i) {
            i = Math.abs(i);
            double y = -1 * amplitude
                    * Math.pow(1 / (1 + Math.pow(open_class * i, 2)), 2);
            return y;
        }

        public void draw(Canvas canvas, Paint mPaint) {
            this.mPaint = mPaint;

            this._draw(1, canvas);
        }

        private void _draw(int m, Canvas canvas) {

            Path path = new Path();
            Path pathN = new Path();
            path.moveTo(mWidth / 4, mHeight / 2);
            pathN.moveTo(mWidth / 4, mHeight / 2);
            double x_base = mWidth / 2  // 波浪位置
                    + (-mWidth / 6 + this.seed
                    * (mWidth / 3));
            double y_base = mHeight / 2;

            double x, y, x_init = 0;
            double i = -1;
            while (i <= 1) {
                x = x_base + i * maxWidth * wAmplitude;
                double function = equation(i) * waveHeight;
                y = y_base + function;
                if (x_init > 0 || x > 0) {
                    x_init = mWidth / 4;
                }
                if (y > 0.1) {
                    path.lineTo((float) x, (float) y);
                    pathN.lineTo((float) x, (float) ((float) y_base - function));
                }
                i += 0.01;
            }
            mPaint.setColor(getResources().getColor(color));
            canvas.drawPath(path, mPaint);
            canvas.drawPath(pathN, mPaint);

        }

        @Override
        public String toString() {
            return "Wave{" +
                    "maxHight=" + maxHeight +
                    ", maxWidth=" + maxWidth +
                    ", color=" + color +
                    ", speed=" + speed +
                    ", amplitude=" + amplitude +
                    ", seed=" + seed +
                    ", open_class=" + open_class +
                    ", mPaint=" + mPaint +
                    '}';
        }
    }

    private void drawLine(Canvas canvas) {
        canvas.save();
        LinearGradient shader = new LinearGradient(
                mWidth / 40, 0,
                mWidth * 39 / 40, 0,
                lineColors,
                linepositions,
                Shader.TileMode.MIRROR);
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER));
        mPaint.setShader(shader);
        mPaint.setStrokeWidth(2);
        canvas.drawLine(mWidth / 40, mHeight / 2, mWidth * 39 / 40, mHeight / 2, mPaint);
        mPaint.setXfermode(null);
        mPaint.setShader(null);
        mPaint.clearShadowLayer();
        canvas.restore();
    }
}

本代码效果图

示例代码地址

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
Android仿Siri是指在Android系统上开发出一种类似于苹果Siri语音助手的果。Siri苹果公司推出的一款智能语音助手,它可以通过语音指令来完成用户的需求,如发送短信、查找信息等。它以其独特的对话界面和流畅的果而受到广大用户的喜爱。 要实现Android仿Siri,首先需要设计一个类似于Siri的对话界面,可以使用Android的布局和控件来完成。在布局中,可以加入文本框、图标等控件,通过这些控件来显示对话内容和用户的问题。 在果方面,可以借鉴Siri中的一些画特,如文字弹出、波浪果等。这些果可以通过Android画库来实现。在画开始时,可以让文本一次性显示出来,或者逐字逐句地显示。然后,可以通过一些缩放、平移和渐变果来让文本或图标呈现出波浪画的果。通过调整这些画的参数和时长,可以使得整个画看起来更加流畅、自然。 除了果外,还可以为Android仿Siri添加声音果,如音频提示或语音合成。这样,在用户与仿Siri对话时,可以出现仿真的语音对话果,增强用户的体验。 总之,Android仿Siri可以通过设计类似的对话界面、实现一些特殊的果和添加声音果来实现。这样的果可以为用户提供一种更加直观、有趣的交互方式,提高用户的使用体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wljian1

你的鼓励就是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值