查看寻呼机+ ImageView + Pinch缩放+旋转

时间:2014-01-06 05:52:07

标签: android imageview android-viewpager pinchzoom

我想在Imageview上实现Pinch Zoom,在View Pager中类似于Default Android Gallery。我在GitHub上找到了多个源,但缩放和滑动仅适用于第一张图像。

我尝试过:

1。)TouchImageView

2。)PhotoView

3。)Android Touch Gallery

以上所有链接适用于单张图片视图。但是当谈到Images in View寻呼机时,它们会有一些故障,只能在View Pager中对第一张图像工作正常。当我们在视图寻呼机中滚动到第3个第4个图像时,如果图像被缩放,拖动功能将无法按预期工作。

如果有人知道任何一个好的图书馆这样做,那么请给我链接。

6 个答案:

答案 0 :(得分:40)

编辑2:示例代码已被推送到TouchImageView的主分支。这是link to the example activitylink to the ExtendedViewPager


编辑:添加了将示例链接调整为TouchImageView的代码。注意:您将需要最新的代码,该代码当前位于dev分支中。将来,这将包含在v1.2.0中。如果TouchImageView覆盖canScrollHorizo​​ntally,你知道你有最新的代码。

第1步:扩展ViewPager并覆盖canScroll以调用canScrollHorizo​​ntallyFroyo。

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步:通过添加canScrollHorizo​​ntallyFroyo修改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实际上是我的项目。我目前在a fix中有dev branch与ViewPagers集成,后者将在即将发布的版本中推送到掌握。不幸的是,此修复程序仅适用于API 14及更高版本,因为蜂窝和早期版本不会调用canScrollHorizontally。如果您需要支持较旧的API,则需要在ViewPager中实施变通方法。 Here is an example.

答案 1 :(得分:4)

我找到了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

答案 2 :(得分:3)

经过几个小时的上述解决方案测试后,我终于找到了令人敬畏的Subsampling Scale Image View库,它甚至可以与Android支持包中的标准ViewPager一起使用。

答案 3 :(得分:2)

我使用ImageViewZoom Library的解决方案基于此自定义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;
        }

    }
}

答案 4 :(得分:0)

我纠正了以前的解决方案。当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;
}

}

答案 5 :(得分:0)

对于那些努力在图像处于缩放状态时禁用viewpager并在图像处于原始状态时启用的用户。我刚刚做了一些更改,正如Mike回答的那样。

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调用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;

    }