android实现录音监听动画的示例代码-kb88凯时官网登录

来自:网络
时间:2024-06-09
阅读:
免费资源网,https://freexyz.cn/

一、前言

在很多app种内置了语音助手,也存在各种动画,主要原因是处理2个阶段问题,第一个是监听声音的等待效果,第二个是语意解析存在一定耗时的等待效果,前者要求有声音输入时有视觉反馈,后者让用户知道在处理某些事情,同时呢,这个效果还能互相切换,这是一般语音监听动画的设计逻辑。本文提供一种,希望对大家有所帮助。

效果图

android实现录音监听动画的示例代码

(gif 有些卡,可能是压缩的原因)

二、实现方法

2.1 过渡动画

必须等待上一个动画结束后再切换为制定状态

2.2 声音抖动计算

本文没有明确计算线性音量,取出音量数据,进行了简单的计算

    public void updateshakevalue(int volume) {
        if (this.getvisibility() != view.visible || !isattachedtowindow()) return;
        if (!isplaying) return;
        float ratio = volume * 1.0f / this.mmaxshakerange;
        if (ratio < 1f / 4) {
            ratio = 0;
        }
        if (ratio >= 1f / 4 && ratio < 2f / 4) {
            ratio = 1f / 4;
        }
        if (ratio >= 2f / 4 && ratio < 3f / 4) {
            ratio = 2f / 4;
        }
        if (ratio >= 3f / 4) {
            ratio = 1f;
        }
        updateshakeratio(ratio);
    }

2.3 模式切换

需要listening和loading 模式之间互相切换

   public void startplay(final int state) {
        post(new runnable() {
            @override
            public void run() {
                setstate(state);
                if (!isplaying) {
                    mcurrentstate = mnextstate;
                }
                isplaying = true;
                if (mnextstate == mcurrentstate) {
                    if (state == state_listening) {
                        startlisteninganim();
                    } else if (state == state_loading) {
                        startloadinganim();
                    }
                } else {
                    starttransformanim();
                }
            }
        });
    }
#loading 效果
radarview.startplay(speechradarview.state_loading);
#listening效果
radarview.startplay(speechradarview.state_listening);
#停止播放
radarview.stopplay();

2.4 抖动幅度范围,以适应不同类型的需求

#最大振幅
radarview.setmaxshakerange(30);
#当前值
radarview.updateshakevalue(20);

三、全部代码

