android 音乐波动动画

2023-11-14

需求:在播放音乐的时候,随机产生不规律动画

这里写图片描述

下载地址:http://download.csdn.net/detail/qq_28195645/9700355

自定义音乐波动控件

package com.sun.audioplayingwave.sloading;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

import com.sun.audioplayingwave.R;
import com.sun.audioplayingwave.sloading.indicator.BaseIndicatorController;
import com.sun.audioplayingwave.sloading.indicator.LineScaleIndicator;
import com.sun.audioplayingwave.sloading.indicator.LineScalePulseOutIndicator;
import com.sun.audioplayingwave.sloading.indicator.LineScalePulseOutThreeIndicator;
import com.sun.audioplayingwave.sloading.indicator.LineScalePulseOutWaveIndicator;



/**
 * Created by walkingMen on 2016/4/27.
 */
public class SLoadingIndicatorView extends View {
    private static final String TAG = SLoadingIndicatorView.class.getSimpleName();
    public static final int DefaultScale = 0;
    public static final int LineScale = 1;
    public static final int LineScalePulseOut = 2;
    public static final int LineScalePulseOutThree = 3;
    public static final int LineScalePulseOutWave = 4;

    //Sizes (with defaults in DP)
    public static final int DEFAULT_SIZE = 45;

    //attrs
    int mIndicatorId;
    int mIndicatorColor;

    Paint mPaint;
    BaseIndicatorController mIndicatorController;

    private boolean mHasAnimation;

    public SLoadingIndicatorView(Context context) {
        super(context);
        init(null, 0);
    }

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

    public SLoadingIndicatorView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(attrs, defStyleAttr);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public SLoadingIndicatorView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(attrs, defStyleAttr);
    }

    private void init(AttributeSet attrs, int defStyle) {
        TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.SLoadingIndicatorView);
        mIndicatorId = a.getInt(R.styleable.SLoadingIndicatorView_s_indicator, DefaultScale);
        mIndicatorColor = a.getColor(R.styleable.SLoadingIndicatorView_s_indicator_color, Color.WHITE);
        a.recycle();
        mPaint = new Paint();
        mPaint.setColor(mIndicatorColor);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setAntiAlias(true);
        applyIndicator();
    }

    private void applyIndicator() {
        switch (mIndicatorId) {
            case DefaultScale:
                mIndicatorController = new LineScaleIndicator();
                break;
            case LineScale:
                mIndicatorController = new LineScaleIndicator();
                break;
            case LineScalePulseOut:
                mIndicatorController = new LineScalePulseOutIndicator();
                break;
            case LineScalePulseOutThree:
                mIndicatorController = new LineScalePulseOutThreeIndicator();
                bringToFront();
                break;
            case LineScalePulseOutWave:
                int[] waveFloats = new int[4];

                int w = View.MeasureSpec.makeMeasureSpec(0,
                        View.MeasureSpec.UNSPECIFIED);
                int h = View.MeasureSpec.makeMeasureSpec(0,
                        View.MeasureSpec.UNSPECIFIED);
                this.measure(w, h);
                int height = this.getMeasuredHeight();
                for (int i = 0; i < 4; i++) {
                    int intRandom = (int) (1 + Math.random() * (4 - 1 + 1));
                    int v = intRandom * 100;
                    waveFloats[i] = v;
                    Log.i(TAG, "applyIndicator: " + waveFloats[i]);
                }
                mIndicatorController = new LineScalePulseOutWaveIndicator(waveFloats);
                bringToFront();
                break;
        }
        mIndicatorController.setTarget(this);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = measureDimension(dp2px(DEFAULT_SIZE), widthMeasureSpec);
        int height = measureDimension(dp2px(DEFAULT_SIZE), heightMeasureSpec);
        setMeasuredDimension(width, height);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawIndicator(canvas);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        if (!mHasAnimation) {
            mHasAnimation = true;
            applyAnimation();
        }
    }

    @Override
    public void setVisibility(int v) {
        if (getVisibility() != v) {
            super.setVisibility(v);
            if (v == GONE || v == INVISIBLE) {
                mIndicatorController.setAnimationStatus(BaseIndicatorController.AnimStatus.END);
            } else {
                mIndicatorController.setAnimationStatus(BaseIndicatorController.AnimStatus.START);
            }
        }
    }

    /**
     * onAttachedToWindow是在第一次onDraw前调用的。也就是我们写的View在没有绘制出来时调用的,但只会调用一次。
     * onDetachedFromWindow相反
     */
    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        if (mHasAnimation) {
            mIndicatorController.setAnimationStatus(BaseIndicatorController.AnimStatus.START);
        }
    }

    /**
     * This is called when the view is detached from a window. At this point it no longer has a surface for drawing.
     */
    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        mIndicatorController.setAnimationStatus(BaseIndicatorController.AnimStatus.CANCEL);
    }

    void drawIndicator(Canvas canvas) {
        mIndicatorController.draw(canvas, mPaint);
    }

    private int measureDimension(int defaultSize, int measureSpec) {
        int result = defaultSize;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);
        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;
        } else if (specMode == MeasureSpec.AT_MOST) {
            result = Math.min(defaultSize, specSize);
        } else {
            result = defaultSize;
        }
        return result;
    }

    void applyAnimation() {
        mIndicatorController.initAnimation();
    }

    private int dp2px(int dpValue) {
        return (int) getContext().getResources().getDisplayMetrics().density * dpValue;
    }
}

自定义插值器抽象类

package com.sun.audioplayingwave.sloading.indicator;


import android.animation.Animator;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.View;

import java.lang.ref.WeakReference;
import java.util.List;

/**
 * Created by walkingMen on 2016/4/27.
 */

public abstract class BaseIndicatorController {


    private WeakReference<View> mTarget;

    private List<Animator> mAnimators;


    public void setTarget(View target) {
        this.mTarget = new WeakReference<>(target);
    }

    public View getTarget() {
        return mTarget != null ? mTarget.get() : null;
    }


    public int getWidth() {
        return getTarget() != null ? getTarget().getWidth() : 0;
    }

    public int getHeight() {
        return getTarget() != null ? getTarget().getHeight() : 0;
    }

    public void postInvalidate() {
        if (getTarget() != null) {
            getTarget().postInvalidate();//刷新界面
        }
    }

    /**
     * draw indicator
     *
     * @param canvas
     * @param paint
     */
    public abstract void draw(Canvas canvas, Paint paint);

    /**
     * create animation or animations
     */
    public abstract List<Animator> createAnimation();

    public void initAnimation() {
        mAnimators = createAnimation();
    }

    /**
     * make animation to start or end when target
     * view was be Visible or Gone or Invisible.
     * make animation to cancel when target view
     * be onDetachedFromWindow.
     *
     * @param animStatus
     */
    public void setAnimationStatus(AnimStatus animStatus) {
        if (mAnimators == null) {
            return;
        }
        int count = mAnimators.size();
        for (int i = 0; i < count; i++) {
            Animator animator = mAnimators.get(i);
            boolean isRunning = animator.isRunning();
            switch (animStatus) {
                case START:
                    if (!isRunning) {
                        animator.start();
                    }
                    break;
                case END:
                    if (isRunning) {
                        animator.end();
                    }
                    break;
                case CANCEL:
                    if (isRunning) {
                        animator.cancel();
                    }
                    break;
            }
        }
    }


    public enum AnimStatus {
        START, END, CANCEL
    }


}

定义音乐波动插值器

package com.sun.audioplayingwave.sloading.indicator;

import android.animation.Animator;
import android.animation.ValueAnimator;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;

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

public class LineScaleWaveIndicator extends BaseIndicatorController {

    public static final float SCALE = 1.0f;

    float[] scaleYFloats = new float[]{SCALE,
            SCALE,
            SCALE,
            SCALE};
    public int[] waveFloats;

    public LineScaleWaveIndicator(int[] waveFloats) {
        this.waveFloats = waveFloats;
    }

    @Override
    public void draw(Canvas canvas, Paint paint) {
        float translateX = getWidth() / 14;
        float translateY = getHeight();
        for (int i = 0; i < 4; i++) {
            canvas.save();
            //平移
            int intRandom = (int) (1 + Math.random() * (10 - 1 + 1));
            float v = intRandom / 10f * getHeight();
            canvas.translate(((i + 1) * 2) * translateX + translateX * i, translateY);
            canvas.scale(SCALE, scaleYFloats[i]);
            RectF rectF = new RectF(-translateX, -getHeight(), 0, 0);
            canvas.drawRoundRect(rectF, 6, 6, paint);
            canvas.restore();
        }
    }

    @Override
    public List<Animator> createAnimation() {
        List<Animator> animators = new ArrayList<>();
        long[] delays = new long[]{100, 200, 300, 400};
        for (int i = 0; i < 4; i++) {
            final int index = i;
            ValueAnimator scaleAnim = ValueAnimator.ofFloat(1, 0.4f, 1);
            scaleAnim.setDuration(1000);
            scaleAnim.setRepeatCount(-1);
            scaleAnim.setStartDelay(delays[i]);
            scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    scaleYFloats[index] = (float) animation.getAnimatedValue();
                    postInvalidate();//刷新界面
                }
            });
            scaleAnim.start();
            animators.add(scaleAnim);
        }
        return animators;
    }

}
package com.sun.audioplayingwave.sloading.indicator;

import android.animation.Animator;
import android.animation.ValueAnimator;

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

/**
 * Created by walkingMen on 2016/4/27.
 */
public class LineScalePulseOutWaveIndicator extends LineScaleWaveIndicator {

    public LineScalePulseOutWaveIndicator(int[] heightFloats) {
        super(heightFloats);
    }

    @Override
    public List<Animator> createAnimation() {
        List<Animator> animators = new ArrayList<>();
        long[] delays = new long[]{500, 100, 200, 300};
        for (int i = 0; i < 4; i++) {
            final int index = i;
            ValueAnimator scaleAnim = ValueAnimator.ofFloat(1, 0.3f, 1);
            scaleAnim.setDuration(900);
            scaleAnim.setRepeatCount(-1);
            scaleAnim.setStartDelay(waveFloats[i]);
            scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    scaleYFloats[index] = (float) animation.getAnimatedValue();
                    postInvalidate();
                }
            });
            scaleAnim.start();
            animators.add(scaleAnim);
        }
        return animators;
    }

}

定义控件的属性

value 新建 attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!--loading控件-->
    <declare-styleable name="SLoadingIndicatorView">
        <attr name="s_indicator">
            <flag name="DefaultScale" value="0"/>
            <flag name="LineScale" value="1"/>
            <flag name="LineScalePulseOut" value="2"/>
            <flag name="LineScalePulseOutThree" value="3"/>
            <flag name="LineScalePulseOutWave" value="4"/>

        </attr>
        <attr name="s_indicator_color" format="color"/>
    </declare-styleable>
</resources>

直接在布局文件中使用

        <com.sun.audioplayingwave.sloading.SLoadingIndicatorView
            android:layout_width="30dp"
            android:layout_height="20dp"
            android:layout_centerInParent="true"
            android:layout_margin="20dp"
            app:s_indicator="LineScalePulseOutWave"/>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

