Android实现简易版弹钢琴效果
参考于:https://www.jb51.net/article/161904.htm
最近由于要写Android的期末报告,老师让写一个类似于钢琴的小程序, 但对深受网课熏陶的我来说,嗯!!! 这是个大问题,一学期快结束了,课没怎么听,回放还没有???这作业怎么写??? 于是,百度出现了,百度是真的香!!! 虽然,他广告多,还收费,链接假……但他实用!!! 嗯,不会写作业 ???问度娘就好了。于是参考了上面链接的东西。 说实话,第一遍看,没怎么看懂!! 确实,毕竟没听课嘛,也不为过,都是这考试的错,毕竟量劫来袭,贫道闭关静颂黄庭! 不怨我!毕竟家里网不好,住在山沟沟里……反正各种理由就是不想上网课。 但是要写作业,毕竟不想挂科!!!
好了,终止废话。干货如下:
- 整个钢琴实现的效果图
- 整个APP的整体框架!!!!!这里很重要!!!!
- 1.新建activity_main.xml文件源码
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/parents"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/background">
<LinearLayout
android:id="@+id/llKeys"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="5"
android:layout_alignParentBottom="true"
android:orientation="horizontal"
android:padding="10dp" >
<Button
android:id="@+id/iv_do"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/icon_do" />
<Button
android:id="@+id/iv_re"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/icon_re" />
<Button
android:id="@+id/iv_mi"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/icon_mi"/>
<Button
android:id="@+id/iv_fa"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/icon_fa"/>
<Button
android:id="@+id/iv_so"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/icon_so"/>
<Button
android:id="@+id/iv_la"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/icon_la" />
<Button
android:id="@+id/iv_si"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/icon_si"/>
</LinearLayout>
</RelativeLayout>
- 2.新建PanioMusic.java文件
/**
* 音乐播放工具类
*/
import java.util.HashMap;
import android.content.Context;
import android.media.AudioManager;
import android.media.SoundPool;
import com.example.pinao.R;
public class Pinao {
// 资源文件
int Music[] = {R.raw.dol, 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 Pinao(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();
}
}
- 3.新建MainActivity.java文件
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.pinao.Pinao;
public class MainActivity extends Activity {
private Button button[];// 按钮数组
private Pinao 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.parents);
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]) {// 在某个按键范围内
// 播放音阶
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) {// 移入的按键没有按下
// 发音
utils.soundPlay(i);
havePlayed[i] = true;
}
pressedkey[count] = i;
if (!laststill) {// 没有手指按在上面
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) {// 已经没有手指按在该键上
havePlayed[temp] = false;
Log.i("--", "button" + temp + "up");
}
break;
}
}
}
//
if (event.getActionMasked() == MotionEvent.ACTION_MOVE
&& !moveflag) {
if (pressedkey[count] != -1) {
havePlayed[pressedkey[count]] = false;
}
}
}
return false;
}
});
keys = (View) findViewById(R.id.llKeys);
}
private void init() {
// 新建工具类
utils = new Pinao(getApplicationContext());
// 按钮资源Id
buttonId = new int[7];
buttonId[0] = R.id.iv_do;
buttonId[1] = R.id.iv_re;
buttonId[2] = R.id.iv_mi;
buttonId[3] = R.id.iv_fa;
buttonId[4] = R.id.iv_so;
buttonId[5] = R.id.iv_la;
buttonId[6] = R.id.iv_si;
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;
}
}
以上就是全部源码文件!!!
-
至于相关的音频素材可自行百度获取。
-
源码文件素材地址:https://download.csdn.net/download/m0_46153949/12536768