Android實(shí)現(xiàn)簡易版彈鋼琴效果
本文實(shí)例為大家分享了Android實(shí)現(xiàn)彈鋼琴效果展示的具體代碼,供大家參考,具體內(nèi)容如下
目標(biāo)效果:

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)手指在同一個(gè)按鈕內(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)前點(diǎn)
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
// // 單獨(dú)一根手指或最先按下的那個(gè)
// pressedkey = temp;
case MotionEvent.ACTION_POINTER_DOWN:
Log.i("--", "count" + count);
pressedkey[count] = temp;
if (!havePlayed[temp]) {// 在某個(gè)按鍵范圍內(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)在兩端的按鈕時(shí),會有一邊越界
if (i < 0 || i >= button.length) {
continue;
}
if (isInScale(event.getX(count),
event.getY(count), button[i])) {// 在某個(gè)按鍵內(nèi)
moveflag = true;
if (i != temp) {// 在相鄰按鍵內(nèi)
boolean laststill = false;
boolean nextstill = false;
// 假設(shè)手指已經(jīng)從上一個(gè)位置抬起,但是沒有真的抬起,所以不移位
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è)置上一個(gè)按鍵
button[temp]
.setBackgroundResource(R.drawable.button);
havePlayed[temp] = false;
}
break;
}
}
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
// 事件與點(diǎn)對應(yīng)
tempIndex = event.getActionIndex();
if (tempIndex == count) {
Log.i("--", "index" + tempIndex);
boolean still = false;
// 當(dāng)前點(diǎn)已抬起
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++) {// 是否還有其他點(diǎn)
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;
}
}
/**
* 判斷某個(gè)點(diǎn)是否在某個(gè)按鈕的范圍內(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;
}
}
/**
* 判斷某個(gè)點(diǎn)是否在一個(gè)按鈕集合中的某個(gè)按鈕內(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頁面對某個(gè)Activity頁面進(jìn)行設(shè)置橫屏
android:screenOrientation="landscape"
8.另外,每個(gè)按鍵的音效需要提前導(dǎo)入res下raw文件夾中。
源碼:點(diǎn)擊打開鏈接
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android提高之使用NDK把彩圖轉(zhuǎn)換灰度圖的方法
這篇文章主要介紹了Android使用NDK把彩圖轉(zhuǎn)換灰度圖的方法,在Android項(xiàng)目開發(fā)中有一定的實(shí)用價(jià)值,需要的朋友可以參考下2014-08-08
Android中制作自定義dialog對話框的實(shí)例分享
這篇文章主要介紹了Android中制作自定義dialog對話框的實(shí)例分享,安卓自帶的Dialog顯然不夠用,因而我們要繼承Dialog類來制作自己的對話框,需要的朋友可以參考下2016-04-04
詳解Android App中ViewPager使用PagerAdapter的方法
這篇文章主要介紹了詳解Android App中ViewPager使用PagerAdapter的方法,同時(shí)附帶了一個(gè)ViewPager的PagerAdapter不能更新數(shù)據(jù)的問題解決方法,需要的朋友可以參考下2016-03-03
android中UIColletionView瀑布流布局實(shí)現(xiàn)思路以及封裝的實(shí)現(xiàn)
本篇文章主要介紹了android中UIColletionView瀑布流布局實(shí)現(xiàn)思路以及封裝的實(shí)現(xiàn),具有一定的參考價(jià)值,有興趣的可以了解一下。<BR>2017-02-02
Android實(shí)現(xiàn)底部半透明彈出框PopUpWindow效果
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)底部半透明彈出框PopUpWindow效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07
在Android上實(shí)現(xiàn)HttpServer的示例代碼
本篇文章主要介紹了在Android上實(shí)現(xiàn)HttpServer的示例代碼,實(shí)現(xiàn)Android本地的微型服務(wù)器,具有一定的參考價(jià)值,有興趣的可以了解一下2017-08-08
Android輸入框?qū)崟r(shí)模糊搜索效果的示例代碼
這篇文章主要介紹了Android輸入框?qū)崟r(shí)模糊搜索效果的示例代碼,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08

