View Pager + ImageView +Pinch Zoom + Rotation



我想在Imageview上实现Pinch Zoom,使用类似于默认Android Gallery的视图内Pager。我在GitHub上找到了多个来源,但缩放和滑动只适用于第一张图片。

我尝试过的:

1.)TouchImageView

2.)PhotoView

3.)Android Touch Gallery

以上所有链接都适用于单个图像视图。但当谈到"视图中的图像"寻呼机时,它们会出现一些小故障,并且只适用于"视图寻呼机"中的第一个图像。当我们滚动到视图寻呼机中的第三个第四个图像时,如果图像被缩放,拖动功能将无法正常工作。

如果有人知道有什么好的图书馆可以做这件事,请给我他们的链接。

编辑2:示例代码已被推送到TouchImageView的master分支。这里有一个到示例活动的链接和一个到ExtendedViewPager的链接。

EDIT:添加了将示例链接调整为TouchImageView的代码。注意:您将需要最新的代码,该代码目前在dev分支中。将来,这将包含在v1.0中。如果TouchImageView覆盖canScrollHorizontally,您就知道您拥有最新的代码。

步骤1:扩展ViewPager并覆盖canScroll以调用canScrollHorizontalyFroyo。

public class ExtendedViewPager extends ViewPager {
public ExtendedViewPager(Context context) {
super(context);
}
public ExtendedViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
if (v instanceof TouchImageView) {
return ((TouchImageView) v).canScrollHorizontallyFroyo(-dx);
} else {
return super.canScroll(v, checkV, dx, x, y);
}
}
}

步骤2:通过添加canScrollHorizontalyFroyo:修改TouchImageView

public boolean canScrollHorizontallyFroyo(int direction) {
return canScrollHorizontally(direction);
}

步骤3:您的活动

public class TouchImageViewActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ExtendedViewPager mViewPager = (ExtendedViewPager) findViewById(R.id.view_pager);
setContentView(mViewPager);
mViewPager.setAdapter(new TouchImageAdapter());
}
static class TouchImageAdapter extends PagerAdapter {
private static int[] images = { R.drawable.img1, R.drawable.img2, R.drawable.img3 };
@Override
public int getCount() {
return images.length;
}
@Override
public View instantiateItem(ViewGroup container, int position) {
TouchImageView img = new TouchImageView(container.getContext());
img.setImageResource(images[position]);
container.addView(img, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
return img;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
}
}

步骤4:main.xml

<com.example.touch.ExtendedViewPager 
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />

TouchImageView实际上是我的项目。我目前在开发分支中有一个与ViewPagers集成的修复程序,它将在即将发布的版本中推送到master。遗憾的是,此修复程序仅适用于API 14及更高版本,因为蜂窝和更早版本不调用canScrollHorizontally。如果您需要支持较旧的API,则需要在ViewPager中实现一个变通方法。下面是一个例子。

我用ImageViewZoom库找到了不错的解决方案。为了在ViewPager中滚动缩放的图像,我创建了自己的ViewPager:

public class ExtendedViewPager extends ViewPager {
public ExtendedViewPager(Context context) {
super(context);
}
public ExtendedViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
if (v instanceof ImageViewTouch) {
return ((ImageViewTouch) v).canScroll(dx);
} else {
return super.canScroll(v, checkV, dx, x, y);
}
}
}

查看更多https://gist.github.com/atermenji/3781644

经过几个小时的测试,我终于找到了令人敬畏的子采样比例图像视图库,它甚至可以与Android支持包中的标准ViewPager一起使用。

我使用ImageViewZoom库的解决方案基于此自定义ViewPager:

public class ImageViewTouchViewPager extends ViewPager {
public ImageViewTouchViewPager(Context context) {
super(context);
}
public ImageViewTouchViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
if (v instanceof ImageViewTouch) {
ImageViewTouch imageViewTouch = (ImageViewTouch)v;
if (imageViewTouch.getScale() == imageViewTouch.getMinScale()) {
return super.canScroll(v, checkV, dx, x, y);
}
return imageViewTouchCanScroll(imageViewTouch, dx);
} else {
return super.canScroll(v, checkV, dx, x, y);
}
}

/**
* Determines whether the ImageViewTouch can be scrolled.
*
* @param direction - positive direction value means scroll from right to left,
*                  negative value means scroll from left to right
* @return true if there is some more place to scroll, false - otherwise.
*/
private boolean imageViewTouchCanScroll(ImageViewTouch v, int direction){
RectF bitmapRect = v.getBitmapRect();
Rect imageViewRect = new Rect();
getGlobalVisibleRect(imageViewRect);
if (null == bitmapRect) {
return false;
}
if (direction < 0) {
return Math.abs(bitmapRect.right - imageViewRect.right) > 1.0f;
}else {
return Math.abs(bitmapRect.left - imageViewRect.left) > 1.0f;
}
}
}

我更正了以前的解决方案。当ImageViewTouch是模式缩放时,您可以滚动页面。

public class ImageViewTouchViewPager extends ViewPager {
public ImageViewTouchViewPager(Context context) {
super(context);
}
public ImageViewTouchViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
if (v instanceof ImageViewTouch) {
ImageViewTouch imageViewTouch = (ImageViewTouch)v;
return imageViewTouchCanScroll(imageViewTouch, dx);
} else {
return super.canScroll(v, checkV, dx, x, y);
}
}

/**
* Determines whether the ImageViewTouch can be scrolled.
*
* @param direction - positive direction value means scroll from right to left,
*                  negative value means scroll from left to right
* @return true if there is some more place to scroll, false - otherwise.
*/
private boolean imageViewTouchCanScroll(ImageViewTouch imageViewTouch, int direction){
int widthScreen = getWidthScreen();
RectF bitmapRect = imageViewTouch.getBitmapRect();
Rect imageViewRect = new Rect();
getGlobalVisibleRect(imageViewRect);
int widthBitmapViewTouch = (int)bitmapRect.width();
if (null == bitmapRect) {
return false;
}
if(widthBitmapViewTouch < widthScreen){
return false;
}
if (direction < 0) {
return Math.abs(bitmapRect.right - imageViewRect.right) > 1.0f;
}else {
return Math.abs(bitmapRect.left - imageViewRect.left) > 1.0f;
}
}
private int getWidthScreen(){
WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
return size.x;
}

}

对于那些在图像处于缩放状态时难以禁用viewpager的人&当图像处于原始状态时启用。我只是按照迈克的回答做了一些改变。

import android.content.Context
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import androidx.viewpager.widget.ViewPager

class DCExtendedViewPager : ViewPager {

private val TAG = DCExtendedViewPager::class.java.simpleName
private var onImageState: OnImageState? = null
private var touchImageViewCustom: DCTouchImageViewLatest? = null

var isScroll: Boolean = true
interface OnImageState {
fun checkImageState(isImageInOriginalState: Boolean)
}

constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)

override fun canScroll(view: View, checkV: Boolean, dx: Int, x: Int, y: Int): Boolean {
return if (view is DCTouchImageViewLatest) {
//   touchImageView=view
// canScrollHorizontally is not supported for Api < 14. To get around this issue,
// ViewPager is extended and canScrollHorizontallyFroyo, a wrapper around
// canScrollHorizontally supporting Api >= 8, is called.
Log.e("ExtendedViewPager", "canScroll zoomedRect" + view.zoomedRect)
view.canScrollHorizontallyFroyo(-dx)
} else {
super.canScroll(view, checkV, dx, x, y)
}
}
override fun onTouchEvent(event: MotionEvent): Boolean {
Log.e(TAG, "onTouchEventenable" + isScroll)
return if (isScroll) {
super.onTouchEvent(event)
} else false
}
override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
Log.e(TAG, "onInterceptTouchEvent")
Log.e(TAG, "currenrLayoutView called")
val currenrLayoutView = getCurrentParentView()
getTouchImageViewInstance(currenrLayoutView!!)
return if (isScroll) {
super.onInterceptTouchEvent(event)
} else false
}

fun isViewPagerScrollValid(): Boolean {
Log.e(TAG, "getFocusedChild()" + focusedChild)

val currenrLayoutView = getCurrentParentView()

var zoomRect = getTouchImageViewInstance(currenrLayoutView!!)?.zoomedRect
var orgzoomRect = getTouchImageViewInstance(currenrLayoutView)?.originalRectF

Log.e(TAG, "onInterceptTouchEvent zoomRect" + zoomRect)
Log.e(TAG, "onInterceptTouchEvent orgzoomRect" + orgzoomRect)
Log.e(TAG, "onInterceptTouchEvent onImageState" + onImageState)
var scrollEnable = (zoomRect == orgzoomRect)

// postLater(getTouchImageViewInstance(currenrLayoutView!!)!!)
onImageState?.checkImageState(scrollEnable)
Log.e(TAG, "onInterceptTouchEvent" + scrollEnable)

return scrollEnable
}

fun setImageStateListner(onImageState: OnImageState) {
this.onImageState = onImageState
}

fun getTouchImageViewInstance(accessingView: View): DCTouchImageViewLatest? {

if (touchImageViewCustom == null) {
try {
for (index in 0 until (accessingView as ViewGroup).childCount) {
var nextChild = accessingView.getChildAt(index)
Log.e(TAG, "nextChild" + nextChild)
if (nextChild is ViewGroup) {
getTouchImageViewInstance(nextChild)
} else if (nextChild is View) {
if (nextChild is DCTouchImageViewLatest) {
touchImageViewCustom = nextChild
setListner()
break
}
}
}
} catch (ex: Exception) {
ex.printStackTrace()
}

}

Log.e(TAG, "getTouchImageViewInstance" + touchImageViewCustom)
return touchImageViewCustom
}
private fun setListner() {
touchImageViewCustom?.setOnDCTouchImageViewLatestListener(object : DCTouchImageViewLatest.OnDCTouchImageViewLatestListener {
override fun onMove() {
Log.e(TAG, "onMove Called")
isScroll = isViewPagerScrollValid()
}
})
}

//Call this method from onPageSelected of viewpager
fun viewPageChanged() {
Log.e(TAG, "viewPageChanged called")
touchImageViewCustom = null
}

fun getCurrentParentView(): View? {
try {
Log.e(TAG, "getCurrentView called")
val currentItem = currentItem
for (i in 0 until childCount) {
val child = getChildAt(i)
val layoutParams = child.layoutParams as ViewPager.LayoutParams
val f = layoutParams.javaClass.getDeclaredField("position") //NoSuchFieldException
f.isAccessible = true
val position = f.get(layoutParams) as Int //IllegalAccessException
Log.e(TAG, "currentItem" + currentItem)
if (!layoutParams.isDecor && currentItem == position) {
Log.e(TAG, "getCurrentView" + child)
return child
}
}
} catch (e: NoSuchFieldException) {
Log.e(TAG, e.toString())
} catch (e: IllegalArgumentException) {
Log.e(TAG, e.toString())
} catch (e: IllegalAccessException) {
Log.e(TAG, e.toString())
}
return null
}

}

在TouchImageView类中,从setImageBitmap、setImageDrawable&setImageURI。

public RectF getOriginalRectF(){
Log.e(TAG,"getOriginalRectF called viewWidth"+viewWidth);
Log.e(TAG,"getOriginalRectF called viewHeight"+viewHeight);
if(originalRectF==null && viewHeight>0 && viewWidth>0){
if (mScaleType == ScaleType.FIT_XY) {
throw new UnsupportedOperationException("getZoomedRect() not supported with FIT_XY");
}
PointF topLeft = transformCoordTouchToBitmap(0, 0, true);
PointF bottomRight = transformCoordTouchToBitmap(viewWidth, viewHeight, true);
float w = getDrawableWidth(getDrawable());
float h = getDrawableHeight(getDrawable());

Log.e(TAG,"getOriginalRectF height"+h);
Log.e(TAG,"getOriginalRectF width"+w);
Log.e("getOriginalRectF","getZoomedRect topLeft"+topLeft.x +"-"+topLeft.y);
Log.e("getOriginalRectF","getZoomedRect bottomRight"+bottomRight.x +"-"+bottomRight.y);

originalRectF=new  RectF(topLeft.x / w, topLeft.y / h, bottomRight.x / w, bottomRight.y / h);

}

return originalRectF;
}

以上任何解决方案都不适用于我。当我使用以下ImageView:时,它对我有效

