Просмотр пейджера + ImageView + Пинч-масштабирование + поворот
Я хочу реализовать Pinch Zoom на Imageview, с помощью панели просмотра Pager, похожей на галерею Android по умолчанию. Я нашел несколько источников по GitHub, но масштабирование и скользящее просто работают только для первого изображения.
Что я пробовал:
1.) TouchImageView
2.) PhotoView
3.) Android Touch Gallery
Все приведенные выше ссылки отлично работают для просмотра одного изображения. Но когда дело доходит до пейджера "Изображения в представлении", у них есть некоторые сбои и только отлично работает для первого изображения в представлении "Пейджер". Когда мы перейдем к 3-му четвертому изображению в представлении пейджера, функция перетаскивания не работает должным образом, если изображение увеличено.
Пожалуйста, если кто-нибудь знает какую-либо хорошую библиотеку для этого, дайте мне ссылку для них.
Ответы
Ответ 1
ОБНОВЛЕНИЕ 2: Пример кода был передан в главную ветку TouchImageView. Вот ссылка на пример активности и ссылка на ExtendedViewPager.
ОБНОВЛЕНИЕ: добавлен код, адаптирующий пример ссылки на TouchImageView. Примечание: вам понадобится последний код, который в данный момент находится в ветке dev. В будущем это будет включено в v1.2.0. Вы знаете, что у вас последний код, если TouchImageView переопределяет canScrollHorizontally.
Шаг 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);
}
}
}
Шаг 2. Измените TouchImageView, добавив canScrollHorizontallyFroyo:
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 на самом деле мой проект. В настоящее время у меня есть исправление в ветки dev для интеграции с ViewPager, которое будет передано мастеру в следующем выпуске. К сожалению, это исправление применимо только для API 14 и выше, поскольку сотовые и более ранние версии не вызывают canScrollHorizontally
. Если вам нужно поддерживать более старые API, вам нужно будет обойти это в вашем ViewPager. Вот пример.
Ответ 2
Я нашел довольно эффективное решение с библиотекой 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
Ответ 3
После нескольких часов тестирования вышеприведенных решений я наконец нашел потрясающую библиотеку масштабирования с уменьшенным выбором изображений, которая работает даже со стандартным ViewPager с Android Пакет поддержки.
Ответ 4
Мое решение с использованием Библиотека 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;
}
}
}
Ответ 5
Я исправил предыдущее решение. Вы можете прокручивать страницу, когда 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;
}
}
Ответ 6
Для тех, кто пытается отключить просмотр, когда изображение находится в защемлении, чтобы увеличить масштаб и включить, когда изображение находится в исходном состоянии. Я только что внес некоторые изменения в ответ майк.
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
}
}