Scrollview vertical and horizontal in android

AndroidScrollview

Android Problem Overview


I'm really tired looking for a solution for vertical and horizontal Scrollview.

I read that there are not any views/layouts in the framework which implement this feature, but I need something like this:

I need to define a layout within other, the child layout must implement scrolling vertical/horizontal for moving.

Initially implemented a code that moved the layout pixel by pixel, but I think that is not the right way. I tried it with ScrollView and Horizontal ScrollView but nothing works like I want it to, because it only implements vertical or horizontal scrolling.

Canvas is not my solution because I need to attach listeners in someones child elements.

What can I do?

Android Solutions


Solution 1 - Android

Mixing some of the suggestions above, and was able to get a good solution:

Custom ScrollView:

package com.scrollable.view;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ScrollView;

public class VScroll extends ScrollView {

	public VScroll(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

	public VScroll(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	public VScroll(Context context) {
		super(context);
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		return false;
	}
}

Custom HorizontalScrollView:

package com.scrollable.view;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.HorizontalScrollView;

public class HScroll extends HorizontalScrollView {

	public HScroll(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

	public HScroll(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	public HScroll(Context context) {
		super(context);
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		return false;
	}
}

the ScrollableImageActivity:

package com.scrollable.view;

import android.app.Activity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.widget.HorizontalScrollView;
import android.widget.ScrollView;

public class ScrollableImageActivity extends Activity {

	private float mx, my;
	private float curX, curY;

	private ScrollView vScroll;
	private HorizontalScrollView hScroll;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		vScroll = (ScrollView) findViewById(R.id.vScroll);
		hScroll = (HorizontalScrollView) findViewById(R.id.hScroll);

	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		float curX, curY;

		switch (event.getAction()) {

			case MotionEvent.ACTION_DOWN:
				mx = event.getX();
				my = event.getY();
				break;
			case MotionEvent.ACTION_MOVE:
				curX = event.getX();
				curY = event.getY();
				vScroll.scrollBy((int) (mx - curX), (int) (my - curY));
				hScroll.scrollBy((int) (mx - curX), (int) (my - curY));
				mx = curX;
				my = curY;
				break;
			case MotionEvent.ACTION_UP:
				curX = event.getX();
				curY = event.getY();
				vScroll.scrollBy((int) (mx - curX), (int) (my - curY));
				hScroll.scrollBy((int) (mx - curX), (int) (my - curY));
				break;
		}

		return true;
	}

}

the layout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="vertical" android:layout_width="fill_parent"
	android:layout_height="fill_parent">
	<com.scrollable.view.VScroll android:layout_height="fill_parent"
		android:layout_width="fill_parent" android:id="@+id/vScroll">
		<com.scrollable.view.HScroll android:id="@+id/hScroll"
			android:layout_width="fill_parent" android:layout_height="fill_parent">
			<ImageView android:layout_width="fill_parent" android:layout_height="fill_parent" android:src="@drawable/bg"></ImageView>
		</com.scrollable.view.HScroll>
	</com.scrollable.view.VScroll>

</LinearLayout>

Solution 2 - Android

Since this seems to be the first search result in Google for "Android vertical+horizontal ScrollView", I thought I should add this here. Matt Clark has built a custom view based on the Android source, and it seems to work perfectly: Two Dimensional ScrollView

Beware that the class in that page has a bug calculating the view's horizonal width. A fix by Manuel Hilty is in the comments:

> Solution: Replace the statement on line 808 by the following: > > final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.leftMargin + lp.rightMargin, MeasureSpec.UNSPECIFIED);


Edit: The Link doesn't work anymore but here is a link to an old version of the blogpost.

Solution 3 - Android

I found a better solution.

XML: (design.xml)

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent">
  <FrameLayout android:layout_width="90px" android:layout_height="90px">
    <RelativeLayout android:id="@+id/container" android:layout_width="fill_parent" android:layout_height="fill_parent">        
    </RelativeLayout>
</FrameLayout>
</FrameLayout>

Java Code:

public class Example extends Activity {
  private RelativeLayout container;
  private int currentX;
  private int currentY;

  protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.design);
	
	container = (RelativeLayout)findViewById(R.id.container);
	
	int top = 0;
	int left = 0;
	
	ImageView image1 = ...
	RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
	layoutParams.setMargins(left, top, 0, 0);				
	container.addView(image1, layoutParams);
	
	ImageView image2 = ...
	left+= 100;
	RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
	layoutParams.setMargins(left, top, 0, 0);				
	container.addView(image2, layoutParams);
	
	ImageView image3 = ...
	left= 0;
	top+= 100;
	RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
	layoutParams.setMargins(left, top, 0, 0);				
	container.addView(image3, layoutParams);
	
	ImageView image4 = ...
	left+= 100;		
	RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
	layoutParams.setMargins(left, top, 0, 0);				
	container.addView(image4, layoutParams);
  }		

  @Override	
  public boolean onTouchEvent(MotionEvent event) {
	switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN: {
            currentX = (int) event.getRawX();
            currentY = (int) event.getRawY();
            break;
        }

        case MotionEvent.ACTION_MOVE: {
            int x2 = (int) event.getRawX();
            int y2 = (int) event.getRawY();
            container.scrollBy(currentX - x2 , currentY - y2);
            currentX = x2;
            currentY = y2;
            break;
        }	
        case MotionEvent.ACTION_UP: {
            break;
        }
    }
      return true; 
  }
}

That's works!!!

If you want to load other layout or control, the structure is the same.

Solution 4 - Android

I use it and works fine:

<?xml version="1.0" encoding="utf-8"?>
<ScrollView android:id="@+id/ScrollView02" 
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content"
            xmlns:android="http://schemas.android.com/apk/res/android">
