Android版网易云音乐唱片机唱片磁盘旋转及唱片机机械臂动画关键代码实现思路

先看一看我的代码运行结果。

代码运行起来初始化状态:

点击开始按钮,唱片机的机械臂匀速接近唱片磁盘,同时唱片磁盘也开始匀速顺时针旋转:

点击停止按钮,唱片机的机械臂匀速抬离唱片磁盘,同时唱片磁盘停止旋转:

实现思路:

(一)旋转唱片磁盘。在附录文章12的基础上,实现网易云音乐风格的唱片磁盘。核心代码:

 //最外部的半透明边线
OvalShape ovalShape0 = new OvalShape();
ShapeDrawable drawable0 = new ShapeDrawable(ovalShape0);
drawable0.getPaint().setColor(0x10000000);
drawable0.getPaint().setStyle(Paint.Style.FILL);
drawable0.getPaint().setAntiAlias(true); //黑色唱片边框
RoundedBitmapDrawable drawable1 = RoundedBitmapDrawableFactory.create(getResources(), BitmapFactory.decodeResource(getResources(), R.drawable.disc));
drawable1.setCircular(true);
drawable1.setAntiAlias(true); //内层黑色边线
OvalShape ovalShape2 = new OvalShape();
ShapeDrawable drawable2 = new ShapeDrawable(ovalShape2);
drawable2.getPaint().setColor(Color.BLACK);
drawable2.getPaint().setStyle(Paint.Style.FILL);
drawable2.getPaint().setAntiAlias(true); //最里面的图像
RoundedBitmapDrawable drawable3 = RoundedBitmapDrawableFactory.create(getResources(), BitmapFactory.decodeResource(getResources(), R.drawable.zhangphil));
drawable3.setCircular(true);
drawable3.setAntiAlias(true); Drawable[] layers = new Drawable[4];
layers[0] = drawable0;
layers[1] = drawable1;
layers[2] = drawable2;
layers[3] = drawable3; LayerDrawable layerDrawable = new LayerDrawable(layers); int width = 10;
//针对每一个图层进行填充,使得各个圆环之间相互有间隔,否则就重合成一个了。
//layerDrawable.setLayerInset(0, width, width, width, width);
layerDrawable.setLayerInset(1, width , width, width, width );
layerDrawable.setLayerInset(2, width * 11, width * 11, width * 11, width * 11);
layerDrawable.setLayerInset(3, width * 12, width * 12, width * 12, width * 12); final View discView = findViewById(R.id.myView);
discView.setBackgroundDrawable(layerDrawable);

唱片磁盘旋转,则通过属性动画ObjectAnimator实现唱片磁盘的顺时针旋转:

 discObjectAnimator = ObjectAnimator.ofFloat(discView, "rotation", 0, 360);
discObjectAnimator.setDuration(20000);
//使ObjectAnimator动画匀速平滑旋转
discObjectAnimator.setInterpolator(new LinearInterpolator());
//无限循环旋转
discObjectAnimator.setRepeatCount(ValueAnimator.INFINITE);
discObjectAnimator.setRepeatMode(ValueAnimator.INFINITE);

(二)唱片机的机械臂。在相对布局的顶部放置一个ImageView,这个ImageView就是机械臂的素材,当点击开始按钮时候,就使用Android属性动画操作该ImageView以左上角坐标位置(x=0,y=0)向下顺时针匀速旋转一定角度使得机械臂刚好落入到唱片磁盘内。当点击停止按钮时候,一方面控制唱片磁盘停止旋转,另一方面要操纵机械臂匀速逆时针向上旋转离开唱片磁盘。

我写的这个例子需要布局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/background"> <View
android:id="@+id/myView"
android:layout_width="300dp"
android:layout_height="300dp"
android:layout_centerInParent="true" /> <ImageView
android:id="@+id/needle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:adjustViewBounds="true"
android:maxHeight="180dp"
android:src="@drawable/needle" /> <Button
android:id="@+id/startButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:text="开始" /> <Button
android:id="@+id/stopButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:text="停止" /> </RelativeLayout>

