Android – 扩大/缩小放大/缩小RelativeLayout

我有一个RelativeLayout和一个私有类的活动,它扩展了SimpleOnScaleGestureListener 。 在监听器的onScale方法中,我想放大/缩小整个布局(用户看到的所有内容),同时用户伸展/捏住他的手指。

我想布局的变化不是永久性的,即当传播/挤压手势结束时,我想布局回到原来的位置(任何重置可以在onScaleEnd方法例如SimpleOnScaleGestureListener )。

我试图通过在RelativeLayout上调用setScaleXsetScaleY来实现它,也使用了ScaleAnimation 。 没有导致平滑的缩放(或任何可以称之为缩放的东西)。 甚至可以放大/缩小RelativeLayout

我留下的唯一想法是从caching中读取屏幕截图,并将其作为ImageView放在整个布局的顶部,并通过setImageMatrix放大/缩小该图像。 我不知道如何实现这一点。

May layout还包含一个片段的容器,在缩放应该是可能的时候这个容器是空的。 在onScaleEnd手势,片段被放入它的容器(已经实施,工作正常)。 这是我的布局:

 <?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> 

编辑我发现这两个相关的主题:
扩展RelativeLayout,并重写dispatchDraw()来创build一个可缩放的ViewGroup
在一个RelativeLayout中放大内容

然而,我没有得到执行。 我还必须在扩展类中包含哪些其他方法来实际缩放布局或重置它?

所以我创build了上面提到的主题中所描述的RelativeLayout的子类。 它看起来像这样:

 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(); } } 

我的SimpleOnScaleGestureListener实现如下所示:

 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(); } } 

希望这可以帮助!

更新:

您可以使用ScaleGestureDetector为您的ZoomableRelativelayout集成ScaleGestureDetector

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

并且您需要将Zoomable布局的触摸监听器与ScaleGestureDetector的监听器进行绑定:

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

我想我设法改善了Schnodahipfe的答案。 我向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); } } 

并像这样重写了OnPinchListener类

 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(); } } 

原来的答案会在每次触摸事件结束时重置比例,但是像这样,您可以放大和缩小多次。

创build一个名为Zoomlayout的类,它扩展了任何你想放大的布局,这是相对布局。

 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); } } 

之后,在只有一个孩子的xml中添加ZoomLayout。例如

 <?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> 

现在在MainActivity中创buildZoomLayout的对象并定义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; } 

我说它会工作。如果这个代码将工作,然后请作出接受。

你只需要传递getActivity()而不是Activity Name

 final ZoomLayout zoomlayout = (ZoomLayout) findViewById(R.id.zoomLayout); zoomlayout.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { zoomlayout.init(getActivity()); return false; } });