android 音乐波动动画 的相关文章

  • 如何在点击时从 webview 获取 URL

    我怎样才能获得 点击的URL webview在其点击事件上 Override public void onClick View v if v getId R id webview Here i want to get clicked url
  • 通过使用计时器(或处理程序)更改 ImageView 中的图像来创建动画

    我想通过更改 ImageView 内的帧来创建一个简单的动画 我不想使用 AnimationDrawable 因为我需要在帧更改或动画停止时接收事件 以便能够向后播放 重新启动等等 我的问题是 尽管 setImageDrawable 被调用
  • 如何在GreenDao中实现表继承

    我一直在尝试创建一个数据库 其中所有表都继承某个元素 以便有可能拥有元数据 我在模型生成器的所有表声明中添加了这一行 public Entity addSuperEntity Schema schema Entity superEntity
  • Android TextToSpeech 行为不规则

    更新 经过一番挖掘 我设法在 Logcat 中找到了一些信息 见底部 编辑2 我现在从头开始创建了一个新活动来减少这个问题 它仍然无法正常工作 这是代码 public class MainActivity extends AppCompat
  • 在 IconPageIndicator 中自定义填充和边距

    我正在尝试实现自定义 IconPageIndicator viewpager 我想自定义 com viewpagerindicator IconPageIndicator 中显示的图标的边距和填充 所以我编写了自定义 IconPageInd
  • 如何查找 Android 上剩余的可用存储空间(磁盘空间)? [复制]

    这个问题在这里已经有答案了 我试图找出运行我的应用程序的 Android 手机上的可用磁盘空间 有没有办法以编程方式执行此操作 Thanks 示例 获取人类可读的大小 如 1 Gb 字符串内存 bytesToHuman totalMemor
  • 如何在 ubuntu 14.04 中保持 Android 模拟器始终位于最前面

    如何在 ubuntu 14 04 中保持 Android 模拟器始终位于最前面 我使用的是 Android Studio 2 1 1 和模拟器版本 25 1 6 在将 Android SDK Tools 更新到 25 1 6 之前它可以正常
  • 如何设置评分栏的星星颜色?

    如何设置评分栏的星星颜色 我想要黄色星星 最简单的方法 android progressTint color color 光滑有光泽
  • 查看登录设备

    我想查看Log在设备上 即System out println 我可以查看DDMS但如何在运行时在设备屏幕上查看APK文件 还有一个适用于 Android 的 Logcat 应用程序 code google com p android ra
  • 使用 GestureDetector 时出现 NullPointerException

    下面是在发生不同事件时加载两个不同图像的帧动画的代码 第一个事件是在活动开始时 其他的是onTouch 我在哪里利用GestureDetector为了onDown and onScroll 问题是我得到NullPointerExceptio
  • Android 1.5 在设备上不再显示 Android 应用程序

    我在 Android Market 上的最新更新导致我的应用程序不再适用于 Android 1 5 设备 我更改了以下内容
  • com.google.android.gms.games.GamesClient 无法解析

    我正在尝试使用 google play 游戏服务开发实时多人游戏 并下载了示例 ButtonClicker2000 但 Eclipse ADK 一直抱怨 com google android gms games GamesClient 无法
  • 带 LiveData 的嵌套观察者(观察观察者)

    我有一个案例 我有 BottomNavigationView 其中片段被显示 隐藏而不是添加 替换 因此它们不会每次都经历生命周期 片段1正在观察一个数据库表 片段2正在观察一个不同的 我的目标是调用 onChanged片段2当 on 改变
  • Android从Activity调用Service中的方法

    我想调用一个方法Service对象来自一个Activity对象 但是我发现不可能从MainActivity通常情况下 我希望我的代码能更好地解释我的意思 Service public class Timer extends Service
  • Android NDK __android_log_print函数和LogCat

    我有一个类似的功能 android log print ANDROID LOG INFO HelloNDK 在我的 C 代码上 我在 LogCat 上找不到该输出 我需要设置什么样的过滤器 按日志标签 按日志消息 按应用程序名称 按日志级别
  • 在 Android 谷歌地图中绘制 4K 折线

    我现在正在开发一个适用于 Android 设备的应用程序 主要功能是在地图上绘制折线以显示城市中每条街道的交通情况 不幸的是 当我绘制大约 3K 折线时 数量会根据屏幕尺寸和缩放级别而减少 我的地图变得非常慢 我没有提及绘制所有线条的时间
  • 在 Android 中的计时器内运行异步任务

    我正在开发一个基本的聊天类型应用程序 目前我正在运行代码 如下所示 class GetMsgs extends AsyncTask
  • Android - 减少位图绘制的内存使用量

    我的应用程序中有一张地图 显示了 Gowalla 的位置 我使用带有简单默认标记的 ItemizedOverlay 但在绘制项目时 我将默认标记替换为从 Gowalla 下载 9 并缓存在磁盘上 的位置图标 问题是 如果屏幕上有很多位置 例
  • 在主表单之前显示登录表单

    我在表单之间导航时遇到问题 我使用 Delphi XE5 创建了一个 Android Firemonkey 移动应用程序 我目前有一个登录表单和主表单 现在我想要有关如何处理登录表单以显示在主表单之前的建议 在 项目选项 中的表单下 选择要
  • Android:如何获取小数点后的两位数?不想截断值

    如何获取小数点后仅两位数的双精度值 例如 如果 a 190253 80846153846 那么结果值应该像 a 190253 80 尝试 我尝试过这个 public static DecimalFormat twoDForm new Dec