上层全部完整Java代码:

package zhangphil.app;

import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
import android.os.Bundle;
import android.view.View;
import android.view.animation.LinearInterpolator;
import android.widget.ImageView; public class MainActivity extends Activity {
private ObjectAnimator discObjectAnimator,neddleObjectAnimator; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); //最外部的半透明边线
OvalShape ovalShape0 = new OvalShape();
ShapeDrawable drawable0 = new ShapeDrawable(ovalShape0);
drawable0.getPaint().setColor(0x10000000);
drawable0.getPaint().setStyle(Paint.Style.FILL);
drawable0.getPaint().setAntiAlias(true); //黑色唱片边框
RoundedBitmapDrawable drawable1 = RoundedBitmapDrawableFactory.create(getResources(), BitmapFactory.decodeResource(getResources(), R.drawable.disc));
drawable1.setCircular(true);
drawable1.setAntiAlias(true); //内层黑色边线
OvalShape ovalShape2 = new OvalShape();
ShapeDrawable drawable2 = new ShapeDrawable(ovalShape2);
drawable2.getPaint().setColor(Color.BLACK);
drawable2.getPaint().setStyle(Paint.Style.FILL);
drawable2.getPaint().setAntiAlias(true); //最里面的图像
RoundedBitmapDrawable drawable3 = RoundedBitmapDrawableFactory.create(getResources(), BitmapFactory.decodeResource(getResources(), R.drawable.zhangphil));
drawable3.setCircular(true);
drawable3.setAntiAlias(true); Drawable[] layers = new Drawable[4];
layers[0] = drawable0;
layers[1] = drawable1;
layers[2] = drawable2;
layers[3] = drawable3; LayerDrawable layerDrawable = new LayerDrawable(layers); int width = 10;
//针对每一个图层进行填充,使得各个圆环之间相互有间隔,否则就重合成一个了。
//layerDrawable.setLayerInset(0, width, width, width, width);
layerDrawable.setLayerInset(1, width , width, width, width );
layerDrawable.setLayerInset(2, width * 11, width * 11, width * 11, width * 11);
layerDrawable.setLayerInset(3, width * 12, width * 12, width * 12, width * 12); final View discView = findViewById(R.id.myView);
discView.setBackgroundDrawable(layerDrawable); ImageView needleImage= (ImageView) findViewById(R.id.needle); findViewById(R.id.startButton).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
discObjectAnimator.start();
neddleObjectAnimator.start();
}
}); findViewById(R.id.stopButton).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
discObjectAnimator.cancel();
neddleObjectAnimator.reverse();
}
}); discObjectAnimator = ObjectAnimator.ofFloat(discView, "rotation", 0, 360);
discObjectAnimator.setDuration(20000);
//使ObjectAnimator动画匀速平滑旋转
discObjectAnimator.setInterpolator(new LinearInterpolator());
//无限循环旋转
discObjectAnimator.setRepeatCount(ValueAnimator.INFINITE);
discObjectAnimator.setRepeatMode(ValueAnimator.INFINITE); neddleObjectAnimator = ObjectAnimator.ofFloat(needleImage, "rotation", 0, 25);
needleImage.setPivotX(0);
needleImage.setPivotY(0);
neddleObjectAnimator.setDuration(800);
neddleObjectAnimator.setInterpolator(new LinearInterpolator());
}
}

遗留问题:

(1)实际上,右上角机械臂这个ImageView以(x=0,y=0)的坐标位置旋转不是很恰当,因为这个机械臂作为图像素材,它本身的左上角肯定有部分空间位置,使得旋转时候不能够刚好以图中机械臂左上角那个螺丝衔接的位置旋转,也许是把机械臂衔接螺丝那个位置遮挡起来就像网易云音乐的做法,但是更完美的处理方法,我个人感觉勇应该分段设计这个机械臂:在素材设计上,把这个机械臂分为两段设计,最上的那个衔接螺丝单独抽出来,固定在布局上,然后螺丝下面把机械臂的尾部遮挡起来,旋转只选择机械臂,这样旋转就非常逼真。

