android小程序-电子钢琴-滑动连续响应

原创文字,转载请标明出处:

利用Button实现简单地电子钢琴,可以简单地响应按钮的click事件来发出相应的声音。但是这样不能达到手指在屏幕滑动,而连续发声的效果,就像手指在真实钢琴按键上滑过一样。本文就是为了解决这个问题。思路:通过父控件响应touchevent,在响应函数中判断位置是否在按钮所在位置,或是从一个按钮移动到另一个按钮内,从而进行相应的操作。


形状文件:res/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>

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>

布局文件:res/layout

activitymain.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/parent"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity" >

    <LinearLayout
        android:id="@+id/title"
        android:layout_width="match_parent"
        android:layout_height="0dp"
            android:layout_weight="1"
            android:orientation="vertical" >

        <TextView
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:id="@+id/text"
            android:text="电子钢琴 by ZH" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:id="@+id/Keys"
        android:layout_height="0dp"
        android:layout_weight="5"
        android:orientation="horizontal"
        android:padding="10dp" >

        <Button
            android:id="@+id/button1"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="@drawable/button"
            android:text="1" />

        <Button
            android:id="@+id/button2"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="@drawable/button"
            android:text="2" />

        <Button
            android:id="@+id/button3"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="@drawable/button"
            android:text="3" />

        <Button
            android:id="@+id/button4"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="@drawable/button"
            android:text="4" />

        <Button
            android:id="@+id/button5"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="@drawable/button"
            android:text="5" />

        <Button
            android:id="@+id/button6"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="@drawable/button"
            android:text="6" />

        <Button
            android:id="@+id/button7"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="@drawable/button"
            android:text="7" />
    </LinearLayout>

</LinearLayout>


源文件:

MyMusicUtils.java

/**
 * 音乐播放帮助类
 */
package com.example.android_simple_piano;

import java.util.HashMap;

import android.content.Context;
import android.media.AudioManager;
import android.media.SoundPool;

public class MyMusicUtils {
	// 资源文件
	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;

	/**
	 * 
	 * @param context
	 *            用于soundpool.load
	 * @param no
	 *            播放声音的编号
	 */
	public MyMusicUtils(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 {
		// TODO Auto-generated method stub
		soundPool.release();
		super.finalize();
	}
}

MainActivity.java

package com.example.android_simple_piano;

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;

public class MainActivity extends Activity {
	private Button button[];//按钮数组
	private MyMusicUtils utils;//工具类
	private View parent;//父视图
	private int buttonId[];//按钮id
	private boolean havePlayed[];//是否已经播放了声音,当手指在同一个按钮内滑动,且已经发声,就为true
	private int currentKey;//手指当前所在按钮
	private int lastKey;//上一个按钮
	private View keys;//按钮们所在的视图

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		//新建工具类
		utils = new MyMusicUtils(getApplicationContext());

		//按钮资源Id
		buttonId = new int[7];
		buttonId[0] = R.id.button1;
		buttonId[1] = R.id.button2;
		buttonId[2] = R.id.button3;
		buttonId[3] = R.id.button4;
		buttonId[4] = R.id.button5;
		buttonId[5] = R.id.button6;
		buttonId[6] = R.id.button7;

		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;
		}

		currentKey = 0;
		lastKey = 0;

		parent = (View) findViewById(R.id.parent);
		parent.setClickable(true);

		parent.setOnTouchListener(new OnTouchListener() {

			@Override
			public boolean onTouch(View v, MotionEvent event) {
				int temp;
				switch (event.getAction()) {
				case MotionEvent.ACTION_DOWN:
					temp = isInAnyScale(event.getX(), event.getY(), button);
					if (temp != -1) {// 在某个按键范围内
						currentKey = temp;
						button[currentKey]
								.setBackgroundResource(R.drawable.button_pressed);

						// 播放音阶
						utils.soundPlay(currentKey);
						Log.i("--", "sound" + currentKey);
						havePlayed[currentKey] = true;
					}
					break;
				case MotionEvent.ACTION_MOVE:
					temp = currentKey;
					for (int i = temp + 1; i >= temp - 1; i--) {
						//当在两端的按钮时,会有一边越界
						if (i < 0 || i >= button.length) {
							continue;
						}
						if (isInScale(event.getX(), event.getY(), button[i])) {// 在某个按键内
							if (i == currentKey) {
								// 在当前按键内且未发音
								if (!havePlayed[i]) {
									utils.soundPlay(currentKey);
									Log.i("--", "sounD" + i);
								}
								break;
							} else {// 在相邻按键内
								lastKey = currentKey;
								// 设置当前按键
								currentKey = i;
								button[currentKey]
										.setBackgroundResource(R.drawable.button_pressed);
								// 发音
								utils.soundPlay(currentKey);
								Log.i("--", "sound" + currentKey);
								havePlayed[currentKey] = true;

								// 设置上一个按键
								button[lastKey]
										.setBackgroundResource(R.drawable.button);
								havePlayed[lastKey] = false;
								break;
							}
						}
					}
					break;
				case MotionEvent.ACTION_UP:
					lastKey = currentKey;
					button[currentKey].setBackgroundResource(R.drawable.button);
					havePlayed[currentKey] = false;

					break;
				}
				return true;
			}
		});

		keys = (View) findViewById(R.id.Keys);

	}

	/**
	 * 判断某个点是否在某个按钮的范围内
	 * 
	 * @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;
	}
}

效果图:



声音文件:http://pan.baidu.com/s/1hq0xXC4


参考文章:

事件分发:http://blog.csdn.net/guolin_blog/article/details/9097463

坐标问题:http://www.cnblogs.com/zhengbeibei/archive/2013/05/07/3065999.html




  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值