随机推荐

  • vue 校验表单报错:model is required for validate to wor

    参考https blog csdn net qq 45376290 article details 107346110 1 属性绑定错误 确保绑定的是 model 而不是v model model 是element ui 里面的一个 属性
  • 压缩感知 热身实验 OMP算法Python实现(详细代码注释)

    压缩感知实验 OMP算法Python实现 一维图信号重建 Experiment Result 一维图信号重建 coding utf 8 Created on Wed Sep 23 21 46 43 2020 author chen impo
  • GetLastError返回值及其含义

    GetLastError返回的值通过在api函数中调用SetLastError或SetLastErrorEx设置 函数并无必要设置上一次错误信息 所以即使一次GetLastError调用返回的是零值 也不能担保函数已成功执行 只有在函数调用
  • dhcp和vrrp技术

    目录 引言 一 DHCP工作原理与配置 1 DHCP 动态主机配置协议 2 DHCP工作原理 3 dhcp配置 同网段 4 dhcp中继 不同同网段 5 例子 二 vrrp作用配置 1 vrrp作用 2 vrrp配置 总结 引言 我们每台电
  • Android系统裁剪:手把手教你如何进行系统裁剪

    内容有点长 想系统裁剪 这篇文章足矣 看完会对系统裁剪及系统有更深的认识 前言 android系统裁剪优化一直是各个厂商定制产品的关键步骤 包括浅层次的去除不必要的apk android apk裁剪定制 和深层次的裁剪整个编译系统和框架层
  • 跨境外贸必看

    Pinterest是一个海外图片社交分享网站 Pinterest与国内小红书的营销方式非常相似 它允许我们定位特定的人群 兴趣甚至位置 借助庞大的用户群体和针对特定受众的能力 它成为外贸与跨境电商的推广营销利器 越来越多的跨境玩家利用它进行
  • 虚拟机opnsense作为dhcp服务器,在OPNsense中,通过主机名或域名访问内部设备

    在局域网环境中 使用域名来访问防火墙或其他设备比使用IP地址更容易让人使用 根据需要 我们可以只使用主机名 服务器 来访问设备上的各种服务 例如文件共享 它比包含域名的名称要短 如果打算运行Web服务器或运行具有Web界面的软件 则可能需要
  • Faster RCNN训练自己的数据集【傻瓜式教程】

    一 下载源码 本文采用的源码是 https github com dBeker Faster RCNN TensorFlow Python3 二 配置环境 由于本文是小白教程 光写几个环境怕有人配置不好或者配置版本搞乱 Faster RCN
  • ELK之Elasticsearch常用DSL语句(kibana语句)

    DSL 是什么 DSL Domain Specific Language 的缩写 中文翻译为领域特定语言 Wikipedia 对于 DSL 的定义还是比较简单的 A specialized computer language designe
  • 8.2.3-elasticsearch内置分词器之keyword/pattern

    ES默认提供了八种内置的analyzer 针对不同的场景可以使用不同的analyzer 1 keyword analyzer 1 1 keyword类型及分词效果 keyword analyzer视字符串为一个整体不进行分词处理 测试key
  • Java多线程编程基础篇(二)-多线程同步关键字

    一 多线程同步关键字 synchronized 1 概念 synchronized保证方法或者代码块在运行时 同一时刻只有一个方法可以进入到临界区 同时它还可以保证共享变量的内存可见性 当多个并发线程访问同一个对象object中的同步代码块
  • mysql 用户流失_利用SQL对平台用户行为进行分析

    一 提出问题 1 平台的用户流失情况是怎样的 2 造成该种流失情况是原因是什么 二 理解数据 1 数据来源 https tianchi aliyun com dataset dataDetail dataId 649 userId 1 本数
  • svn 新建文件不能直接提交终于解决了

    preface 一直在做的一个项目最近要上线了 之前一直遗留了一个 svn 问题 新创建的文件不能 直接在外层目录直接提交 只能一级一级 的先添加目录 然后添加目录中的文件 最后在外层目录提交 因为写得东西太多 总不可避免的 会有遗漏提交
  • c++堆栈类模板实现

    最近在复习数据结构 涉及到堆栈的实现 通过类模板可以使堆栈的存储数据类型更为灵活 下面是堆栈的实现代码 ifndef MYSTACK H define MYSTACK H include
  • Spring-Boot-MainApplication 类文件的位置

    搭建 SpringBoot 项目时有一个主程序入口类 这个 MainApp 类必须在放在整个项目的最根目录 Spring 在扫描注解的时候是扫描这个文件所在包以下的所有Class 如果其他类放在了高于这个类或其他目录下就会扫描不到 impo
  • [思考进阶]01 如何克服自己的无知?

    除了要提升自己的技术能力 思维的学习和成长也非常非常重要 特推出此 思考进阶 系列 进行刻意练习 从而提升自己的认知 有段时间我特别喜欢研究一些定律和法则 比如 熵增定律 懒蚂蚁效应 蝴蝶效应 吸引力法则 多米诺效应等等 大部分都是看书或者
  • c8051f120的spi应用总结

    spi应用总结 主控程序中SPI通信的铁电 想用FEDR45V100A 替代FM25V10 发现铁电存储时波形正常 但读出数据都为0xff 还在查找问题中 一 主控界面 设置 gt 管理员设置 gt 5网络参数设置 gt 4导出参数 5导入
  • 高并发,你真的理解透彻了吗?

    高并发 几乎是每个程序员都想拥有的经验 原因很简单 随着流量变大 会遇到各种各样的技术问题 比如接口响应超时 CPU load升高 GC频繁 死锁 大数据量存储等等 这些问题能推动我们在技术深度上不断精进 在过往的面试中 如果候选人做过高并
  • 已启用Azure Arc的Kubernetes第2部分:添加安全性和监视

    目录 设置Microsoft Defender for Clound 启用Microsoft Defender 安装Microsoft Defender for Kubernetes Cluster Extension 设置Azure Mo
  • android 音乐波动动画

    需求 在播放音乐的时候 随机产生不规律动画 下载地址 http download csdn net detail qq 28195645 9700355 自定义音乐波动控件 package com sun audioplayingwave