(2)从代码中可以看出里面很多位置、角度、距离的值都是写死的,比如机械臂旋转的角度,机械臂的最大高度等等,作为demo说明解决方案没问题,但是在涉及到千百种Android屏幕尺寸各异的设备时候,情况变得比较复杂,要精心计算这些空间位置距离。

(3)发现一个Android自身的问题。在本例中,如果把背景图片background.jpg换成更高质量和分辨率的图如1080 X 1920,则动画执行非常之卡。但是如果把背景图片质量换成低分辨率图540 X 960则不影响动画执行效率。

我写的这个例子中用到的一些素材。

整个背景图background.jpg:

唱片机的机械臂needle.png

唱片磁盘包括头像的外部黑色外圈disc.png:

头像是我csdn的博客头像:

附录:

1,《Android动画Animation的两种加载执行方式》链接地址:http://blog.csdn.net/zhangphil/article/details/47394225


2,《Android AnimationDrawable动画与APP启动引导页面》链接地址:http://blog.csdn.net/zhangphil/article/details/47416915  


3,《Android layer-list(1)》链接地址:http://blog.csdn.net/zhangphil/article/details/517209244

4,《Android layer-list:联合shape(2)》链接地址:http://blog.csdn.net/zhangphil/article/details/51721283 


5,《Android layer-list(3)》链接地址:http://blog.csdn.net/zhangphil/article/details/51721816


6,《Android Property Animation属性动画初识:透明渐变(1)》链接地址:http://blog.csdn.net/zhangphil/article/details/50484224   


7,《Android Property Animation属性动画:rotation旋转(2)》链接地址:http://blog.csdn.net/zhangphil/article/details/50495555  


8,《Android Property Animation属性动画初识:位移translation(3)》链接地址:http://blog.csdn.net/zhangphil/article/details/50495844 


9,《Android Property Animation属性动画:scale缩放动画(4)》链接地址:http://blog.csdn.net/zhangphil/article/details/50497404


10,《Android Property Animation属性动画集:AnimatorSet(5)》链接地址:http://blog.csdn.net/zhangphil/article/details/50498531


11,《Android ImageView加载圆形图片且同时绘制圆形图片的外部边缘边线及边框》链接地址:http://blog.csdn.net/zhangphil/article/details/51944262


12,《Android View加载圆形图片且同时绘制圆形图片的外部边缘边线及边框:LayerDrawable实现》链接:http://blog.csdn.net/zhangphil/article/details/52035255

