Android – acercar / alejar RelativeLayout con spread / pinch

Tengo una actividad con un RelativeLayout y una clase privada en él, que extiende el SimpleOnScaleGestureListener . En el método onScale del oyente me gustaría acercar / alejar el diseño completo (todo lo que ve el usuario) con el usuario extendiendo / pellizcando sus dedos.

Me gustaría que los cambios en el diseño no ser permanente, es decir, cuando el gesto de propagación / pellizco es más que me gustaría que el diseño para volver a lo que era en primer lugar (cualquier restablecimiento podría hacerse en el método onScaleEnd de El SimpleOnScaleGestureListener por ejemplo).

He intentado implementarlo a través de llamar a setScaleX y setScaleY en RelativeLayout y también usando una ScaleAnimation . Tampoco resultó en un zoom suave (o cualquier cosa que se podría llamar zoom). ¿Es incluso posible acercar / alejar un RelativeLayout ?

La única idea que me queda es leer una captura de pantalla de la caché y ponerla como ImageView en la parte superior de todo el diseño y el zoom in / out de esta imagen a través de setImageMatrix . Sin embargo, no tengo ni idea de cómo implementar esto.

El diseño de mayo también contiene un contenedor para un fragmento, que está vacío en el momento en el que se supone que el zoom es posible. En el gesto onScaleEnd , el fragmento se pone en su contenedor (ya implementado y funcionando bien). Aquí está mi diseño:

 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/layout_pinch" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#ffffff" > <!-- Layout containing the thumbnail ImageViews --> <LinearLayout android:id="@+id/thumbnail_group_pui" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerVertical="true" android:orientation="horizontal" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/tn_c1"/> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/tn_c2"/> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/tn_c3"/> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/tn_c4"/> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/tn_c5"/> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/tn_c6"/> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/tn_c7"/> </LinearLayout> <!-- Layout containing the dashed boxes --> <LinearLayout android:layout_width="match_parent" android:layout_height="152dp" android:layout_centerVertical="true" android:orientation="horizontal" > <ImageView android:layout_width="177dp" android:layout_height="match_parent" android:layout_marginLeft="3dp" android:layout_marginRight="3dp" android:background="@drawable/dashed_box"/> <ImageView android:layout_width="177dp" android:layout_height="match_parent" android:layout_marginLeft="3dp" android:layout_marginRight="3dp" android:background="@drawable/dashed_box"/> <ImageView android:layout_width="177dp" android:layout_height="match_parent" android:layout_marginLeft="3dp" android:layout_marginRight="3dp" android:background="@drawable/dashed_box"/> <ImageView android:layout_width="177dp" android:layout_height="match_parent" android:layout_marginLeft="3dp" android:layout_marginRight="3dp" android:background="@drawable/dashed_box"/> <ImageView android:layout_width="177dp" android:layout_height="match_parent" android:layout_marginLeft="3dp" android:layout_marginRight="3dp" android:background="@drawable/dashed_box"/> <ImageView android:layout_width="177dp" android:layout_height="match_parent" android:layout_marginLeft="3dp" android:layout_marginRight="3dp" android:background="@drawable/dashed_box"/> <ImageView android:layout_width="177dp" android:layout_height="match_parent" android:layout_marginLeft="3dp" android:layout_marginRight="3dp" android:background="@drawable/dashed_box"/> </LinearLayout> <!-- Container for the fragments --> <FrameLayout android:id="@+id/fragment_container_pui" android:layout_width="match_parent" android:layout_height="match_parent" /> </RelativeLayout> 

EDIT He encontrado estos dos temas relacionados:
Extendiendo RelativeLayout y reemplazando dispatchDraw () para crear un ViewGroup con zoom
Zoom de contenido en un RelativeLayout

No obtuve la implementación, sin embargo. ¿Qué otros métodos tengo que incluir en la clase extendida para realmente escalar el diseño o restablecerlo?

