Android实现简易版弹钢琴效果

软件发布|下载排行|最新软件

当前位置:首页IT学院IT技术

Android实现简易版弹钢琴效果

  2021-04-03 我要评论

目标效果:

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文件夹中。

源码:点击打开链接

您可能感兴趣的文章:

Copyright 2022 版权所有 软件发布 访问手机版

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 联系我们