• 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




  • 相关阅读:
    python生成器和使用gevent操作协程
    python飞机大战
    python控制鼠标键盘+监听键盘
    python生成彩色二维码
    springboot+springcloud+maven相关父子项目创建
    c++求最大公约数
    java8 LocalDateTime
    nginx 代理wss
    vue 全局使用axios
    Vue3.0核心源码解读| 组件渲染:vnode 到真实 DOM 是如何转变的?
  • 原文地址:https://www.cnblogs.com/zhanghang-BadCoder/p/6476474.html
Copyright © 2020-2023  润新知