1
私はAndroidには初めてのので、多くの研究でズーム用のカスタム相対レイアウトを作成しましたが、今はImageviewのように振る舞うはずのドラッグ/ドラッグ。カスタムレイアウトでスクロール/パンニングまたはドラッグ
私は行列を使用していませんが、ScaleGestureDetector.SimpleOnScaleGestureListener
です。今私は同じにパンニング/ドラッグを組み込みたいと思います。
コードでドラッグ/パンニングを実行するにはどうすればよいですか?適切なコメントと理解を持つ私のカスタム相対レイアウトです。
/*
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
*
* @description : Custom Layout Zoom
*
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
*/
package com.layoutzooming;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.OnDoubleTapListener;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.view.ViewParent;
import android.widget.RelativeLayout;
public class ZoomLayout extends RelativeLayout implements OnDoubleTapListener, OnGestureListener{
//ScalingFactor i.e. Amount of Zoom
static float mScaleFactor = 1.0f;
// Maximum and Minimum Zoom
private static float MIN_ZOOM = 1.0f;
private static float MAX_ZOOM = 3.0f;
//Different Operation to be used
private final int NONE_OPERATION=0;
private final int ZOOM_OPERATION=2;
private float mWidth= 1280;
private float mHeight=800;
// Mode to select the operation
private int mode;
//Track X and Y coordinate of the finger when it first touches the screen
private float mInitialX = 0f;
private float mInitialY = 0f;
// Track the Bound of the Image after zoom to calculate the offset
static Rect mClipBound;
// mDetector to detect the scaleGesture for the pinch Zoom
private ScaleGestureDetector mDetector;
// mDoubleTapDetector to detect the double tap
private GestureDetector mDoubleTapDetector;
//Pivot point for Scaling
static float gx=0,gy=0;
/*
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
*
* @description : Constructor is called when used via XML
*
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
*/
public ZoomLayout(Context context, AttributeSet attrs) {
super(context, attrs);
setWillNotDraw(false);
mClipBound = new Rect();
// Intialize ScaleGestureDetector
mDetector = new ScaleGestureDetector(getContext(), new ZoomListener());
mDoubleTapDetector = new GestureDetector(context,this);
mDoubleTapDetector.setOnDoubleTapListener(this);
}
/*
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
*
* @description : Constructor is called when used via code
*
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
*/
public ZoomLayout(Context context) {
super(context);
setWillNotDraw(false);
mClipBound = new Rect();
// Intialize ScaleGestureDetector
mDetector = new ScaleGestureDetector(getContext(), new ZoomListener());
mDoubleTapDetector = new GestureDetector(context,this);
mDoubleTapDetector.setOnDoubleTapListener(this);
}
/*
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
*
* @description : OnTouchEvent of the layout which handles all type of motion-events possible
* @ Returns : true - we are handling the touchEvent.
*
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
// Handles all type of motion-events possible
switch(event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
// Event occurs when the first finger is pressed on the Screen
Log.d("Print", "Event: Action_Down ");
mInitialX = event.getX();
mInitialY = event.getY();
break;
case MotionEvent.ACTION_POINTER_DOWN:
//Event occurs when the second finger is pressed down
Log.d("Print", "Event: Action_Pointer_Down ");
// If second finger is pressed on the screen with the first set the Mode to Zoom operation
mode=ZOOM_OPERATION;
break;
case MotionEvent.ACTION_UP:
//Event occurs when all the finger are taken of the screen
Log.d("Print", "Event: Action_UP ");
//If all the fingers are taken up there will be no operation
mode = NONE_OPERATION;
break;
}
// Give the event to the mDetector to get the scaling Factor
mDetector.onTouchEvent(event);
// Give the event to the mDoubleTapDetector for the doubleTap
mDoubleTapDetector.onTouchEvent(event);
return true;
}
/*
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
*
* @description : By overriding the onInterceptTouchEvent y overriding the onInterceptTouchEvent,
* This allows you to watch events as they are dispatched to your children, and
* take ownership of the current gesture at any point. Allowing onTouchEvent of RelativeLayout to handle the
* all the motioin events .
*
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
onTouchEvent(ev);
return super.onInterceptTouchEvent(ev);
}
/*
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
*
* @descriptiont : invalidateChildInParent
*
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
*/
@Override
public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
return super.invalidateChildInParent(location, dirty);
}
/*
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
*
* @descriptiont : Correctly sets the x,y position of the children relative to each other for different scale factors.
*
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
*/
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b)
{
int count = getChildCount();
for(int i=0;i<count;i++){
View child = getChildAt(i);
if(child.getVisibility()!=GONE){
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams)child.getLayoutParams();
child.layout(
(int)(params.leftMargin),
(int)(params.topMargin),
(int)((params.leftMargin + child.getMeasuredWidth())),
(int)((params.topMargin + child.getMeasuredHeight()))
);
}
}
}
/*
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
*
* @description : Called by draw to draw the ChildViews. We need to gained control before the children are
* drawn so that to apply the scaling Factors
*
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
*/
@Override
protected void dispatchDraw(Canvas canvas) {
//Save the canvas to set the scaling factor returned from detector
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.scale(mScaleFactor, mScaleFactor,gx,gy);
super.dispatchDraw(canvas);
mClipBound = canvas.getClipBounds();
canvas.restore();
}
/*
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
*
* @name : ZoomListener
* @description : Class which defines the listener for ScaleGestureDetector
*
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
*/
private class ZoomListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
@Override
public boolean onScale(ScaleGestureDetector detector) {
// getting the scaleFactor from the detector
mScaleFactor *= detector.getScaleFactor(); // Gives the scaling factor from the previous scaling to the current
// Log.d("Print", "detector scaling Factor" + mScaleFactor);
gx = detector.getFocusX();
gy = detector.getFocusY();
// Limit the scale factor in the MIN and MAX bound
mScaleFactor= Math.max(Math.min(mScaleFactor, MAX_ZOOM),MIN_ZOOM);
// Log.d("Print", "Bounded scaling Factor" + mScaleFactor);
/*//Force canvas to redraw itself only if the one event is to happen (say Zooming only) else do not invalidate here for multi operations
As what we de for scrolling or panning will not reflect here. So we will add this in onDraw method
invalidate();*/
// Here we are only zooming so invalidate has to be done
invalidate();
requestLayout();
// we have handle the onScale
return true;
}
}
@Override
public boolean onDoubleTap(MotionEvent e) {
// Make the mScaleFactor to its normal value
mScaleFactor=1.0f;
// Force the canvas to redraw itself again as the changes has been occured.
invalidate();
requestLayout();
return false;
}
@Override
public boolean onDoubleTapEvent(MotionEvent e) {
// Log.d("Print", "OnDoubleTapEvent");
return false;
}
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
// Log.d("Print", "OnSingleTap");
return false;
}
@Override
public boolean onDown(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2,
float velocityX, float velocityY) {
return false;
}
@Override
public void onLongPress(MotionEvent e) {
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
return false;
}
@Override
public void onShowPress(MotionEvent e) {
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
}
通常のScrollViewの内部でHorizontalScrollViewを使用して全方向スクロール/パンを有効にしましたか? – Kostas
@Kostas:どのようにすべての方向に有効にするには? – user1169079
HorizontalScrollViewをScrollViewの中に入れて、それがどのように動作するかを見てみましょう:-) – Kostas