Skip to content

Instantly share code, notes, and snippets.

@Folyd
Created Sep 9, 2015
Embed
What would you like to do?
A Piano Keyboarad View in Android
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
import com.theonepiano.smartpiano.R;
import com.theonepiano.smartpiano.util.Utils;
import java.util.ArrayList;
import java.util.List;
public final class Keyboard extends View {
private int ROUND_X = 2, ROUND_Y = 2;
private float mWhiteKeyWidth, mWhiteKeyHeight, mBlackKeyWidth, mBlackKeyHeight;
/**
* The anchors pixels of all key.
*/
private List<Float> mKeyAnchors = new ArrayList<>();
private Paint mPaint = new Paint();
/**
* The regular piano with 52 white keys,total 88 keys.
*/
public static final int TYPE_PIANO = 52;
/**
* The light piano with 36 white keys,total 61 keys.
*/
public static final int TYPE_LIGHT = 36;
/**
* Current keyboard type.{@link #TYPE_PIANO} or {@link #TYPE_LIGHT}
*/
private int mKeyboardType = TYPE_PIANO;
public Keyboard(Context context) {
super(context);
}
public Keyboard(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.Keyboard);
mKeyboardType = ta.getInt(R.styleable.Keyboard_pianoType, TYPE_PIANO);
ta.recycle();
}
public Keyboard(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
int whiteKeyCount = mKeyboardType;
//Notice:We should multiply by 1.0f to convert width to float type to reduce mistakes.
mWhiteKeyWidth = getWidth() * 1.0f / whiteKeyCount;
float blackWhiteWidthRatio = 13f / 20f;
mBlackKeyWidth = mWhiteKeyWidth * blackWhiteWidthRatio;
mWhiteKeyHeight = getHeight();
float blackWhiteHeightRatio = 95f / 144f;
mBlackKeyHeight = mWhiteKeyHeight * blackWhiteHeightRatio;
}
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
mPaint.setAntiAlias(true);
canvas.drawColor(Color.TRANSPARENT);
if (mKeyboardType == TYPE_PIANO) {
drawForPianoKeyboard(canvas);
} else if (mKeyboardType == TYPE_LIGHT) {
drawForLightKeyboard(canvas);
}
}
/**
* Drawer 88 key for piano.
*
* @param canvas
*/
private void drawForPianoKeyboard(Canvas canvas) {
int whiteCount = drawKeys(canvas, 0, 3);
float base = computeSpecificDividerX(whiteCount);
for (int i = 0; i < 7; i++) {
float start = i * 7 * mWhiteKeyWidth;
whiteCount = whiteCount + drawOctave(canvas, base + start);
}
base = computeSpecificDividerX(whiteCount);
drawKeys(canvas, base, 1);
}
/**
* Draw 61 key for light piano.
*
* @param canvas
*/
private void drawForLightKeyboard(Canvas canvas) {
int whiteCount = 0;
float base = computeSpecificDividerX(whiteCount);
for (int i = 0; i < 5; i++) {
float start = i * 7 * mWhiteKeyWidth;
whiteCount = whiteCount + drawOctave(canvas, base + start);
}
base = computeSpecificDividerX(whiteCount);
drawKeys(canvas, base, 1);
}
/**
* @param canvas
* @param base
* @param count
* @return white key count which been drew.
*/
private int drawKeys(Canvas canvas, float base, int count) {
if (count <= 0) {
return 0;
}
if (count > 12) {
count = 12;
}
int whiteCount = 0;
float left, top, right, bottom;
for (int i = 0; i < count; i++) {
if (i == 1 || i == 3 || i == 6 || i == 8 || i == 10) {
//Black key
float axis = computeSpecificDividerX(whiteCount);
left = axis - mBlackKeyWidth / 2;
right = axis + mBlackKeyWidth / 2;
top = 0;
bottom = mBlackKeyHeight;
mKeyAnchors.add(base + left);
drawBlackKey(canvas, base + left, top, base + right, bottom);
} else {
//White key
left = computeSpecificDividerX(whiteCount);
right = computeSpecificDividerX(whiteCount + 1);
top = 0;
bottom = mWhiteKeyHeight;
mKeyAnchors.add(base + right);
drawWhiteKey(canvas, base + left, top, base + right, bottom);
whiteCount++;
}
}
return whiteCount;
}
private int drawOctave(Canvas canvas, float base) {
return drawKeys(canvas, base, 12);
}
private void drawWhiteKey(Canvas canvas, float left, float top, float right, float bottom) {
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(Color.parseColor("#000000"));
RectF rect = new RectF(left, top, right, bottom);
canvas.drawRoundRect(rect, ROUND_X, ROUND_Y, mPaint);
mPaint.reset();
}
private void drawBlackKey(Canvas canvas, float left, float top, float right, float bottom) {
RectF rect = new RectF(left, top, right, bottom);
// mPaint.setStyle(Paint.Style.STROKE);
// mPaint.setColor(Color.parseColor("#FFFFFF"));
// canvas.drawRoundRect(rect, ROUND_X, ROUND_Y, mPaint);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(Color.parseColor("#000000"));
canvas.drawRoundRect(rect, ROUND_X, ROUND_Y, mPaint);
mPaint.reset();
}
/**
* Set the keyboard type. {@link #TYPE_PIANO} or {@link #TYPE_LIGHT}.
*
* @param keyboardType
*/
public void setKeyboardType(int keyboardType) {
if (mKeyboardType == keyboardType) return;
mKeyboardType = keyboardType;
}
private float computeSpecificDividerX(int i) {
return i * mWhiteKeyWidth;
}
/**
* @param axis
* @return
*/
public int determineKeyNumber(float axis) {
int number = 0;
for (int i = 0; i < mKeyAnchors.size(); i++) {
float r = Math.abs(mKeyAnchors.get(i) - axis);
if (r <= mBlackKeyWidth / 2 || r <= mWhiteKeyWidth) {
number = i;
break;
}
}
return number;
}
/**
* Obtain the key pixels by key number.
*
* @param number
* @return
*/
public float obtainKeyPixels(int number) {
if (Utils.isCollectionEmpty(mKeyAnchors)) {
return 0;
}
if (number < 0) {
return 0;
}
if (number >= mKeyAnchors.size()) {
return mKeyAnchors.size() - 1;
}
return mKeyAnchors.get(number);
}
/**
* Get current white key count.
*
* @return
*/
public int getWhiteKeyCount() {
return mKeyboardType;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment