溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Android如何實現(xiàn)簡易版彈鋼琴效果

發(fā)布時間:2021-04-16 10:09:05 來源:億速云 閱讀:223 作者:小新 欄目:移動開發(fā)

這篇文章給大家分享的是有關(guān)Android如何實現(xiàn)簡易版彈鋼琴效果的內(nèi)容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。

具體內(nèi)容如下

目標(biāo)效果:

Android如何實現(xiàn)簡易版彈鋼琴效果

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[];// 按鈕數(shù)組
 private PanioMusic utils;// 工具類
 private View parent;// 父視圖
 private int buttonId[];// 按鈕id
 private boolean havePlayed[];// 是否已經(jīng)播放了聲音,當(dāng)手指在同一個按鈕內(nèi)滑動,且已經(jīng)發(fā)聲,就為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;// 標(biāo)記是否是在按鍵上移動
  temp = isInAnyScale(event.getX(count), event.getY(count),
  button);
  if (temp != -1) {// 事件對應(yīng)的是當(dāng)前點
  switch (event.getActionMasked()) {
  case MotionEvent.ACTION_DOWN:
  // // 單獨一根手指或最先按下的那個
  // pressedkey = temp;
  case MotionEvent.ACTION_POINTER_DOWN:
  Log.i("--", "count" + count);
  pressedkey[count] = temp;
  if (!havePlayed[temp]) {// 在某個按鍵范圍內(nèi)
   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--) {
   // 當(dāng)在兩端的按鈕時,會有一邊越界
   if (i < 0 || i >= button.length) {
   continue;
   }
   if (isInScale(event.getX(count),
   event.getY(count), button[i])) {// 在某個按鍵內(nèi)
   moveflag = true;
   if (i != temp) {// 在相鄰按鍵內(nèi)
   boolean laststill = false;
   boolean nextstill = false;
   // 假設(shè)手指已經(jīng)從上一個位置抬起,但是沒有真的抬起,所以不移位
   pressedkey[count] = -1;
   for (int j = 0; j < pointercount; j++) {
   if (pressedkey[j] == temp) {
    laststill = true;
   }
   if (pressedkey[j] == i) {
    nextstill = true;
   }
   }
 
   if (!nextstill) {// 移入的按鍵沒有按下
   // 設(shè)置當(dāng)前按鍵
   button[i]
    .setBackgroundResource(R.drawable.button_pressed);
   // 發(fā)音
   utils.soundPlay(i);
   havePlayed[i] = true;
   }
 
   pressedkey[count] = i;
 
   if (!laststill) {// 沒有手指按在上面
   // 設(shè)置上一個按鍵
   button[temp]
    .setBackgroundResource(R.drawable.button);
   havePlayed[temp] = false;
   }
 
   break;
   }
   }
  }
  break;
  case MotionEvent.ACTION_UP:
  case MotionEvent.ACTION_POINTER_UP:
  // 事件與點對應(yīng)
  tempIndex = event.getActionIndex();
  if (tempIndex == count) {
   Log.i("--", "index" + tempIndex);
   boolean still = false;
   // 當(dāng)前點已抬起
   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) {// 已經(jīng)沒有手指按在該鍵上
   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;
 }
 
 }
 
 /**
 * 判斷某個點是否在某個按鈕的范圍內(nèi)
 *
 * @param x 橫坐標(biāo)
 * @param y 縱坐標(biāo)
 * @param button 按鈕對象
 * @return 在:true;不在:false
 */
 private boolean isInScale(float x, float y, Button button) {
 // keys.getTop()是獲取按鈕所在父視圖相對其父視圖的右上角縱坐標(biāo)
 
 if (x > button.getLeft() && x < button.getRight()
 && y > button.getTop() + keys.getTop()
 && y < button.getBottom() + keys.getTop()) {
 return true;
 } else {
 return false;
 }
 }
 
 /**
 * 判斷某個點是否在一個按鈕集合中的某個按鈕內(nèi)
 *
 * @param x 橫坐標(biāo)
 * @param y 縱坐標(biāo)
 * @param button 按鈕數(shù)組
 * @return
 */
 private int isInAnyScale(float x, float y, Button[] button) {
 // keys.getTop()是獲取按鈕所在父視圖相對其父視圖的右上角縱坐標(biāo)
 
 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頁面進行設(shè)置橫屏

android:screenOrientation="landscape"

8.另外,每個按鍵的音效需要提前導(dǎo)入res下raw文件夾中。

感謝各位的閱讀!關(guān)于“Android如何實現(xiàn)簡易版彈鋼琴效果”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,讓大家可以學(xué)到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI