ユーザーが画像やテキストなどを追加できるこのキャンバスがあります。ユーザーがアイテムの1つをキャンバスのいずれかの側にドラッグした場合、必要に応じて展開する必要があります。グーグルで検索しましたが、妥当な解決策が見つかりませんでした。また、キャンバスは画面の幅の約90%、高さの70%です。ソリューション全体を求めているわけではありません。これを行う方法のヒントが必要です(リンク、ドキュメントなど)。
質問する
2740 次
1 に答える
2
さて、あなたが達成しようとしていることを推測するのは難しいです。「必要に応じて拡張する必要がある」とはどういう意味ですか?親ビューを埋めるために展開しますか?本来のサイズに拡張しますか?
カスタムビュークラスで使用する(不完全な)コードを次に示します。そのほとんどは、ここにある複数のソリューションから収集されたものであり、元の作成者に感謝します。onDrawは最も興味深いものです。描画する場合(ここではカスタム描画と表示されます)、キャンバス自体が変換およびスケーリングされるため、変換やスケーリングについて心配する必要はありません。つまり、x座標とy座標は、ビューサイズを基準にしており、単にスケールを掛けるだけです。
public class LightsViewer extends ImageView {
private float scale;
// minimum and maximum zoom
private float MIN_ZOOM = 1f;
private float MAX_ZOOM = 5f;
// mid point between fingers to centre scale
private PointF mid = new PointF();
private float scaleFactor = 1.f;
private ScaleGestureDetector detector;
// drag/zoom mode
private final static int NONE = 0;
// current mode
private int mode ;
private float startX = 0f;
private float startY = 0f;
private float translateX = 0f;
private float translateY = 0f;
private float previousTranslateX = 0f;
private float previousTranslateY = 0f;
public LightsViewer(Context context) {
super(context);
detector = new ScaleGestureDetector(getContext(), new ScaleListener());
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
displayWidth = display.getWidth();
displayHeight = display.getHeight();
}
public LightsViewer(Context context, AttributeSet attrs) {
super(context,attrs);
detector = new ScaleGestureDetector(getContext(), new ScaleListener());
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
displayWidth = display.getWidth();
displayHeight = display.getHeight();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int ZOOM = 2;
int DRAG = 1;
if (!allowZooming){return true;}
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
mode = DRAG;
//We assign the current X and Y coordinate of the finger to startX and startY minus the previously translated
//amount for each coordinates This works even when we are translating the first time because the initial
//values for these two variables is zero.
startX = event.getX() - previousTranslateX;
startY = event.getY() - previousTranslateY;
break;
case MotionEvent.ACTION_MOVE:
if (mode == ZOOM){
Log.d("LIGHTS","ACTION_MOVE:Move but ZOOM, breaking");
break;}
translateX = event.getX() - startX;
translateY = event.getY() - startY;
//We cannot use startX and startY directly because we have adjusted their values using the previous translation values.
//This is why we need to add those values to startX and startY so that we can get the actual coordinates of the finger.
double distance = Math.sqrt(Math.pow(event.getX() - (startX + previousTranslateX), 2) +
Math.pow(event.getY() - (startY + previousTranslateY), 2)
);
if(distance > 0) {
dragged = true;
}
break;
case MotionEvent.ACTION_POINTER_DOWN:
midPoint(mid, event);
mode = ZOOM;
break;
case MotionEvent.ACTION_UP:
mode = NONE;
dragged = false;
//All fingers went up, so let's save the value of translateX and translateY into previousTranslateX and
//previousTranslate
previousTranslateX = translateX;
previousTranslateY = translateY;
break;
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
//This is not strictly necessary; we save the value of translateX and translateY into previousTranslateX
//and previousTranslateY when the second finger goes up
previousTranslateX = translateX;
previousTranslateY = translateY;
break;
}
detector.onTouchEvent(event);
//We redraw the canvas only in the following cases:
//
// o The mode is ZOOM
// OR
// o The mode is DRAG and the scale factor is not equal to 1 (meaning we have zoomed) and dragged is
// set to true (meaning the finger has actually moved)
if ((mode == DRAG && scaleFactor != 1f && dragged) || mode == ZOOM) {
this.invalidate();
}
return true;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (this.getImageMatrix().isIdentity()){return;}
if (allowZooming){
this.applyMatrix(this.getImageMatrix());
}
}
@Override
public void onDraw(Canvas canvas) {
canvas.save();
// scale the canvas
canvas.scale(scaleFactor, scaleFactor, mid.x, mid.y);
canvas.translate(translateX / scaleFactor, translateY / scaleFactor);
super.onDraw(canvas);
// do custom drawing here...e.g.
canvas.drawCircle(100,100, 3 / scaleFactor,light.paint);
canvas.restore();
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
@Override
public boolean onScale(ScaleGestureDetector detector) {
scaleFactor *= detector.getScaleFactor();
scaleFactor = Math.max(MIN_ZOOM, Math.min(scaleFactor, MAX_ZOOM));
return true;
}
}
// calculate the mid point of the first two fingers
private void midPoint(PointF point, MotionEvent event) {
// ...
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
Log.d("LIGHTS", x/2 + "," + y/2);
}
public void setMinZoom(float minZoom){
this.MIN_ZOOM = minZoom;
}
public void applyMatrix(Matrix matrix){
float[] matrixValues = new float[9];
matrix.getValues(matrixValues);
int x = (int)matrixValues[Matrix.MTRANS_X];
int y = (int)matrixValues[Matrix.MTRANS_Y];
float scale = matrixValues[Matrix.MSCALE_X];
if (lights!=null){
for (Light light:lights){
light.setX((int)((light.originalX * scale) + x));
light.setY((int)((light.originalY * scale) + y));
}
}
// if either the x or y translations are less than 0, then the image has been cropped
// so set the min zoom to the ratio of the displayed size and the actual size of the image
if (matrixValues[Matrix.MTRANS_X] < 0 || matrixValues[Matrix.MTRANS_Y] <0){
MIN_ZOOM = displayWidth / this.getDrawable().getIntrinsicWidth();
}else{
MIN_ZOOM = 1;
}
}
public void enableZooming(boolean enable){
allowZooming = enable;
}
public void setScale(float scale){
for (Light light:lights){
light.setX((int)(light.originalX * scale));
light.setY((int)(light.originalY * scale));
}
}
}
于 2012-04-13T09:13:40.207 に答える