在较大背景的顶部使用不可见的按钮在概念上很容易,但会出现您提到的可伸缩性问题。它也不能很好地识别多个同时触摸。第二种方法的核心,使用触摸,可能是你想走的路。onTouch() 方法中的 MotionEvent 将为您提供触摸的位置和动作。然后它就变成了一个练习,用适当的音柱或琴弦来翻译触摸/移动/抬起的点的坐标。
有很多关于触摸识别的不错的教程。这是一个。
编辑:
有几种方法可以在触摸位置和所需的琴弦和音品之间进行转换。一种方法是只对每个触摸事件strng = x / (width / NUM_STRINGS)
进行计算fret = y / (height / NUM_FRETS)
。(假设字符串在显示屏上纵向绘制。)
另一种直接的方法是构建和使用查找表来进行翻译。这确实需要几千字节来存储整数,但允许进行几个快速数组查找来确定字符串和音品。
这是实现后一种方法的示例活动。它包含一些假设和捷径,但基本功能应该是相当健全的。只有down事件显示翻译;您还需要为 up 和 move 事件做一些适当的事情。
MainActivity.java
package com.example.guitar;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
import android.widget.LinearLayout;
public class MainActivity extends Activity
implements OnTouchListener, ViewTreeObserver.OnGlobalLayoutListener {
final static String TAG = "MainActivity";
final static int NUM_STRINGS = 6;
final static int NUM_FRETS = 12;
ImageView img = null;
LinearLayout layout = null;
int width = 0;
int height = 0;
int touchToString[] = null;
int touchToFret[] = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
layout = (LinearLayout) findViewById(R.id.layout);
layout.setOnTouchListener(this);
layout.getViewTreeObserver().addOnGlobalLayoutListener(this);
}
public boolean onTouch(View v, MotionEvent event) {
// Handle the touch event:
int idx = event.getActionIndex();
int id = event.getPointerId(idx);
int x = (int) event.getX(idx);
int y = (int) event.getY(idx);
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
Log.d(TAG, String.format("DOWN event for pointer %d at %d, %d", id, x, y));
// If touch is within the bounds of the layout:
if (x > 0 && x < width && y > 0 && y < height)
Log.i(TAG, String.format("Pressed string %d at fret position %d",
touchToString[x], touchToFret[y]));
break;
case MotionEvent.ACTION_MOVE:
for (int ptr = 0; ptr < event.getPointerCount(); ptr++)
Log.d(TAG, String.format("MOVE event for pointer %d at %d, %d",
event.getPointerId(ptr), (int) event.getX(ptr), (int) event.getY(ptr)));
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_CANCEL:
Log.d(TAG, String.format("UP event for pointer %d at %d, %d", id, x, y));
break;
}
return true;
}
public void onGlobalLayout() {
// Get the current width and height of the layout:
width = layout.getMeasuredWidth();
height = layout.getMeasuredHeight();
Log.i(TAG, String.format("The layout is now (%d x %d)", width , height));
// (Re)build the string position translation array:
touchToString = new int[width];
for (int x = 0; x < width; x++)
touchToString[x] = x / (width / NUM_STRINGS);
// (Re)build the fret position translation array:
touchToFret = new int[height];
for (int y = 0; y < height; y++)
touchToFret[y] = y / (height / NUM_FRETS);
}
}