目标效果:

 

1.drawable下新建button_selector.xml页面:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"><item android:drawable="@drawable/button_pressed" android:state_pressed="true"></item><item android:drawable="@drawable/button"></item></selector>

2.drawable下新建button.xml页面:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" ><cornersandroid:bottomLeftRadius="10dp"android:bottomRightRadius="10dp" ></corners><strokeandroid:width="2dp"android:color="#605C59" /><gradientandroid:angle="270"android:endColor="#FFFFFF"android:startColor="#F5F5F5" /></shape>
3.drawable下新建button_pressed.xml页面:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" ><solid android:color="#A4A4A4" /><cornersandroid:bottomLeftRadius="10dp"android:bottomRightRadius="10dp" ></corners><strokeandroid:width="2dp"android:color="#605C59" /></shape>
4.新建PanioMusic.java类
package com.example.weixu.view;/*** 音乐播放帮助类*/import java.util.HashMap;
import android.content.Context;
import android.media.AudioManager;
import android.media.SoundPool;import com.example.weixu.playpanio.R;public class PanioMusic {// 资源文件int Music[] = {R.raw.do1, R.raw.re2, R.raw.mi3, R.raw.fa4, R.raw.sol5,R.raw.la6, R.raw.si7,};SoundPool soundPool;HashMap<Integer, Integer> soundPoolMap;public PanioMusic(Context context) {soundPool = new SoundPool(2, AudioManager.STREAM_MUSIC, 100);soundPoolMap = new HashMap<Integer, Integer>();for (int i = 0; i < Music.length; i++) {soundPoolMap.put(i, soundPool.load(context, Music[i], 1));}}public int soundPlay(int no) {return soundPool.play(soundPoolMap.get(no), 100, 100, 1, 0, 1.0f);}public int soundOver() {return soundPool.play(soundPoolMap.get(1), 100, 100, 1, 0, 1.0f);}@Overrideprotected void finalize() throws Throwable {soundPool.release();super.finalize();}
}
5.activity_main.xml页面:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/llparent"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".MainActivity" ><LinearLayoutandroid:id="@+id/llKeys"android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="5"android:orientation="horizontal"android:padding="10dp" ><Buttonandroid:id="@+id/btPanioOne"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:background="@drawable/button"android:text="1" /><Buttonandroid:id="@+id/btPanioTwo"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:background="@drawable/button"android:text="2" /><Buttonandroid:id="@+id/btPanioThree"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:background="@drawable/button"android:text="3" /><Buttonandroid:id="@+id/btPanioFour"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:background="@drawable/button"android:text="4" /><Buttonandroid:id="@+id/btPanioFive"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:background="@drawable/button"android:text="5" /><Buttonandroid:id="@+id/btPanioSix"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:background="@drawable/button"android:text="6" /><Buttonandroid:id="@+id/btPanioSeven"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:background="@drawable/button"android:text="7" /></LinearLayout></LinearLayout>
6.MainActivity.java页面:
package com.example.weixu.playpanio;import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.Button;import com.example.weixu.view.PanioMusic;public class MainActivity extends Activity {private Button button[];// 按钮数组private PanioMusic utils;// 工具类private View parent;// 父视图private int buttonId[];// 按钮idprivate boolean havePlayed[];// 是否已经播放了声音,当手指在同一个按钮内滑动,且已经发声,就为trueprivate View keys;// 按钮们所在的视图private int pressedkey[];@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);init();parent = (View) findViewById(R.id.llparent);parent.setClickable(true);parent.setOnTouchListener(new OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {int temp;int tempIndex;int pointercount;pointercount = event.getPointerCount();for (int count = 0; count < pointercount; count++) {boolean moveflag = false;// 标记是否是在按键上移动temp = isInAnyScale(event.getX(count), event.getY(count),button);if (temp != -1) {// 事件对应的是当前点switch (event.getActionMasked()) {case MotionEvent.ACTION_DOWN:// // 单独一根手指或最先按下的那个// pressedkey = temp;case MotionEvent.ACTION_POINTER_DOWN:Log.i("--", "count" + count);pressedkey[count] = temp;if (!havePlayed[temp]) {// 在某个按键范围内button[temp].setBackgroundResource(R.drawable.button_pressed);// 播放音阶utils.soundPlay(temp);Log.i("--", "sound" + temp);havePlayed[temp] = true;}break;case MotionEvent.ACTION_MOVE:temp = pressedkey[count];for (int i = temp + 1; i >= temp - 1; i--) {// 当在两端的按钮时,会有一边越界if (i < 0 || i >= button.length) {continue;}if (isInScale(event.getX(count),event.getY(count), button[i])) {// 在某个按键内moveflag = true;if (i != temp) {// 在相邻按键内boolean laststill = false;boolean nextstill = false;// 假设手指已经从上一个位置抬起,但是没有真的抬起,所以不移位pressedkey[count] = -1;for (int j = 0; j < pointercount; j++) {if (pressedkey[j] == temp) {laststill = true;}if (pressedkey[j] == i) {nextstill = true;}}if (!nextstill) {// 移入的按键没有按下// 设置当前按键button[i].setBackgroundResource(R.drawable.button_pressed);// 发音utils.soundPlay(i);havePlayed[i] = true;}pressedkey[count] = i;if (!laststill) {// 没有手指按在上面// 设置上一个按键button[temp].setBackgroundResource(R.drawable.button);havePlayed[temp] = false;}break;}}}break;case MotionEvent.ACTION_UP:case MotionEvent.ACTION_POINTER_UP:// 事件与点对应tempIndex = event.getActionIndex();if (tempIndex == count) {Log.i("--", "index" + tempIndex);boolean still = false;// 当前点已抬起for (int t = count; t < 5; t++) {if (t != 4) {if (pressedkey[t + 1] >= 0) {pressedkey[t] = pressedkey[t + 1];} else {pressedkey[t] = -1;}} else {pressedkey[t] = -1;}}for (int i = 0; i < pressedkey.length; i++) {// 是否还有其他点if (pressedkey[i] == temp) {still = true;break;}}if (!still) {// 已经没有手指按在该键上button[temp].setBackgroundResource(R.drawable.button);havePlayed[temp] = false;Log.i("--", "button" + temp + "up");}break;}}}//if (event.getActionMasked() == MotionEvent.ACTION_MOVE&& !moveflag) {if (pressedkey[count] != -1) {button[pressedkey[count]].setBackgroundResource(R.drawable.button);havePlayed[pressedkey[count]] = false;}}}return false;}});keys = (View) findViewById(R.id.llKeys);}private void init() {// 新建工具类utils = new PanioMusic(getApplicationContext());// 按钮资源IdbuttonId = new int[7];buttonId[0] = R.id.btPanioOne;buttonId[1] = R.id.btPanioTwo;buttonId[2] = R.id.btPanioThree;buttonId[3] = R.id.btPanioFour;buttonId[4] = R.id.btPanioFive;buttonId[5] = R.id.btPanioSix;buttonId[6] = R.id.btPanioSeven;button = new Button[7];havePlayed = new boolean[7];// 获取按钮对象for (int i = 0; i < button.length; i++) {button[i] = (Button) findViewById(buttonId[i]);button[i].setClickable(false);havePlayed[i] = false;}pressedkey = new int[5];for (int j = 0; j < pressedkey.length; j++) {pressedkey[j] = -1;}}/*** 判断某个点是否在某个按钮的范围内** @param x      横坐标* @param y      纵坐标* @param button 按钮对象* @return 在:true;不在:false*/private boolean isInScale(float x, float y, Button button) {// keys.getTop()是获取按钮所在父视图相对其父视图的右上角纵坐标if (x > button.getLeft() && x < button.getRight()&& y > button.getTop() + keys.getTop()&& y < button.getBottom() + keys.getTop()) {return true;} else {return false;}}/*** 判断某个点是否在一个按钮集合中的某个按钮内** @param x      横坐标* @param y      纵坐标* @param button 按钮数组* @return*/private int isInAnyScale(float x, float y, Button[] button) {// keys.getTop()是获取按钮所在父视图相对其父视图的右上角纵坐标for (int i = 0; i < button.length; i++) {if (x > button[i].getLeft() && x < button[i].getRight()&& y > button[i].getTop() + keys.getTop()&& y < button[i].getBottom() + keys.getTop()) {return i;}}return -1;}
}
7.AndroidManifest.xml页面对某个Activity页面进行设置横屏
android:screenOrientation="landscape"
8.另外,每个按键的音效需要提前导入res下raw文件夹中。
源码: 点击打开链接

