Android实现简易版弹钢琴效果
程序员文章站
2023-10-22 16:37:34
本文实例为大家分享了android实现弹钢琴效果展示的具体代码,供大家参考,具体内容如下
目标效果:
1.drawable下新建button_selector.xm...
本文实例为大家分享了android实现弹钢琴效果展示的具体代码,供大家参考,具体内容如下
目标效果:
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" > <corners android:bottomleftradius="10dp" android:bottomrightradius="10dp" > </corners> <stroke android:width="2dp" android:color="#605c59" /> <gradient android: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" /> <corners android:bottomleftradius="10dp" android:bottomrightradius="10dp" > </corners> <stroke android: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); } @override protected 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" > <linearlayout android:id="@+id/llkeys" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="5" android:orientation="horizontal" android:padding="10dp" > <button android:id="@+id/btpanioone" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:background="@drawable/button" android:text="1" /> <button android:id="@+id/btpaniotwo" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:background="@drawable/button" android:text="2" /> <button android:id="@+id/btpaniothree" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:background="@drawable/button" android:text="3" /> <button android:id="@+id/btpaniofour" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:background="@drawable/button" android:text="4" /> <button android:id="@+id/btpaniofive" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:background="@drawable/button" android:text="5" /> <button android:id="@+id/btpaniosix" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:background="@drawable/button" android:text="6" /> <button android: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[];// 按钮id private boolean haveplayed[];// 是否已经播放了声音,当手指在同一个按钮内滑动,且已经发声,就为true private view keys;// 按钮们所在的视图 private int pressedkey[]; @override protected 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() { @override public 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()); // 按钮资源id buttonid = 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贝塞尔曲线实现手指轨迹