<HorizontalScrollView android:id="@+id/HorizontalScrollView01" 
                      android:layout_width="wrap_content" 
                      android:layout_height="wrap_content">
<ImageView android:id="@+id/ImageView01"
           android:src="@drawable/pic" 
           android:isScrollContainer="true" 
           android:layout_height="fill_parent" 
           android:layout_width="fill_parent" 
           android:adjustViewBounds="true">
</ImageView>
</HorizontalScrollView>
</ScrollView>

The source link is here: Android-spa

Solution 5 - Android

My solution based on Mahdi Hijazi answer, but without any custom views: Layout:

<HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/scrollHorizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ScrollView 
        android:id="@+id/scrollVertical"
        android:layout_width="wrap_content"
        android:layout_height="match_parent" >
		    
        <WateverViewYouWant/>

    </ScrollView>
</HorizontalScrollView>

Code (onCreate/onCreateView):

	final HorizontalScrollView hScroll = (HorizontalScrollView) value.findViewById(R.id.scrollHorizontal);
	final ScrollView vScroll = (ScrollView) value.findViewById(R.id.scrollVertical);
	vScroll.setOnTouchListener(new View.OnTouchListener() {	//inner scroll listener 		
		@Override
		public boolean onTouch(View v, MotionEvent event) {
			return false;
		}
	});
	hScroll.setOnTouchListener(new View.OnTouchListener() { //outer scroll listener			
		private float mx, my, curX, curY;
		private boolean started = false;

		@Override
		public boolean onTouch(View v, MotionEvent event) {
			curX = event.getX();
			curY = event.getY();
			int dx = (int) (mx - curX);
			int dy = (int) (my - curY);
			switch (event.getAction()) {
				case MotionEvent.ACTION_MOVE:
					if (started) {
						vScroll.scrollBy(0, dy);
						hScroll.scrollBy(dx, 0);
					} else {
						started = true;
					}
					mx = curX;
					my = curY;
					break;
				case MotionEvent.ACTION_UP: 
					vScroll.scrollBy(0, dy);
					hScroll.scrollBy(dx, 0);
					started = false;
					break;
			}
			return true;
		}
	});

You can change the order of the scrollviews. Just change their order in layout and in the code. And obviously instead of WateverViewYouWant you put the layout/views you want to scroll both directions.

Solution 6 - Android

Option #1: You can come up with a new UI design that does not require simultaneous horizontal and vertical scrolling.

Option #2: You can obtain the source code to ScrollView and HorizontalScrollView, learn how the core Android team implemented those, and create your own BiDirectionalScrollView implementation.

Option #3: You can get rid of the dependencies that are requiring you to use the widget system and draw straight to the Canvas.

Option #4: If you stumble upon an open source application that seems to implement what you seek, look to see how they did it.

Solution 7 - Android

Try this

<?xml version="1.0" encoding="utf-8"?>
<ScrollView android:id="@+id/Sview" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content"
        xmlns:android="http://schemas.android.com/apk/res/android">
<HorizontalScrollView 
   android:id="@+id/hview" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content">
<ImageView .......
 [here xml code for image]
</ImageView>
</HorizontalScrollView>
</ScrollView>

Solution 8 - Android

since the Two Dimensional Scrollview link is dead I could not get it so I created my own component. It handles flinging and works properly for me. The only restriction is that wrap_content might not work properly for that component.

https://gist.github.com/androidseb/9902093

Solution 9 - Android

I have a solution for your problem. You can check the ScrollView code it handles only vertical scrolling and ignores the horizontal one and modify this. I wanted a view like a webview, so modified ScrollView and it worked well for me. But this may not suit your needs.

Let me know what kind of UI you are targeting for.

Regards,

Ravi Pandit

Solution 10 - Android

Playing with the code, you can put an HorizontalScrollView into an ScrollView. Thereby, you can have the two scroll method in the same view.

Source : http://androiddevblog.blogspot.com/2009/12/creating-two-dimensions-scroll-view.html

I hope this could help you.

Solution 11 - Android

use this way I tried this I fixed it

Put All your XML layout inside

<android.support.v4.widget.NestedScrollView 

I explained this in this link https://stackoverflow.com/questions/54532894/vertical-recyclerview-and-horizontal-recyclerview-scrolling-together

Solution 12 - Android

If you want to scroll vertically and horizontally this is an example:

Horizontal scroll inside vertical scroll and both works:

<ScrollView
        android:id="@+id/verticalScroll"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

...
     <HorizontalScrollView
            android:id="@+id/horizontalScroll"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            *android:overScrollMode="never"*>
...
     </HorizontalScrollView>
...
</ScrollView>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionKronosView Question on Stackoverflow
Solution 1 - AndroidMahdi HijaziView Answer on Stackoverflow
Solution 2 - AndroidCachapaView Answer on Stackoverflow
Solution 3 - AndroidKronosView Answer on Stackoverflow
Solution 4 - AndroidRedaxView Answer on Stackoverflow
Solution 5 - AndroidYan.YurkinView Answer on Stackoverflow
Solution 6 - AndroidCommonsWareView Answer on Stackoverflow
Solution 7 - AndroidMBMJView Answer on Stackoverflow
Solution 8 - AndroidandroidsebView Answer on Stackoverflow
Solution 9 - AndroidRavi PanditView Answer on Stackoverflow
Solution 10 - AndroidEriatolcView Answer on Stackoverflow
Solution 11 - AndroidSirwan RahimiView Answer on Stackoverflow
Solution 12 - AndroidEgor ShlomaView Answer on Stackoverflow