import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.animation.DecelerateInterpolator;
import android.widget.ImageView;
@SuppressLint("AppCompatCustomView")
public class TouchImageView extends ImageView implements ViewTreeObserver.OnGlobalLayoutListener,View.OnTouchListener {
private final static int SINGLE_TOUCH = 1; //Single point
private final static int DOUBLE_TOUCH = 2; //Double finger
//Multi-finger touch mode, single finger, double finger
private int mode;
//Distance between two finger touch points
private float oldDist;
private float newDist;
/**
* Maximum zoom level
*/
private static final float MAX_SCALE = 5f;
/**
* Double-click the zoom level
*/
private  float mDoubleClickScale = 2;

/**
* Scales when initialization, if the picture is wide or higher than the screen, this value will be less than 0
*/
private float initScale = 1.0f;
private boolean once = true;
private RectF rectF;
/**
* Double-click detection
*/
private GestureDetector mGestureDetector;
private int x = 0;
private int y = 0;
private Point mPoint = new Point();
private final Matrix matrix = new Matrix();
private Matrix oldMatrix = new Matrix();
private ValueAnimator animator;
public TouchImageView(Context context) {
this(context, null);
}
public TouchImageView(Context context, AttributeSet attrs) {
super(context, attrs);
super.setScaleType(ScaleType.MATRIX);
setOnTouchListener(this);
/**
* Double click to implement the picture to zoom
*/
mGestureDetector = new GestureDetector(context,
new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onDoubleTap(MotionEvent e) {
changeViewSize(e);
return true;
}
});
}
@Override
public boolean onTouch(View view, MotionEvent event) {
rectF = getMatrixRectF(); //Get image boundaries
if (mGestureDetector.onTouchEvent(event))
return true;
switch (event.getAction() & event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
//If the boundary of the picture is overstelled, then intercept the event, not letting ViewPager processing
if (rectF.width() > getWidth() || rectF.height() > getHeight()) {
getParent().requestDisallowInterceptTouchEvent(true);
}
mode = SINGLE_TOUCH;
x = (int) event.getRawX();
y = (int) event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
if (mode >= DOUBLE_TOUCH) //Double finger zoom
{
getParent().requestDisallowInterceptTouchEvent(true);
newDist = calculateDist(event); //Calculate distance
Point point = getMiPoint(event); //Get the midpoint coordinates between the two-hand fingers
if (newDist > oldDist + 1) //Pixabay (add one to prevent jitter)
{
changeViewSize(oldDist, newDist, point); //Enlarge reduction according to distance
oldDist = newDist;
}
if (oldDist > newDist + 1) //Narrow
{
changeViewSize(oldDist, newDist, point);
oldDist = newDist;
}
}
if (mode == SINGLE_TOUCH) //Drag and drop
{
float dx = event.getRawX() - x;
float dy = event.getRawY() - y;
//If the boundary of the picture in the movement exceeds the screen, then intercept the event, do not let ViewPager processing
if (rectF.width() > getWidth() || rectF.height() > getHeight()) {
getParent().requestDisallowInterceptTouchEvent(true);
}
//If you move the picture to the right, don't intercept the event, let the ViewPager process
if (rectF.left >= 0 && dx > 0)
getParent().requestDisallowInterceptTouchEvent(false);
//If you move to the left, don't intercept the event, let ViewPager processing
if (rectF.right <= getWidth() && dx < 0)
getParent().requestDisallowInterceptTouchEvent(false);
if (getDrawable() != null) {
//If the image width or height does not exceed the screen, then it is forbidden to slide around or down.
if (rectF.width() <= getWidth())
dx = 0;
if (rectF.height() < getHeight())
dy = 0;
//If the picture moves down to the end, don't let it continue to move
if (rectF.top >= 0 && dy > 0)
dy = 0;
//If the picture moves up to the end, don't let it continue to move
if (rectF.bottom <= getHeight() && dy < 0)
dy = 0;
//When the movement distance is greater than 1, it moves because Action_Move is relatively sensitive.
//  The finger can only detect the jitter of the finger and let the picture move.
if (Math.abs(dx) > 1 || Math.abs(dy) > 1)
matrix.postTranslate(dx, dy);
setImageMatrix(matrix);
}
}
x = (int) event.getRawX();
y = (int) event.getRawY();
break;
case MotionEvent.ACTION_POINTER_DOWN:
mode += 1;
oldDist = calculateDist(event);
Log.e("q", "" + "a");
Log.e(":::", "" + event.getPointerCount() + "   " + event.getActionIndex() + "   " + event.findPointerIndex(0));
break;
case MotionEvent.ACTION_POINTER_UP:
mode -= 1;
break;
case MotionEvent.ACTION_UP:
backToPosition();
mode = 0;
break;
//In Action_Move, the event is intercepted, sometimes Action_up can't trigger, so add Action_Cancel
case MotionEvent.ACTION_CANCEL:
backToPosition();
mode = 0;
break;
default:
break;
}
return true;
}
/**
* Calculate the distance between two finger touch points
*/
private float calculateDist(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return (float) Math.sqrt(x * x + y * y);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
getViewTreeObserver().addOnGlobalLayoutListener(this);
}
/**
* If it is separated from the screen boundary, then the image boundary is combined with the screen boundary.
* If the finger moves quickly, the picture will have a blank distance after the picture is stopped, and then the judgment can no longer move,
* However, it has appeared before the next judgment can continue to move.
* So you need to reset
*/
private void backToPosition() {
if (rectF.left >= 0) { //Image Left boundary and screen from the screen
matrix.postTranslate(-rectF.left, 0);
setImageMatrix(matrix);
}
if (rectF.right <= getWidth()) { //Image Right Boundary and Screen Distance
matrix.postTranslate(getWidth() - rectF.right, 0);
setImageMatrix(matrix);
}
if (rectF.top >= 0) { //Image on the image and the screen from the screen
matrix.postTranslate(0, -rectF.top);
setImageMatrix(matrix);
}
if (rectF.bottom <= getHeight()) { //Image of the image and the screen
matrix.postTranslate(0, getHeight() - rectF.bottom);
setImageMatrix(matrix);
}
}