public class speechradarview extends view {
    private static final long animation_circle_timeout = 1000;
    private static final long animation_loading_timeout = 800;
    private valueanimator mshakeanimatortimer;
    private int mfixedradius = 0;
    private int mmaxradius = 0;
    private textpaint mpaint;
    private animationcircle[] manimationcircle = new animationcircle[2];
    private float mbullketstrokewidthsize;
    private animatorset manimatortimerset = null;
    private animatorset mnextanimatortimerset = null;
    private valueanimator mtransformanimatortimer;
    private int animation_main_color = 0x99ff8c14;
    private static final int main_color = 0xffff8c14;
    rectf arcbounds = new rectf();
    linearinterpolator linearinterpolator = new linearinterpolator();
    acceleratedecelerateinterpolator acceleratedecelerateinterpolator = new acceleratedecelerateinterpolator();
    public static final int state_loading = 0;
    public static final int state_listening = 1;
    private int mcurrentstate = state_loading;
    private int mnextstate = state_loading; //过渡值
    private float loading_stoke_width = 0;
    private int loading_start_angle = 90;
    private int mcurrentangle = loading_start_angle;
    private int mtransformloadingcolor = color.transparent;
    private int mtransformlisteningcolor = color.transparent;
    private boolean isplaying = false;
    private float mshakeratio = 0;
    private float mnextshakeratio = 0;
    private long mstartshaketime = 0;
    private int mmaxshakerange = 100;
    public speechradarview(context context) {
        this(context, null);
    }
    public speechradarview(context context, attributeset attrs) {
        this(context, attrs, 0);
    }
    public speechradarview(context context, attributeset attrs, int defstyleattr) {
        super(context, attrs, defstyleattr);
        initpaint();
    }
    private void setstate(int state) {
        if (this.mnextstate == state) {
            return;
        }
        this.mnextstate = state;
    }
    public int getstate() {
        return mnextstate;
    }
    private void initpaint() {
        // 实例化画笔并打开抗锯齿
        mpaint = new textpaint(paint.anti_alias_flag);
        mpaint.setantialias(true);
        mpaint.setpatheffect(new cornerpatheffect(10)); //设置线条类型
        mpaint.setstrokewidth(dip2px(1));
        mpaint.settextsize(dip2px((12)));
        mpaint.setstyle(paint.style.stroke);
        mbullketstrokewidthsize =  dip2px(5);
        loading_stoke_width =  dip2px(5);
    }
    @override
    protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {
        super.onmeasure(widthmeasurespec, heightmeasurespec);
        super.onmeasure(widthmeasurespec, heightmeasurespec);
        int widthmode = measurespec.getmode(widthmeasurespec);
        int width = measurespec.getsize(widthmeasurespec);
        int heightmode = measurespec.getmode(heightmeasurespec);
        int height = measurespec.getsize(heightmeasurespec);
        if (widthmode != measurespec.exactly) {
            width = (int) dip2px(210);
        }
        if (heightmode != measurespec.exactly) {
            height = (int) dip2px(210);
        }
        setmeasureddimension(width, height);
    }
    public float dip2px(float dp) {
        return typedvalue.applydimension(typedvalue.complex_unit_dip, dp, getresources().getdisplaymetrics());
    }
    @override
    protected void ondraw(canvas canvas) {
        super.ondraw(canvas);
        int width = getwidth();
        int height = getheight();
        if (width == 0 || height == 0) return;
        int centerx = width / 2;
        int centery = height / 2;
        int diameter = math.min(width, height) / 2;
        mfixedradius = diameter / 3;
        mmaxradius = diameter;
        initanimationcircle();
        if (!isineditmode() && !isplaying) return;
        int layerid = savelayer(canvas, centerx, centery);
        if (mnextstate == mcurrentstate) {
            if (mcurrentstate == state_listening) {
                drawanimationcircle(canvas);
                drawfixcircle(canvas, main_color);
                drawflashbullket(canvas, color.white, mshakeratio);
                mshakeratio = 0;
            } else if (mcurrentstate == state_loading) {
                drawloadingarc(canvas, main_color);
                drawflashbullket(canvas, main_color, 0);
            }
        } else {
            if (this.mnextstate == state_listening) {
                drawloadingarc(canvas, mtransformloadingcolor);
                drawfixcircle(canvas, mtransformlisteningcolor);
                drawflashbullket(canvas, color.white, 0);
            } else {
                drawfixcircle(canvas, mtransformlisteningcolor);
                drawloadingarc(canvas, mtransformloadingcolor);
                drawflashbullket(canvas, main_color, 0);
            }
        }
        restorelayer(canvas, layerid);
    }
    private void drawloadingarc(canvas canvas, int color) {
        int oldcolor = mpaint.getcolor();
        paint.style style = mpaint.getstyle();
        float strokewidth = mpaint.getstrokewidth();
        mpaint.setstrokewidth(loading_stoke_width);
        float inneroffset = loading_stoke_width / 2;
        mpaint.setcolor(color);
        mpaint.setstyle(paint.style.stroke);
        arcbounds.set(-mfixedradius   inneroffset, -mfixedradius   inneroffset, mfixedradius - inneroffset, mfixedradius - inneroffset);
        canvas.drawarc(arcbounds, mcurrentangle, 270, false, mpaint);
        mpaint.setcolor(oldcolor);
        mpaint.setstyle(style);
        mpaint.setstrokewidth(strokewidth);
    }
    private void drawflashbullket(canvas canvas, int color, float fraction) {
        int bullketzonewidth = mfixedradius;
        int bullketzoneheight = mfixedradius * 2 / 3;
        int minheight = (int) (bullketzoneheight / 3f);
        int maxrangeheight = (int) (bullketzoneheight * 2 / 3f);
        drawflashbullket(canvas, bullketzonewidth, color, minheight, (maxrangeheight * fraction));
    }
    private void drawflashbullket(canvas canvas, int width, int color, int height, float delta) {
        int offset = (int) ((width - mbullketstrokewidthsize * 4) / 3);
        int oldcolor = mpaint.getcolor();
        float strokewidth = mpaint.getstrokewidth();
        if (delta < 0f) {
            delta = 0f;
        }
        mpaint.setcolor(color);
        mpaint.setstrokecap(paint.cap.round);
        mpaint.setstrokewidth(mbullketstrokewidthsize);
        for (int i = 0; i < 4; i  ) {
            int startx = (int) (i * (offset   mbullketstrokewidthsize) - width / 2   mbullketstrokewidthsize / 2);
            if (i == 0 || i == 3) {
                canvas.drawline(startx, -height / 2f   delta * 1 / 3, startx, height / 2f   delta * 1 / 3, mpaint);
            } else {
                canvas.drawline(startx, -(height / 2f   delta * 2 / 3), startx, (height / 2f   delta * 2 / 3), mpaint);
            }
        }
        mpaint.setcolor(oldcolor);
        mpaint.setstrokewidth(strokewidth);
    }
    @override
    protected void onsizechanged(int w, int h, int oldw, int oldh) {
        super.onsizechanged(w, h, oldw, oldh);
    }
    private void drawanimationcircle(canvas canvas) {
        for (int i = 0; i < manimationcircle.length; i  ) {
            animationcircle circle = manimationcircle[i];
            if (circle.radius > mfixedradius) {
                drawcircle(canvas, circle.color, circle.radius);
                log.e("animationcircle", "i="   i   " , radius="   circle.radius);
            } else {
                log.d("animationcircle", "i="   i   " , radius="   circle.radius);
            }
        }
    }
    private void initanimationcircle() {
        for (int i = 0; i < manimationcircle.length; i  ) {
            if (manimationcircle[i] == null) {
                if (i == 0) {
                    manimationcircle[i] = new animationcircle(mmaxradius, mfixedradius, 0x88ff8c14);
                } else {
                    manimationcircle[i] = new animationcircle(mmaxradius, mfixedradius, 0x99ff8c14);
                }
            } else {
                if (manimationcircle[i].token != mmaxradius) {
                    manimationcircle[i].radius = mfixedradius;
                    manimationcircle[i].token = mmaxradius;
                }
            }
        }
    }
    private void drawcircle(canvas canvas, int color, float radius) {
        int oldcolor = mpaint.getcolor();
        paint.style style = mpaint.getstyle();
        float strokewidth = mpaint.getstrokewidth();
        mpaint.setstrokewidth(0);
        mpaint.setcolor(color);
        mpaint.setstyle(paint.style.fill);
        canvas.drawcircle(0, 0, radius, mpaint);
        mpaint.setcolor(oldcolor);
        mpaint.setstyle(style);
        mpaint.setstrokewidth(strokewidth);
    }
    private void restorelayer(canvas canvas, int save) {
        canvas.restoretocount(save);
    }
    private int savelayer(canvas canvas, int centerx, int centery) {
        int save = canvas.save();
        canvas.translate(centerx, centery);
        return save;
    }
    private void drawfixcircle(canvas canvas, int color) {
        drawcircle(canvas, color, mfixedradius);
    }
    public void startplay(final int state) {
        post(new runnable() {
            @override
            public void run() {
                setstate(state);
                if (!isplaying) {
                    mcurrentstate = mnextstate;
                }
                isplaying = true;
                if (mnextstate == mcurrentstate) {
                    if (state == state_listening) {
                        startlisteninganim();
                    } else if (state == state_loading) {
                        startloadinganim();
                    }
                } else {
                    starttransformanim();
                }
            }
        });
    }
    public void startloadinganim() {
        if (manimatortimerset != null) {
            manimatortimerset.cancel();
        }
        manimatortimerset = getanimatorloadingset();
        if (manimatortimerset != null) {
            manimatortimerset.start();
        }
    }
    private void starttransformanim() {
        if (mnextanimatortimerset != null) {
            mnextanimatortimerset.cancel();
        }
        if (mtransformanimatortimer != null) {
            mtransformanimatortimer.cancel();
        }
        mtransformanimatortimer = buildtransformanimatortimer(mcurrentstate, mnextstate);
        if (mnextstate == state_listening) {
            mnextanimatortimerset = getanimatorcircleset();
        } else {
            mnextanimatortimerset = getanimatorloadingset();
        }
        if (mtransformanimatortimer != null) {
            mtransformanimatortimer.start();
        }
        if (mnextanimatortimerset != null) {
            mnextanimatortimerset.start();
        }
    }
    public void startlisteninganim() {
        if (manimatortimerset != null) {
            manimatortimerset.cancel();
        }
        animatorset animatortimerset = getanimatorcircleset();
        if (animatortimerset == null) return;
        manimatortimerset = animatortimerset;
        manimatortimerset.start();
    }
    @nullable
    private animatorset getanimatorcircleset() {
        animatorset animatortimerset = new animatorset();
        valueanimator firstanimatortimer = buildcircleanimatortimer(manimationcircle[0]);
        valueanimator secondanimatortimer = buildcircleanimatortimer(manimationcircle[1]);
        if (firstanimatortimer == null || secondanimatortimer == null) return null;
        secondanimatortimer.setstartdelay(animation_circle_timeout / 2);
        animatortimerset.playtogether(firstanimatortimer, secondanimatortimer);
        return animatortimerset;
    }
    @nullable
    private animatorset getanimatorloadingset() {
        valueanimator valueanimator = buildloadinganimatortimer();
        if (valueanimator == null) return null;
        animatorset animatortimerset = new animatorset();
        animatortimerset.play(valueanimator);
        return animatortimerset;
    }
    @nullable
    private valueanimator buildcircleanimatortimer(final animationcircle circle) {
        if (mfixedradius <= 0 || circle == null) return null;
        valueanimator animatortimer = valueanimator.offloat(mfixedradius, math.min(getwidth(),getheight()) / 2f);
        animatortimer.setduration(animation_circle_timeout);
        animatortimer.setrepeatcount(valueanimator.infinite);
        animatortimer.setinterpolator(linearinterpolator);
        animatortimer.addupdatelistener(new valueanimator.animatorupdatelistener() {
            @override
            public void onanimationupdate(valueanimator animation) {
                float dx = (float) animation.getanimatedvalue();
                float fraction = 1 - animation.getanimatedfraction();
                float radius = dx;
                int color = argb((int) (color.alpha(animation_main_color) * fraction), color.red(animation_main_color), color.green(animation_main_color), color.blue(animation_main_color));
                if (mcurrentstate != mnextstate) {
                    color = color.transparent;
                }
                if (circle.radius != radius || circle.color != color) {
                    circle.radius = radius;
                    circle.color = color;
                    postinvalidate();
                }
            }
        });
        return animatortimer;
    }
    @nullable
    private valueanimator buildloadinganimatortimer() {
        if (mfixedradius <= 0) return null;
        valueanimator animatortimer = valueanimator.offloat(0, 1);
        animatortimer.setduration(animation_loading_timeout);
        animatortimer.setrepeatcount(valueanimator.infinite);
        animatortimer.setinterpolator(new acceleratedecelerateinterpolator());
        animatortimer.addupdatelistener(new valueanimator.animatorupdatelistener() {
            @override
            public void onanimationupdate(valueanimator animation) {
                float fraction = animation.getanimatedfraction();
                int angle = (int) (loading_start_angle   fraction * 360);
                if (mcurrentangle != angle) {
                    mcurrentangle = angle;
                    postinvalidate();
                }
            }
        });
        return animatortimer;
    }
    @nullable
    private valueanimator buildtransformanimatortimer(final int currentstate, final int nextstate) {
        if (mfixedradius <= 0) return null;
        final int alpha = color.alpha(main_color);
        final int red = color.red(main_color);
        final int green = color.green(main_color);
        final int blue = color.blue(main_color);
        valueanimator animatortimer = valueanimator.offloat(currentstate, nextstate);
        animatortimer.setduration(animation_loading_timeout);
        animatortimer.setinterpolator(acceleratedecelerateinterpolator);
        animatortimer.addupdatelistener(new valueanimator.animatorupdatelistener() {
            @override
            public void onanimationupdate(valueanimator animation) {
                float animatedvalue = (float) animation.getanimatedvalue();
                if (mcurrentstate != mnextstate) {
                    mtransformlisteningcolor = argb((int) (alpha * animatedvalue), red, green, blue);
                    mtransformloadingcolor = argb((int) (alpha * (1 - animatedvalue)), red, green, blue);
                    log.d("animatedvalue", " --- >"   animatedvalue);
                    postinvalidate();
                }
            }
        });
        animatortimer.addlistener(new animatorlisteneradapter() {
            @override
            public void onanimationend(animator animation) {
                super.onanimationend(animation);
                resetanimationstate();
            }
            @override
            public void onanimationcancel(animator animation) {
                super.onanimationcancel(animation);
                resetanimationstate();
            }
        });
        return animatortimer;
    }
    private void resetanimationstate() {
        mcurrentstate = mnextstate;
        if (manimatortimerset != null) {
            if (manimatortimerset != mnextanimatortimerset) {
                manimatortimerset.cancel();
            }
        }
        manimatortimerset = mnextanimatortimerset;
    }
    @override
    protected void ondetachedfromwindow() {
        super.ondetachedfromwindow();
        stopplay();
    }
    public void stopplay() {
        isplaying = false;
        mcurrentangle = loading_start_angle;
        try {
            if (manimatortimerset != null) {
                manimatortimerset.cancel();
            }
            if (mnextanimatortimerset != null) {
                mnextanimatortimerset.cancel();
            }
            if (mshakeanimatortimer != null) {
                mshakeanimatortimer.cancel();
            }
        } catch (exception e) {
            e.printstacktrace();
        }
        resetanimationcircle();
        postinvalidate();
    }
    private void resetanimationcircle() {
        for (animationcircle circle : manimationcircle) {
            if (circle != null) {
                circle.radius = mfixedradius;
            }
        }
    }
    public static int argb(
            @intrange(from = 0, to = 255) int alpha,
            @intrange(from = 0, to = 255) int red,
            @intrange(from = 0, to = 255) int green,
            @intrange(from = 0, to = 255) int blue) {
        return (alpha << 24) | (red << 16) | (green << 8) | blue;
    }
    public boolean isplaying() {
        return isplaying;
    }
    private void updateshakeratio(final float ratio) {
        long currenttimemillis = system.currenttimemillis();
        if (currenttimemillis - mstartshaketime >= 150) {
            mnextshakeratio = ratio;
            if (mshakeratio != mnextshakeratio) {
                startshakeanimation();
            }
            mstartshaketime = currenttimemillis;
        }
    }
    private void startshakeanimation() {
        if (mshakeanimatortimer != null) {
            mshakeanimatortimer.cancel();
        }
        mshakeanimatortimer = valueanimator.offloat(mshakeratio, mnextshakeratio);
        mshakeanimatortimer.setduration(100);
        mshakeanimatortimer.setinterpolator(acceleratedecelerateinterpolator);
        mshakeanimatortimer.addupdatelistener(new valueanimator.animatorupdatelistener() {
            @override
            public void onanimationupdate(valueanimator animation) {
                float ratio = (float) animation.getanimatedvalue();
                if (mshakeratio != ratio) {
                    mshakeratio = ratio;
                    postinvalidate();
                }
            }
        });
        mshakeanimatortimer.start();
    }
    public void setmaxshakerange(int maxshakerange) {
        this.mmaxshakerange = maxshakerange;
        if (this.mmaxshakerange <= 0) this.mmaxshakerange = 100;
    }
    public void updateshakevalue(int volume) {
        if (this.getvisibility() != view.visible || !isattachedtowindow()) return;
        if (!isplaying) return;
        float ratio = volume * 1.0f / this.mmaxshakerange;
        if (ratio < 1f / 4) {
            ratio = 0;
        }
        if (ratio >= 1f / 4 && ratio < 2f / 4) {
            ratio = 1f / 4;
        }
        if (ratio >= 2f / 4 && ratio < 3f / 4) {
            ratio = 2f / 4;
        }
        if (ratio >= 3f / 4) {
            ratio = 1f;
        }
        updateshakeratio(ratio);
    }
    public boolean isattachedtowindow() {
        if (build.version.sdk_int >= build.version_codes.kitkat) {
            return super.isattachedtowindow();
        } else {
            return getwindowtoken() != null;
        }
    }
    private static class animationcircle {
        private float radius;
        private int color;
        private int token;
        animationcircle(int token, int radius, int color) {
            this.radius = radius;
            this.color = color;
            this.token = token;
        }
    }
}

四、总结

总体上这个设计不是很难,难点是状态切换的一些过渡设计,保证上一个动画结束完成之后才能展示下一个动画,其词就是抖动逻辑,实际上也不是很复杂,第三方sdk的音量值一般都是有的,实时获取就好了。

以上就是android实现录音监听动画的示例代码的详细内容,更多关于android录音监听动画的资料请关注其它相关文章!

免费资源网,https://freexyz.cn/
返回顶部
顶部
网站地图