Android-简易版弹钢琴相关推荐

  1. Android钢琴滑动代码,Android实现简易版弹钢琴效果

    本文实例为大家分享了Android实现弹钢琴效果展示的具体代码,供大家参考,具体内容如下 目标效果: 1.drawable下新建button_selector.xml页面: 2.drawable下新建 ...

  2. Android实现简易版日记本notePad

    今天实现一个日常中大家可能会使用到的功能-日记本,也可以说是备忘录,并已实现兼容androidX和深色模式. app中使用Androidx中的Room数据库,Room持久数据库提供了一个SQLite抽 ...

  3. Android之登录注册——简易版

    今天,我要分享给大家的是Android中常见的一个的登录注册的案例,我这里写的是简易版,如果大家有更精彩的拓展,可以自行发挥哦! 运行过程相信大家都已经心知肚明了,所以我在这里就直接发布代码了,其中有 ...

  4. Android拦截黑名单(简易版)

    拦截黑名单的话,一般都是去系统数据库里面取值,判断来电手机号码或者短信号码是否在我黑名单数据中是否存在.如果存在就拦截.而我这里就投机取巧了,没有去数据库.只是简单的拦截,将数据写死了! 来上代码: ...

  5. 【Android笔记65】Android小案例之简易版的房贷计算器(附源代码)

    这篇文章,主要介绍如何使用Android实现一个简易版的房贷计算器小案例. 目录 一.房贷计算器 1.1.运行效果演示 1.2.前提准备 (1)等额本息和等额本金

  6. Android简易音乐重构MVVM Java版 -搭建项目(八)

    Android简易音乐重构MVVM Java版 -搭建项目(八) 关于 新版本配置 网易云音乐api版本更新 重构代码 新建app类继承Application 项目结构 定义BaseActivity. ...

  7. Android简易音乐重构MVVM Java版-新增推荐菜单及侧边栏展示(十二)

    Android简易音乐重构MVVM Java版-新增推荐菜单及侧边栏展示(十二) 关于 效果图 添加侧边栏 添加推荐歌单 新增RecommendAdapter适配器 修改DiscoverFragmen ...

  8. android 实现qq动画,Android项目:简易版QQ的实现

    简易版QQ实现涉及的三个功能模块 引导界面 splash界面(静态) 1.作用:初始化服务器端的一些数据,初始化成功后跳转到主界面 2.页面的延迟跳转: //在主线程中: new Handler(). ...

  9. Android简易音乐重构MVVM Java版-新增推荐雷达歌单及重构首页(十三)

    Android简易音乐重构MVVM Java版-新增推荐雷达歌单及重构首页(十三) 关于 效果图 修改ApiService 添加HomeDiscoverEntity实体类 添加BannerExtInf ...

