This view is a scrollable and zoomable strip. It will be used for scrolling the keyboard.master
parent
1c6027bc3b
commit
5073a65ad1
@ -0,0 +1,192 @@ |
||||
/* |
||||
* Copyright 2013 Google Inc. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.levien.synthesizer.android.widgets.keyboard; |
||||
|
||||
import android.content.Context; |
||||
import android.graphics.Canvas; |
||||
import android.graphics.Paint; |
||||
import android.graphics.Rect; |
||||
import android.util.AttributeSet; |
||||
import android.view.MotionEvent; |
||||
import android.view.View; |
||||
|
||||
public class ScrollStripView extends View { |
||||
public ScrollStripView(Context context, AttributeSet attrs) { |
||||
super(context, attrs); |
||||
drawingRect_ = new Rect(); |
||||
paint_ = new Paint(); |
||||
touchDown_ = new boolean[2]; |
||||
touchx_ = new float[2]; |
||||
offset_ = -2000.0f; // TODO: make more systematic
|
||||
zoom_ = 3.0f; |
||||
} |
||||
|
||||
public void bindKeyboard(KeyboardView kv) { |
||||
keyboardView_ = kv; |
||||
kv.setScrollZoom(offset_, zoom_); |
||||
} |
||||
|
||||
@Override |
||||
protected void onDraw(Canvas canvas) { |
||||
super.onDraw(canvas); |
||||
getDrawingRect(drawingRect_); |
||||
float x0 = 100f + offset_; |
||||
float x1 = x0 + 100f * zoom_; |
||||
paint_.setStyle(Paint.Style.STROKE); |
||||
canvas.drawLine(x0, drawingRect_.top, x0, drawingRect_.bottom, paint_); |
||||
canvas.drawLine(x1, drawingRect_.top, x1, drawingRect_.bottom, paint_); |
||||
} |
||||
|
||||
private boolean onTouchDown(int id, float x) { |
||||
touchx_[id] = x; |
||||
if (!touchDown_[0] && !touchDown_[1]) { |
||||
deltaAtTouch_ = offset_ - x; |
||||
} else { |
||||
deltaAtTouch_ = offset_ - touchx_[0]; |
||||
zoomAtTouch_ = zoom_; |
||||
scaleAtTouch_ = zoom_ / (touchx_[1] - touchx_[0]); |
||||
} |
||||
touchDown_[id] = true; |
||||
return false; |
||||
} |
||||
|
||||
private boolean onTouchUp(int id) { |
||||
touchDown_[id] = false; |
||||
if (touchDown_[1 - id]) { |
||||
// Going from 2-finger (zoom) back to 1-finger (scroll)
|
||||
deltaAtTouch_ = offset_ - touchx_[1 - id]; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
@Override |
||||
public boolean onTouchEvent(MotionEvent event) { |
||||
int action = event.getAction(); |
||||
int actionCode = action & MotionEvent.ACTION_MASK; |
||||
boolean redraw = false; |
||||
if (actionCode == MotionEvent.ACTION_DOWN) { |
||||
int pointerId = event.getPointerId(0); |
||||
if (pointerId < 2 && pointerId >= 0) { |
||||
redraw = onTouchDown(pointerId, event.getX()); |
||||
} |
||||
} else if (actionCode == MotionEvent.ACTION_POINTER_DOWN) { |
||||
int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) |
||||
>> MotionEvent.ACTION_POINTER_INDEX_SHIFT; |
||||
int pointerId = event.getPointerId(pointerIndex); |
||||
if (pointerId < 2 && pointerId >= 0) { |
||||
redraw = onTouchDown(pointerId, event.getX(pointerIndex)); |
||||
} |
||||
} else if (actionCode == MotionEvent.ACTION_UP) { |
||||
int pointerId = event.getPointerId(0); |
||||
if (pointerId < 2 && pointerId >= 0) { |
||||
onTouchUp(pointerId); |
||||
} |
||||
} else if (actionCode == MotionEvent.ACTION_POINTER_UP) { |
||||
int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) |
||||
>> MotionEvent.ACTION_POINTER_INDEX_SHIFT; |
||||
int pointerId = event.getPointerId(pointerIndex); |
||||
if (pointerId < 2 && pointerId >= 0) { |
||||
onTouchUp(pointerId); |
||||
} |
||||
} else if (actionCode == MotionEvent.ACTION_MOVE) { |
||||
for (int pointerIndex = 0; pointerIndex < event.getPointerCount(); pointerIndex++) { |
||||
int pointerId = event.getPointerId(pointerIndex); |
||||
if (pointerId < 2 && pointerId >= 0) { |
||||
touchx_[pointerId] = event.getX(pointerIndex); |
||||
} |
||||
} |
||||
if (touchDown_[0] && !touchDown_[1]) { |
||||
offset_ = touchx_[0] + deltaAtTouch_; |
||||
redraw = true; |
||||
} else if (!touchDown_[0] && touchDown_[1]) { |
||||
offset_ = touchx_[1] + deltaAtTouch_; |
||||
redraw = true; |
||||
} else if (touchDown_[0] && touchDown_[1]) { |
||||
zoom_ = scaleAtTouch_ * (touchx_[1] - touchx_[0]); |
||||
offset_ = touchx_[0] + zoom_ / zoomAtTouch_ * deltaAtTouch_; |
||||
redraw = true; |
||||
} |
||||
offset_ = Math.min(0, offset_); |
||||
// TODO: max offset
|
||||
} |
||||
if (redraw) { |
||||
if (keyboardView_ != null) { |
||||
keyboardView_.setScrollZoom(offset_, zoom_); |
||||
} |
||||
invalidate(); |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Layout measurement for this widget. |
||||
* This method just sets a basic minimum size and makes the widget maximized otherwise. |
||||
*/ |
||||
@Override |
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { |
||||
int widthMode = MeasureSpec.getMode(widthMeasureSpec); |
||||
int widthSize = MeasureSpec.getSize(widthMeasureSpec); |
||||
int heightMode = MeasureSpec.getMode(heightMeasureSpec); |
||||
int heightSize = MeasureSpec.getSize(heightMeasureSpec); |
||||
|
||||
int width = 0; |
||||
int height = 0; |
||||
|
||||
float density = getResources().getDisplayMetrics().density; |
||||
int maxHeight = (int) (50.0f * density + 0.5f); |
||||
|
||||
switch (widthMode) { |
||||
case MeasureSpec.EXACTLY: |
||||
width = widthSize; |
||||
break; |
||||
case MeasureSpec.AT_MOST: |
||||
width = widthSize; |
||||
break; |
||||
case MeasureSpec.UNSPECIFIED: |
||||
width = 10; |
||||
break; |
||||
} |
||||
|
||||
switch (heightMode) { |
||||
case MeasureSpec.EXACTLY: |
||||
height = heightSize; |
||||
break; |
||||
case MeasureSpec.AT_MOST: |
||||
height = Math.min(maxHeight, heightSize); |
||||
break; |
||||
case MeasureSpec.UNSPECIFIED: |
||||
height = 10; |
||||
break; |
||||
} |
||||
|
||||
setMeasuredDimension(width, height); |
||||
} |
||||
|
||||
Rect drawingRect_; |
||||
Paint paint_; |
||||
float offset_; |
||||
float zoom_; |
||||
|
||||
// touch state
|
||||
boolean[] touchDown_; |
||||
float[] touchx_; |
||||
float deltaAtTouch_; |
||||
float zoomAtTouch_; |
||||
float scaleAtTouch_; |
||||
|
||||
KeyboardView keyboardView_; |
||||
} |
Loading…
Reference in new issue