Scrollview вертикальный и горизонтальный в Android
Я очень устал искать решение для вертикальной и горизонтальной прокрутки.
Я прочитал, что в фреймворке нет никаких представлений / макетов, которые реализуют эту функцию, но мне нужно что-то вроде этого:
Мне нужно определить макет внутри другого, дочерний макет должен реализовывать прокрутку по вертикали / горизонтали для перемещения.
Изначально реализован код, который перемещал макет пиксель за пикселем, но я думаю, что это не правильный путь. Я попробовал это с ScrollView и Horizontal ScrollView, но ничего не работает так, как я хочу, потому что он реализует только вертикальную или горизонтальную прокрутку.
Canvas - не мое решение, потому что мне нужно прикрепить слушателей к чьим-то дочерним элементам.
Что я могу сделать?
12 ответов
Смешав некоторые из предложенных выше предложений, удалось найти хорошее решение:
Пользовательский 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;
}
}
Пользовательский 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;
}
}
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;
}
}
расположение:
<?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>
Так как это, кажется, первый результат поиска в Google для "Android вертикальный + горизонтальный ScrollView", я подумал, что должен добавить это здесь. Мэтт Кларк создал собственный вид на основе источника Android, и он, кажется, отлично работает: двумерный ScrollView
Помните, что у класса на этой странице есть ошибка, вычисляющая горизонтальную ширину представления. Исправление Мануэля Хилти в комментариях:
Решение: замените оператор в строке 808 следующим текстом:
final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.leftMargin + lp.rightMargin, MeasureSpec.UNSPECIFIED);
Изменить: Ссылка больше не работает, но вот ссылка на старую версию поста.
Я нашел лучшее решение.
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-код:
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;
}
}
Это работает!!!
Если вы хотите загрузить другой макет или элемент управления, структура будет такой же.
Я им пользуюсь и отлично работает
<?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>
Ссылка на источник находится здесь: Android-spa
Мое решение основано на ответе Махди Хиджази, но без каких-либо пользовательских представлений:
Планировка:
<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>
Код (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;
}
});
Вы можете изменить порядок прокрутки. Просто измените их порядок в макете и в коде. И очевидно, что вместо WeverViewYou вы хотите поместить макет / представления, которые вы хотите прокрутить в обоих направлениях.
Попробуй это
<?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>
Вариант № 1: Вы можете придумать новый дизайн пользовательского интерфейса, который не требует одновременной горизонтальной и вертикальной прокрутки.
Вариант № 2: Вы можете получить исходный код ScrollView
а также HorizontalScrollView
узнайте, как их реализовала основная команда Android, и создайте свой собственный BiDirectionalScrollView
реализация.
Вариант № 3: Вы можете избавиться от зависимостей, которые требуют от вас использовать систему виджетов и рисовать прямо на холсте.
Вариант № 4: Если вы наткнулись на приложение с открытым исходным кодом, которое, кажется, реализует то, что вы ищете, посмотрите, как они это сделали.
Поскольку ссылка на двухмерное прокручивание не работает, я не смог ее получить, поэтому создал свой собственный компонент. Он справляется со сбрасыванием и работает правильно для меня. Единственное ограничение заключается в том, что wrap_content может не работать должным образом для этого компонента.
У меня есть решение вашей проблемы. Вы можете проверить код ScrollView, он обрабатывает только вертикальную прокрутку, игнорирует горизонтальную и изменить это. Мне нужен был вид, похожий на веб-просмотр, поэтому я модифицировал ScrollView, и он хорошо работал для меня. Но это может не соответствовать вашим потребностям.
Дайте мне знать, на какой пользовательский интерфейс вы ориентируетесь.
С Уважением,
Рави Пандит
Играя с кодом, вы можете поместить HorizontalScrollView в ScrollView. Таким образом, вы можете использовать два метода прокрутки в одном представлении.
Источник: http://androiddevblog.blogspot.com/2009/12/creating-two-dimensions-scroll-view.html
Я надеюсь, что это может помочь вам.
Использовать это, как я пытался это я исправил
Поместите все ваши XML макет внутри
<android.support.v4.widget.NestedScrollView
Я объяснил это в этой ссылке: вертикальная прокрутка и горизонтальная прокрутка.
Если вы хотите прокручивать вертикально и горизонтально, это пример:
Горизонтальная прокрутка внутри вертикальной прокрутки, и обе работы:
<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>