/**
* Get the zoom in the zoom of double finger zoom
*
* @return
*/
private Point getMiPoint(MotionEvent event) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
mPoint.set((int) x / 2, (int) y / 2);
return mPoint;
}
/**
* Double finger zoom picture
*/
private void changeViewSize(float oldDist, float newDist, Point mPoint) {
float scale = newDist / oldDist; //scaling ratio
matrix.postScale(scale, scale, mPoint.x, mPoint.y);
checkBorderAndCenterWhenScale();
setImageMatrix(matrix);
//Prevent reduction is less than the initial picture size, need to reset
reSetMatrix();
//If the zoom has been larger than the target multiple, stop, because it is possible to be exceeded, then directly zoom to the target size
if (getMatrixValueX() >= MAX_SCALE)
{
matrix.postScale(MAX_SCALE/getMatrixValueX(), MAX_SCALE/getMatrixValueX(), x, y);
checkBorderAndCenterWhenScale();
setImageMatrix(matrix);
return;
}
}
/**
* Double click to zoom pictures
*/
private void changeViewSize(MotionEvent e) {
//Get double-click coordinates
final float x = e.getX();
final float y = e.getY();
//If you are still zooming, you will return directly.
if (animator != null && animator.isRunning())
return;
//Judgment is a state in which it is amplified or reduced
if (!isZoomChanged()) {
animator = ValueAnimator.ofFloat(1.0f, 2.0f);
} else {
animator = ValueAnimator.ofFloat(1.0f, 0.0f);
}
animator.setTarget(this);
animator.setDuration(500);
animator.setInterpolator(new DecelerateInterpolator());
animator.start();
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
Float value = (Float) animator.getAnimatedValue();
matrix.postScale(value, value, x, y);
checkBorderAndCenterWhenScale();
setImageMatrix(matrix);
/**
* Control reduction range
* If it is already less than the initial size, then restore to the initial size, then stop
*/
if (checkRestScale()) {
matrix.set(oldMatrix);
setImageMatrix(matrix);
return;
}
/**
* Control the range of amplification
* If the magnification of the target is already larger than the target, it is directly in the target magnification.
* Then stop
*/
if (getMatrixValueX() >= mDoubleClickScale)
{
matrix.postScale(mDoubleClickScale/getMatrixValueX(), mDoubleClickScale/getMatrixValueX(), x, y);
checkBorderAndCenterWhenScale();
setImageMatrix(matrix);
return;
}
}
});
}
/**
* Judging whether the zoom level is changed
*
* @return  TRUE expressed the non-initial value, FALSE indicates the initial value.
*/
private boolean isZoomChanged() {
float[] values = new float[9];
getImageMatrix().getValues(values);
//Get the current X-axis scale level
float scale = values[Matrix.MSCALE_X];
//Get the X-axis scaling level of the template, both
oldMatrix.getValues(values);
return scale != values[Matrix.MSCALE_X];
}
/**
* Reset Matrix
*/
private void reSetMatrix() {
if (checkRestScale()) {
matrix.set(oldMatrix);
setImageMatrix(matrix);
return;
}
}
/**
* Setup double-click a large multiple
*/
private void setDoubleClickScale(RectF rectF)
{
if(rectF.height()<getHeight()-100)
{
mDoubleClickScale=getHeight()/rectF.height();
}
else
mDoubleClickScale=2f;
}
/**
* Judging whether it needs to be reset
*
* @return  When the current zoom level is less than the template zoom level, reset
*/
private boolean checkRestScale() {
// TODO Auto-generated method stub
float[] values = new float[9];
getImageMatrix().getValues(values);
//Get the current X-axis scale level
float scale = values[Matrix.MSCALE_X];
//Get the X-axis scaling level of the template, both
oldMatrix.getValues(values);
return scale < values[Matrix.MSCALE_X];
}
private float getMatrixValueX()
{
// TODO Auto-generated method stub
float[] values = new float[9];
getImageMatrix().getValues(values);
//Get the current X-axis scale level
float scale = values[Matrix.MSCALE_X];
//Get the X-axis scaling level of the template, both
oldMatrix.getValues(values);
return scale / values[Matrix.MSCALE_X];
}
/**
* When zooming, perform image display scope control
*/
private void checkBorderAndCenterWhenScale()
{
RectF rect = getMatrixRectF();
float deltaX = 0;
float deltaY = 0;
int width = getWidth();
int height = getHeight();
//  Control range if wide or higher than the screen
if (rect.width() >= width)
{
if (rect.left > 0)
{
deltaX = -rect.left;
}
if (rect.right < width)
{
deltaX = width - rect.right;
}
}
if (rect.height() >= height)
{
if (rect.top > 0)
{
deltaY = -rect.top;
}
if (rect.bottom < height)
{
deltaY = height - rect.bottom;
}
}
//  If the width or higher is less than the screen, let it hit
if (rect.width() < width)
{
deltaX = width * 0.5f - rect.right + 0.5f * rect.width();
}
if (rect.height() < height)
{
deltaY = height * 0.5f - rect.bottom + 0.5f * rect.height();
}
Log.e("TAG", "deltaX = " + deltaX + " , deltaY = " + deltaY);
matrix.postTranslate(deltaX, deltaY);
setImageMatrix(matrix);
}
/**
* Get the range of images according to the Matrix of the current picture
*
* @return
*/
private RectF getMatrixRectF()
{
RectF rect = new RectF();
Drawable d = getDrawable();
if (null != d)
{
rect.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
matrix.mapRect(rect); //If this is not this, the output of the following Log will be the same as the previous sentence.
}
Log.e("aaaa",""+rect.bottom+"  "+rect.left+"   "+rect.right+"  "+rect.top);
return rect;
}
@Override
public void onGlobalLayout() {
if (once)
{
Drawable d = getDrawable();
if (d == null)
return;
Log.e("TAG", d.getIntrinsicWidth() + " , " + d.getIntrinsicHeight());
int width = getWidth();
int height = getHeight();
//  Get the width and high of the picture
int dw = d.getIntrinsicWidth();
int dh = d.getIntrinsicHeight();
float scale = 1.0f;
// If the image is wide or higher than the screen, zoom to the width or high of the screen.
if (dw > width && dh <= height)
{
scale = width * 1.0f / dw;
}
if (dh > height && dw <= width)
{
scale = height * 1.0f / dh;
}
//  If the width and high are greater than the screen, it will make it adapt to the screen size according to the proportion.
if (dw > width && dh > height)
{
scale = Math.min(width * 1.0f / dw, height * 1.0f / dh);
}
initScale = scale;
Log.e("TAG", "initScale = " + initScale);
matrix.postTranslate((width - dw) / 2, (height - dh) / 2);
matrix.postScale(scale, scale, getWidth() / 2,
getHeight() / 2);
//  Image Move to the screen center
setImageMatrix(matrix);
oldMatrix.set(getImageMatrix());
once = false;
RectF rectF=getMatrixRectF();
setDoubleClickScale(rectF);
}
}
}

此外,我使用了以下ExtendedViewPager:

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import androidx.viewpager.widget.ViewPager;
public class ExtendedViewPager extends ViewPager {
public ExtendedViewPager(Context context) {
super(context);
}
public ExtendedViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
try {
return super.onTouchEvent(ev);
} catch (IllegalArgumentException ex) {
ex.printStackTrace();
}
return false;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
try {
return super.onInterceptTouchEvent(ev);
} catch (IllegalArgumentException ex) {
ex.printStackTrace();
}
return false;
}

}

最新更新