最新文章

  1. flex自定义的分区域状态显示控件——原创
  2. linux登录主机命令,linux w命令查询已登录主机的用户信息
  3. 栈和队列的共同点和不同点
  4. 小米路由做文件共享服务器,群晖NAS+小米路由器文件直接传输
  5. 《python初级爬虫》(一)
  6. Win10切换用户,开始菜单,应用都不见了
  7. C. Candy Store(数学)
  8. 我同学——应聘阿里巴巴之经过
  9. html内容页上一页下一页,帝国CMS内容页增加内容分页上一页标签功能!
  10. android源代码文件结构
  11. vue检测当前是什么浏览器
  12. springboot以FTP方式上传文件到远程服务器
  13. win7计算机 我的文档,轻松转移Win7系统我的文档库保存位置
  14. 使用深度学习识别狗的品种
  15. sap服务器文件上传,服务器上传数据sap
  16. 5 款最好的免费 SSD 数据恢复软件
  17. JSP页面传值到JSP页面
  18. js_实现网页自动跳转
  19. Apple iOS产品硬件参数.
  20. 服务器被入侵怎么办?看我操作!

热门文章

  1. Python爬虫 爬取豆瓣读书
  2. python开发前端后端区别_前端开发与后端开发有什么区别?
  3. cortex a7 a53_奥迪A7 升级原厂空气悬挂、FOGIAGO碳纤维进气套件、自动泊车辅助-改装作品...
  4. Ubuntu开机卡在 A start job is runing for wait for Network to be configured (1min 23s / no limit)解决方法
  5. prometheus 添加 login 登录认证界面(nginx + flask 实现)
  6. 行业追踪,2023-07-04,受特斯拉中报影响,汽车零部件放量强势拉升,不调整
  7. 【数据分析】绘制统计图
  8. 二进制二维码转换图片
  9. java.李雷和韩梅梅的加密纸条
  10. C++程序设计:圆桌问题