Android版网易云音乐唱片机唱片磁盘旋转及唱片机机械臂动画关键代码实现思路的更多相关文章

  1. android仿网易云音乐引导页、仿书旗小说Flutter版、ViewPager切换、爆炸菜单、风扇叶片效果等源码

    Android精选源码 复现网易云音乐引导页效果 高仿书旗小说 Flutter版,支持iOS.Android Android Srt和Ass字幕解析器 Material Design ViewPage ...

  2. Android开发——网易云音乐使用的开源组件集合

    前言 网易云音乐Android版从第一版使用到现在,全新的 Material Design 界面,更加清新.简洁.同样也是音乐播放器开发者,我们确实需要思考,相同的功能,会如何选择.感谢开源,让我们有 ...

  3. 由 UWP 版网易云音乐闪退引发的博文

    今天,不知怎么的.网易云音乐出现了一打开就闪退的情况.百度了好些时候未果,就直接 Windows + i 打开 Windows 设置 > 应用 在应用和功能列表中找到网易云音乐,在展开的 高级选 ...

  4. Linux版网易云音乐播放音乐时无限显示“网络错误”的解决办法

    安装 gstreamer0.10-plugins-good debian类系统: -plugins-good

  5. 实现一个网易云音乐的 BottomSheetDialog

    作者:林冠宏 / 指尖下的幽灵 掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8 博客:http://www.cnblogs.com/linguan ...

  6. 用RotateDrawable实现网易云音乐唱片机效果

    imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="唱片机" title=""> ...

  7. [转]网易云音乐Android版使用的开源组件

    原文链接 网易云音乐Android版从第一版使用到现在,全新的 Material Design 界面,更加清新.简洁.同样也是音乐播放器开发者,我们确实需要思考,相同的功能,会如何选择.感谢开源,让我 ...

  8. 【第二版】高仿Android网易云音乐企业级项目实战课程介绍

    这是一门付费Android项目课程,我们只做付费课程:同时也感谢大家的支持. 这一节,对本课程做一个简单介绍,以及放一些项目效果图,如果想直接查看项目视频演示,可以直接在腾讯课堂查看[高仿Androi ...

  9. 高仿Android网易云音乐OkHttp+Retrofit+RxJava+Glide+MVC+MVVM

    简介 这是一个使用Java(以后还会推出Kotlin版本)语言,从0开发一个Android平台,接近企业级的项目(我的云音乐),包含了基础内容,高级内容,项目封装,项目重构等知识:主要是使用系统功能, ...

随机推荐

  1. HDU 4366 Successor 分块做法

    http://acm.hdu.edu.cn/showproblem.php?pid=4366 今日重新做了这题的分块,果然是隔太久了,都忘记了.. 首先,用DFS序变成一维的问题 关键是它有两个权值, ...

  2. LVS实现负载均衡

    三台主机模拟 sishen_63(分发器): eth0(Bridge):192.168.1.63 eth1(vmnet4):192.168.2.63 sishen_64(RealServer1): e ...

  3. 降低winnt Apache服务的权限,让你的虚拟主机更安全

    winnt 安装 Apache 后,在后台的服务默认是以system权限运行的(system是winnt的最高权限),这给服务器带来很大的安全隐患,最近我遇到的就是php的W8C 文件管理既然可以随意 ...

  4. Visual Studio Code配置 HTML 开发环境

    Visual Studio Code配置 HTML 开发环境 https://v.qq.com/x/page/l0532svf47c.html?spm=a2h0k.11417342.searchres ...

  5. 动手实现 Redux(四):共享结构的对象提高性能

    接下来两节某些地方可能会稍微有一点点抽象,但是我会尽可能用简单的方式进行讲解.如果你觉得理解起来有点困难,可以把这几节多读多理解几遍,其实我们一路走来都是符合“逻辑”的,都是发现问题.思考问题.优化代 ...

  6. hadoop的安装和配置

    hadoop安装 在Apache Hadoop主页的下载页面https://hadoop.apache.org/releases.html选择版本进行下载: 下载下来的是压缩包: 将压缩包使用Xftp ...

  7. 修改他人电脑的Windows登录密码

    在别人电脑已登录Windows的情况下: 打开控制面板 -> 管理工具 -> 计算机管理   或者  对Win图标单击右键 -> 计算机管理 -> 本地用户和组 -> 用 ...

  8. 【经验总结】VS2010下建立MFC程序

    孙鑫的MFC教学视频非常不错,但是由于视频中孙鑫老师采用VC6.0版本,而现在 许多人都转向了使用VS,VS为我们生成了许多不需要的代码,这也导致在这节课的学习编程中总是遇到一些困难.那么,如何去掉这 ...

  9. requirejs&&springboot

    1.Spring Boot Spring boot 基础结构主要有三个文件夹: (1)src/main/java  程序开发以及主程序入口 (2)src/main/resources 配置文件 (3) ...

  10. Kotlin学习的一些笔记

    Introduction 写在前面 关于本书 这本书适合你吗? 关于作者 介绍 什么是Kotlin? 我们通过Kotlin得到什么 准备工作 Android Studio 安装Kotlin插件 创建一 ...