Así que creé una subclase de RelativeLayout como se describe en los temas mencionados anteriormente. Se parece a esto:

 public class ZoomableRelativeLayout extends RelativeLayout { float mScaleFactor = 1; float mPivotX; float mPivotY; public ZoomableRelativeLayout(Context context) { super(context); // TODO Auto-generated constructor stub } public ZoomableRelativeLayout(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub } public ZoomableRelativeLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // TODO Auto-generated constructor stub } protected void dispatchDraw(Canvas canvas) { canvas.save(Canvas.MATRIX_SAVE_FLAG); canvas.scale(mScaleFactor, mScaleFactor, mPivotX, mPivotY); super.dispatchDraw(canvas); canvas.restore(); } public void scale(float scaleFactor, float pivotX, float pivotY) { mScaleFactor = scaleFactor; mPivotX = pivotX; mPivotY = pivotY; this.invalidate(); } public void restore() { mScaleFactor = 1; this.invalidate(); } } 

Mi implementación de SimpleOnScaleGestureListener tiene este aspecto:

 private class OnPinchListener extends SimpleOnScaleGestureListener { float startingSpan; float endSpan; float startFocusX; float startFocusY; public boolean onScaleBegin(ScaleGestureDetector detector) { startingSpan = detector.getCurrentSpan(); startFocusX = detector.getFocusX(); startFocusY = detector.getFocusY(); return true; } public boolean onScale(ScaleGestureDetector detector) { mZoomableRelativeLayout.scale(detector.getCurrentSpan()/startingSpan, startFocusX, startFocusY); return true; } public void onScaleEnd(ScaleGestureDetector detector) { mZoomableRelativeLayout.restore(); } } 

¡Espero que esto ayude!

Actualizar:

Puede integrar OnPinchListener para su ZoomableRelativelayout utilizando ScaleGestureDetector :

 ScaleGestureDetector scaleGestureDetector = new ScaleGestureDetector(this, new OnPinchListener()); 

Y usted está obligado a ligar el oyente táctil de Zoomable layout con el oyente táctil de ScaleGestureDetector:

 mZoomableLayout.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { // TODO Auto-generated method stub scaleGestureDetector.onTouchEvent(event); return true; } }); 

Creo que logré mejorar la respuesta de Schnodahipfe un poco. He añadido dos métodos a la clase ZoomableRelativeLayout.

 public void relativeScale(float scaleFactor, float pivotX, float pivotY) { mScaleFactor *= scaleFactor; if(scaleFactor >= 1) { mPivotX = mPivotX + (pivotX - mPivotX) * (1 - 1 / scaleFactor); mPivotY = mPivotY + (pivotY - mPivotY) * (1 - 1 / scaleFactor); } else { pivotX = getWidth()/2; pivotY = getHeight()/2; mPivotX = mPivotX + (pivotX - mPivotX) * (1 - scaleFactor); mPivotY = mPivotY + (pivotY - mPivotY) * (1 - scaleFactor); } this.invalidate(); } public void release() { if(mScaleFactor < MIN_SCALE) { final float startScaleFactor = mScaleFactor; Animation a = new Animation() { @Override protected void applyTransformation(float interpolatedTime, Transformation t) { scale(startScaleFactor + (MIN_SCALE - startScaleFactor)*interpolatedTime,mPivotX,mPivotY); } }; a.setDuration(300); startAnimation(a); } else if(mScaleFactor > MAX_SCALE) { final float startScaleFactor = mScaleFactor; Animation a = new Animation() { @Override protected void applyTransformation(float interpolatedTime, Transformation t) { scale(startScaleFactor + (MAX_SCALE - startScaleFactor)*interpolatedTime,mPivotX,mPivotY); } }; a.setDuration(300); startAnimation(a); } } 

Y reescribió la clase OnPinchListener como esta

 private class OnPinchListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { float currentSpan; float startFocusX; float startFocusY; public boolean onScaleBegin(ScaleGestureDetector detector) { currentSpan = detector.getCurrentSpan(); startFocusX = detector.getFocusX(); startFocusY = detector.getFocusY(); return true; } public boolean onScale(ScaleGestureDetector detector) { ZoomableRelativeLayout zoomableRelativeLayout= (ZoomableRelativeLayout) ImageFullScreenActivity.this.findViewById(R.id.imageWrapper); zoomableRelativeLayout.relativeScale(detector.getCurrentSpan() / currentSpan, startFocusX, startFocusY); currentSpan = detector.getCurrentSpan(); return true; } public void onScaleEnd(ScaleGestureDetector detector) { ZoomableRelativeLayout zoomableRelativeLayout= (ZoomableRelativeLayout) ImageFullScreenActivity.this.findViewById(R.id.imageWrapper); zoomableRelativeLayout.release(); } } 

La respuesta original restablecería la escala cada vez que terminara el evento táctil, pero de esta manera puede acercar y alejar varias veces.

Crear una clase llamada Zoomlayout que se extiende cualquier diseño que desea ampliar en mi caso es Disposición relativa.

 public class ZoomLayout extends RelativeLayout implements ScaleGestureDetector.OnScaleGestureListener { private enum Mode { NONE, DRAG, ZOOM } private static final String TAG = "ZoomLayout"; private static final float MIN_ZOOM = 1.0f; private static final float MAX_ZOOM = 4.0f; private Mode mode = Mode.NONE; private float scale = 1.0f; private float lastScaleFactor = 0f; // Where the finger first touches the screen private float startX = 0f; private float startY = 0f; // How much to translate the canvas private float dx = 0f; private float dy = 0f; private float prevDx = 0f; private float prevDy = 0f; public ZoomLayout(Context context) { super(context); init(context); } public ZoomLayout(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public ZoomLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context); } public void init(Context context) { final ScaleGestureDetector scaleDetector = new ScaleGestureDetector(context, this); this.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View view, MotionEvent motionEvent) { switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: Log.i(TAG, "DOWN"); if (scale > MIN_ZOOM) { mode = Mode.DRAG; startX = motionEvent.getX() - prevDx; startY = motionEvent.getY() - prevDy; } break; case MotionEvent.ACTION_MOVE: if (mode == Mode.DRAG) { dx = motionEvent.getX() - startX; dy = motionEvent.getY() - startY; } break; case MotionEvent.ACTION_POINTER_DOWN: mode = Mode.ZOOM; break; case MotionEvent.ACTION_POINTER_UP: mode = Mode.DRAG; break; case MotionEvent.ACTION_UP: Log.i(TAG, "UP"); mode = Mode.NONE; prevDx = dx; prevDy = dy; break; } scaleDetector.onTouchEvent(motionEvent); if ((mode == Mode.DRAG && scale >= MIN_ZOOM) || mode == Mode.ZOOM) { getParent().requestDisallowInterceptTouchEvent(true); float maxDx = (child().getWidth() - (child().getWidth() / scale)) / 2 * scale; float maxDy = (child().getHeight() - (child().getHeight() / scale))/ 2 * scale; dx = Math.min(Math.max(dx, -maxDx), maxDx); dy = Math.min(Math.max(dy, -maxDy), maxDy); Log.i(TAG, "Width: " + child().getWidth() + ", scale " + scale + ", dx " + dx + ", max " + maxDx); applyScaleAndTranslation(); } return true; } }); } // ScaleGestureDetector @Override public boolean onScaleBegin(ScaleGestureDetector scaleDetector) { Log.i(TAG, "onScaleBegin"); return true; } @Override public boolean onScale(ScaleGestureDetector scaleDetector) { float scaleFactor = scaleDetector.getScaleFactor(); Log.i(TAG, "onScale" + scaleFactor); if (lastScaleFactor == 0 || (Math.signum(scaleFactor) == Math.signum(lastScaleFactor))) { scale *= scaleFactor; scale = Math.max(MIN_ZOOM, Math.min(scale, MAX_ZOOM)); lastScaleFactor = scaleFactor; } else { lastScaleFactor = 0; } return true; } @Override public void onScaleEnd(ScaleGestureDetector scaleDetector) { Log.i(TAG, "onScaleEnd"); } private void applyScaleAndTranslation() { child().setScaleX(scale); child().setScaleY(scale); child().setTranslationX(dx); child().setTranslationY(dy); } private View child() { return getChildAt(0); } } 

Después de esto agregue ZoomLayout en xml que tiene solamente un niño. Por ejemplo

 <?xml version="1.0" encoding="utf-8"?> <com.focusmedica.digitalatlas.headandneck.ZoomLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:id="@+id/zoomLayout" android:background="#000000" android:layout_height="match_parent"> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:paddingTop="5dp" android:textColor="#ffffff" android:text="Heading" android:gravity="center" android:textAlignment="textStart" android:paddingLeft="5dp" android:textSize="20sp" android:textStyle="bold" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/tvSubtitle2" android:layout_toLeftOf="@+id/ivOn" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" /> <ImageView android:id="@+id/ivOff" android:layout_width="40dp" android:layout_height="40dp" android:src="@drawable/off_txt" android:layout_alignParentTop="true" android:layout_alignParentRight="true" android:layout_alignParentEnd="true" /> <ImageView android:id="@+id/ivOn" android:layout_width="40dp" android:layout_height="40dp" android:src="@drawable/on_txt" android:layout_alignParentTop="true" android:layout_alignLeft="@+id/pinOn" android:layout_alignStart="@+id/pinOn" /> <ImageView android:id="@+id/pinOff" android:visibility="invisible" android:layout_width="40dp" android:layout_height="40dp" android:src="@drawable/pin_off" android:layout_alignParentTop="true" android:layout_alignParentRight="true" android:layout_alignParentEnd="true" /> <ImageView android:id="@+id/pinOn" android:layout_width="40dp" android:layout_height="40dp" android:src="@drawable/pin_on" android:layout_alignParentTop="true" android:layout_toLeftOf="@+id/ivOff" android:layout_toStartOf="@+id/ivOff" /> <RelativeLayout android:id="@+id/linear" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true"> <ImageView android:src="@drawable/wait" android:layout_width="match_parent" android:layout_height="300dp" android:id="@+id/fullIVideo"/> <ImageView android:src="@drawable/wait" android:layout_width="match_parent" android:layout_height="300dp" android:id="@+id/colorCode"/> <ImageView android:src="@drawable/wait" android:layout_width="match_parent" android:layout_height="300dp" android:id="@+id/labelText"/> <ImageView android:src="@drawable/download" android:layout_marginTop="91dp" android:layout_width="100dp" android:layout_height="100dp" android:id="@+id/label_play" android:layout_alignTop="@+id/fullIVideo" android:layout_centerVertical="true" android:layout_centerHorizontal="true" /> </RelativeLayout> <LinearLayout android:orientation="vertical" android:id="@+id/custom_toast_layout" android:layout_width="300dp" android:layout_above="@+id/up" android:background="@drawable/rectangle_frame" android:paddingLeft="10dp" android:paddingBottom="10dp" android:paddingTop="10dp" android:paddingRight="10dp" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:layout_height="wrap_content"> <TextView android:textSize="15sp" android:textColor="#ffffff" android:layout_gravity="center" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Medium Text" android:id="@+id/tvLabel" /> <TextView android:textColor="#ffffff" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:text="New Text" android:layout_gravity="center" android:id="@+id/tvLabelDescription" /> </LinearLayout> <ImageView android:layout_width="50dp" android:layout_height="50dp" android:src="@drawable/up" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:id="@+id/up" /> </RelativeLayout> </com.focusmedica.digitalatlas.headandneck.ZoomLayout> 

Ahora en MainActivity cree el objeto de ZoomLayout y defina id.Like

 ZoomLayout zoomlayout=(ZoomLayout)findviewbyid(R.id.zoomLayout); zoomlayout.setOnTouchListener(FullScreenVideoActivity.this); public boolean onTouch(View v, MotionEvent event) { linear.init(FullScreenVideoActivity.this); return false; } 

I hpoe él trabajará. Si este código trabajará entonces satisface hace como aceptado.

La solución de Ashish funcionó para mí. Tuve que hacer algunos ajustes de codificación, ya que había algunos errores de formato en la implementación MainActivity.

Vea a continuación los cambios:

 final ZoomLayout zoomlayout = (ZoomLayout) findViewById(R.id.zoomLayout); zoomlayout.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { zoomlayout.init(FullScreenVideoActivity.this); return false; } }); 
  • Error al inflacionar la clase android.support.design.widget.CoordinatorLayout y ClassNotFoundException: android.support.design.R $ styleable
  • Barra de herramientas extendida con vista personalizada que no se muestra con ancho completo
  • Cambiar el color del divisor en Android PreferenciaActividad
  • Diseño Nombre de la carpeta para Tablet 7 "
  • OnItemClickListener de spinner
  • Cómo construir un diseño complejo en android con múltiples vistas de lista
  • Expand y Collapase en Android
  • La animación del hilador personalizado no es lo suficientemente suave: framesCount y error frameDuration
  • Eliminar TextView predeterminado del nuevo diseño de la actividad
  • Cambiar presentación de notificaciones
  • ¿Cómo puedo descompilar archivos dex de forma programática dentro de Android?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.