服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Android - Android实现简易版弹钢琴效果

Android实现简易版弹钢琴效果

2022-10-18 13:33Vivinia_Vivinia Android

这篇文章主要为大家详细介绍了Android实现简易版弹钢琴效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文实例为大家分享了Android实现弹钢琴效果展示的具体代码,供大家参考,具体内容如下

目标效果:

Android实现简易版弹钢琴效果

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

?
1
2
3
4
5
6
7
<?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页面:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?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页面:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?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类

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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页面:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
<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页面:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
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页面进行设置横屏

?
1
android:screenOrientation="landscape"

8.另外,每个按键的音效需要提前导入res下raw文件夹中。

源码:点击打开链接

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/hester_hester/article/details/69942859

延伸 · 阅读

精彩推荐