Android View Pager + ImageView +双指缩放 + 旋转
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20943831/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
View Pager + ImageView +Pinch Zoom + Rotation
提问by Avtar Guleria
I want to implement Pinch Zoom on Imageview, with in View Pager similar to Default Android Gallery. I have found multiple source over GitHub, But the zoom and sliding just work for only first image.
我想在 Imageview 上实现捏缩放,在 View Pager 中类似于 Default Android Gallery。我在 GitHub 上找到了多个来源,但缩放和滑动仅适用于第一张图像。
What I have tried:
我尝试过的:
1.) TouchImageView
1.)触摸图像视图
2.) PhotoView
2.) 照片视图
3.)安卓触控图库
All the above links works fine for single image view. But when it comes to Images in View pager, They have some glitches and only works fine for first image in the View Pager. When we scroll over to 3rd 4th image in view pager, Dragging functionality not working as expected if the image is zoomed.
以上所有链接都适用于单个图像视图。但是当涉及到视图寻呼机中的图像时,它们有一些小故障,并且仅适用于视图寻呼机中的第一张图像。当我们在视图寻呼机中滚动到第 3 4 张图像时,如果图像被缩放,则拖动功能无法按预期工作。
Please if any one knows any good library for doing this, then provide me the link for them.
如果有人知道这样做的好图书馆,请为我提供他们的链接。
回答by Mike Ortiz
EDIT 2: Example code has been pushed to the master branch of TouchImageView. Here is a link to the example activityand a link to the ExtendedViewPager.
编辑 2:示例代码已被推送到 TouchImageView 的主分支。这是示例活动的链接和 ExtendedViewPager的链接。
EDIT: added code adapting the example link to TouchImageView. Note: you will need the latest code, which is currently in the dev branch. In the future, this will be included in v1.2.0. You know you have the latest code if TouchImageView overrides canScrollHorizontally.
编辑:添加了将示例链接改编为 TouchImageView 的代码。注意:您将需要最新的代码,该代码当前位于 dev 分支中。将来,这将包含在 v1.2.0 中。如果 TouchImageView 覆盖 canScrollHorizontally,您就知道您拥有最新的代码。
Step 1: Extend ViewPager and override canScroll to call canScrollHorizontallyFroyo.
第 1 步:扩展 ViewPager 并覆盖 canScroll 以调用 canScrollHorizontallyFroyo。
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);
}
}
}
Step 2:Modify TouchImageView by adding canScrollHorizontallyFroyo:
第 2 步:通过添加 canScrollHorizontallyFroyo 来修改 TouchImageView:
public boolean canScrollHorizontallyFroyo(int direction) {
return canScrollHorizontally(direction);
}
Step 3:Your activity
第 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;
}
}
}
Step 4:main.xml
第 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 is actually my project. I currently have a fixin the dev branchfor integration with ViewPagers, which will be pushed to master in an upcoming release. Unfortunately, this fix is only applicable for API 14 and greater since honeycomb and earlier do not call canScrollHorizontally
. If you need to support older APIs, then you will need to implement a workaround in your ViewPager. Here is an example.
TouchImageView 实际上是我的项目。我目前在dev 分支中有一个与 ViewPagers 集成的修复程序,它将在即将发布的版本中推送到 master。不幸的是,此修复仅适用于 API 14 及更高版本,因为 Honeycomb 及更早版本不调用. 如果您需要支持较旧的 API,那么您需要在 ViewPager 中实现一种解决方法。这是一个例子。canScrollHorizontally
回答by Mansurov Ruslan
I found pretty solution with ImageViewZoomlibrary. In order to scroll zoomed image in ViewPager I created own 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);
}
}
}
回答by lobzik
After several hours of testing the solutions above I have finally found the awesome Subsampling Scale Image Viewlibrary, which works even with standard ViewPager from Android Support Package.
经过几个小时的测试上述解决方案,我终于找到了很棒的子采样比例图像视图库,它甚至可以与 Android 支持包中的标准 ViewPager 一起使用。
回答by moondroid
My solution using ImageViewZoom Libraryis based on this custom 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;
}
}
}
回答by Krystian
I corrected the previous solution . You can scroll page , when ImageViewTouch is mode zoom.
我更正了以前的解决方案。当 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;
}
}
}
回答by Vikas Rai
For Those who are struggling to disable viewpager when the image is in pinched to zoom state & enable when the image is in original state. I just made some changes as answered by Mike.
对于那些在图像处于缩放状态时努力禁用 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
}
}
In TouchImageView class, call getOriginalRectF() from setImageBitmap, setImageDrawable & setImageURI.
在 TouchImageView 类中,从 setImageBitmap、setImageDrawable 和 setImageURI 调用 getOriginalRectF()。
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;
}