4

Is there an equivalent in android of UIScrollView where I can slide an image around. Thank you.

Sorry I was not more specific. I need to slide in all directions. Androids ScrollView will not do this. I been using a WebView which works but it only works on 4.0 and higher it seems like.


This is what I came up with. I put my ImageView inside of a WebView and I assigned setOnTouchListener on ImageView. It seems to work well.

  web = new WebView(this);
  web.setVerticalScrollBarEnabled(false);
  web.setHorizontalScrollBarEnabled(false);
  web.setBackgroundColor(Color.RED);
  web.setId(100);
  RelativeLayout.LayoutParams layoutForContainer = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
    layoutForContainer.height = 300;
    layoutForContainer.width = 300;
    layoutForContainer.addRule(RelativeLayout.CENTER_IN_PARENT);
    web.setLayoutParams(layoutForContainer);     
  layout.addView(web);

  myImageView = new ImageView(this);
  myImageView.setImageResource(R.drawable.myImage); 
  RelativeLayout.LayoutParams layoutForLargeImage = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
  layoutForLargeImage.height = (int) 768;
  layoutForLargeImage.width = (int) 1024;
  myImageView.setLayoutParams(layoutForLargeImage); 
  web.addView(myImageView);

  myImageView.setOnTouchListener(new View.OnTouchListener() {
    float downX, downY;
    int scrollByX, scrollByY;
    public boolean onTouch(View view, MotionEvent event) {
        float currentX, currentY;
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                downX = event.getX();
                downY = event.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                currentX = event.getX();
                currentY = event.getY();
                scrollByX = (int)(downX - currentX);
                scrollByY = (int)(downY - currentY);

                myImageView.scrollBy(scrollByX, scrollByY);
                downX = currentX;
                downY = currentY;

                break;
        }
        return true;
    }
});
Bobby
  • 6,115
  • 4
  • 35
  • 36
  • possible duplicate of [View with horizontal and vertical pan/drag and pinch-zoom](http://stackoverflow.com/questions/12479859/view-with-horizontal-and-vertical-pan-drag-and-pinch-zoom) – Shalmezad Nov 04 '14 at 19:23

3 Answers3

2

This question's almost a year old, but it's the top in a google search for this problem, so I thought I'd add some details.

If you're looking for a generic one direction view that can scroll, the other answers of using Android's built in ScrollView will work fine.

However, if you want the multidirectional aspect of iOS's UIScrollView, you'll have to design/use a custom view (or use a hack such as using a webview). An example implementation of a view that can do this can be found in a related question here:

View with horizontal and vertical pan/drag and pinch-zoom

Then depending on your tastes, you can modify it as needed, such as this implementation without the zooming (just the panning):

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.view.*;

public class MultiDirectionPanGroup extends ViewGroup {

    private static final int INVALID_POINTER_ID = 1;
    private int mActivePointerId = INVALID_POINTER_ID;

    private float mPosX;
    private float mPosY;
    private Matrix mTranslateMatrix = new Matrix();
    private Matrix mTranslateMatrixInverse = new Matrix();

    private float mLastTouchX;
    private float mLastTouchY;

    private float mFocusY;

    private float mFocusX;

    private float[] mInvalidateWorkingArray = new float[6];
    private float[] mDispatchTouchEventWorkingArray = new float[2];
    private float[] mOnTouchEventWorkingArray = new float[2];


    public MultiDirectionPanGroup(Context context) {
        super(context);
        mTranslateMatrix.setTranslate(0, 0);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = getChildAt(i);
            if (child.getVisibility() != GONE) {
                child.layout(l, t, l+child.getMeasuredWidth(), t + child.getMeasuredHeight());
            }
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = getChildAt(i);
            if (child.getVisibility() != GONE) {
                measureChild(child, widthMeasureSpec, heightMeasureSpec);
            }
        }
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        canvas.save();
        canvas.translate(mPosX, mPosY);
        super.dispatchDraw(canvas);
        canvas.restore();
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        mDispatchTouchEventWorkingArray[0] = ev.getX();
        mDispatchTouchEventWorkingArray[1] = ev.getY();
        mDispatchTouchEventWorkingArray = screenPointsToScaledPoints(mDispatchTouchEventWorkingArray);
        ev.setLocation(mDispatchTouchEventWorkingArray[0],
                mDispatchTouchEventWorkingArray[1]);
        return super.dispatchTouchEvent(ev);
    }

    /**
     * Although the docs say that you shouldn't override this, I decided to do
     * so because it offers me an easy way to change the invalidated area to my
     * likening.
     */
    @Override
    public ViewParent invalidateChildInParent(int[] location, Rect dirty) {

        mInvalidateWorkingArray[0] = dirty.left;
        mInvalidateWorkingArray[1] = dirty.top;
        mInvalidateWorkingArray[2] = dirty.right;
        mInvalidateWorkingArray[3] = dirty.bottom;


        mInvalidateWorkingArray = scaledPointsToScreenPoints(mInvalidateWorkingArray);
        dirty.set(Math.round(mInvalidateWorkingArray[0]), Math.round(mInvalidateWorkingArray[1]),
                Math.round(mInvalidateWorkingArray[2]), Math.round(mInvalidateWorkingArray[3]));

        location[0] *= mScaleFactor;
        location[1] *= mScaleFactor;
        return super.invalidateChildInParent(location, dirty);
    }

    private float[] scaledPointsToScreenPoints(float[] a) {
        mTranslateMatrix.mapPoints(a);
        return a;
    }

    private float[] screenPointsToScaledPoints(float[] a){
        mTranslateMatrixInverse.mapPoints(a);
        return a;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        mOnTouchEventWorkingArray[0] = ev.getX();
        mOnTouchEventWorkingArray[1] = ev.getY();

        mOnTouchEventWorkingArray = scaledPointsToScreenPoints(mOnTouchEventWorkingArray);

        ev.setLocation(mOnTouchEventWorkingArray[0], mOnTouchEventWorkingArray[1]);

        final int action = ev.getAction();
        switch (action & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN: {
                final float x = ev.getX();
                final float y = ev.getY();

                mLastTouchX = x;
                mLastTouchY = y;

                // Save the ID of this pointer
                mActivePointerId = ev.getPointerId(0);
                break;
            }

            case MotionEvent.ACTION_MOVE: {
                // Find the index of the active pointer and fetch its position
                final int pointerIndex = ev.findPointerIndex(mActivePointerId);
                final float x = ev.getX(pointerIndex);
                final float y = ev.getY(pointerIndex);

                final float dx = x - mLastTouchX;
                final float dy = y - mLastTouchY;

                mPosX += dx;
                mPosY += dy;
                mTranslateMatrix.preTranslate(dx, dy);
                mTranslateMatrix.invert(mTranslateMatrixInverse);

                mLastTouchX = x;
                mLastTouchY = y;

                invalidate();
                break;
            }

            case MotionEvent.ACTION_UP: {
                mActivePointerId = INVALID_POINTER_ID;
                break;
            }

            case MotionEvent.ACTION_CANCEL: {
                mActivePointerId = INVALID_POINTER_ID;
                break;
            }

            case MotionEvent.ACTION_POINTER_UP: {
                // Extract the index of the pointer that left the touch sensor
                final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
                final int pointerId = ev.getPointerId(pointerIndex);
                if (pointerId == mActivePointerId) {
                    // This was our active pointer going up. Choose a new
                    // active pointer and adjust accordingly.
                    final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
                    mLastTouchX = ev.getX(newPointerIndex);
                    mLastTouchY = ev.getY(newPointerIndex);
                    mActivePointerId = ev.getPointerId(newPointerIndex);
                }
                break;
            }
        }
        return true;
    }

}
Community
  • 1
  • 1
Shalmezad
  • 475
  • 1
  • 4
  • 21
1

Obviously, there are many options like UIScrollView, (1) you can take HorizontalScrollView (2) you can take Viewpager.

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >  

 <WebView
            android:id="@+id/webview"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />                   
</RelativeLayout>
Hiren Patel
  • 52,124
  • 21
  • 173
  • 151
  • ScrollView only supports vertical scrolling. I need to scroll in all directions. – Bobby Sep 28 '13 at 03:38
  • which type of contents you have? my means either HTML data or other? – Hiren Patel Sep 28 '13 at 03:43
  • I just have an ImageView I want to scroll. I put it in a WebView but it does not work lower than 4.0. I have been messing with setOnTouchListener on A container that holds ImageView which works nicely but I cannot get the ImageView to be bigger and then whatever container I have it in that scrolls. – Bobby Sep 29 '13 at 01:59
  • @Bob webview does not require Scrollview. it has its own scroll view. you can take webview without Scrollview. webview will scroll automatically with contents of data you have. See my edited answer. – Hiren Patel Sep 30 '13 at 05:07
-1

you can do this using in android

<ScrollView
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     >

 </ScrollView>
mharindu
  • 167
  • 3