Intereting Posts
Студия Android не открывается в Windows Как настроить цвет фона элемента и цвета текста внутри NavigationView? Как установить фоновое изображение кнопки с эффектом пульсации в android WebView в ScrollView: «Просмотр слишком большой, чтобы вписаться в кеш-файл» – как переделать макет? Как я могу позволить пользователям получить доступ к внутреннему каталогу хранения моего приложения? При нажатии кнопки DatePicker на моем устройстве (с личным приложением) Разница между getView & getDropDownView в SpinnerAdapter Объяснение Аффинации задачи Android Анимация макетов с использованием атрибута «animateLayoutChanges» в XML Mockito с Robolectric: «ClassCastException произошло при создании прокси» Как создать пользовательскую кнопку в Android с помощью стилей XML Eclipse: проверьте, что aapt присутствует в «.. \ sdk \ build-tools \ 23.0.0_rc1 \ aapt.exe" Как я могу запустить Activity из класса non-Activity? Необязательный метод в интерфейсе Java Как запустить Runnable thread в Android?

ScrollView Inside ScrollView

Я знаю, что люди из Google попросили нас не вводить прокручиваемое представление в другое прокручиваемое представление, но есть ли какое-либо официальное заявление от них, направляющее нас не делать этого?

Solutions Collecting From Web of "ScrollView Inside ScrollView"

Это достаточно близко?

Вы никогда не должны использовать HorizontalScrollView с ListView, поскольку ListView позаботится о своей собственной прокрутке. Самое главное, что это приводит к поражению всех важных оптимизаций в ListView для работы с большими списками, поскольку оно эффективно заставляет ListView отображать весь список элементов для заполнения бесконечного контейнера, поставляемого HorizontalScrollView.

http://developer.android.com/reference/android/widget/HorizontalScrollView.html

ОБНОВИТЬ:

Поскольку вы можете использовать двумерный прокрутки, вы можете подумать об использовании этого: интернет-архив blog.gorges.us/2010/06/android-two-dimensional-scrollview/

Я не использовал это, но это может быть разумный подход.

Попробуй это

Примечание: здесь parentScrollView означает Outer ScrollView, а childScrollView – Innner ScrollView

 parentScrollView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { Log.v(TAG, "PARENT TOUCH"); findViewById(R.id.child_scroll).getParent() .requestDisallowInterceptTouchEvent(false); return false; } }); childScrollView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { Log.v(TAG, "CHILD TOUCH"); // Disallow the touch request for parent scroll on touch of child view v.getParent().requestDisallowInterceptTouchEvent(true); return false; } }); 

Ответ Атула Бхардваджа выше – правильный способ сделать это. Но в случае, если кто-то должен применить его к ScrollView, где у вас меньше контроля над родителем, я думаю, что это достаточно гибко и просто так, как он должен работать:

 private void makeMyScrollSmart() { myScroll.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View __v, MotionEvent __event) { if (__event.getAction() == MotionEvent.ACTION_DOWN) { // Disallow the touch request for parent scroll on touch of child view requestDisallowParentInterceptTouchEvent(__v, true); } else if (__event.getAction() == MotionEvent.ACTION_UP || __event.getAction() == MotionEvent.ACTION_CANCEL) { // Re-allows parent events requestDisallowParentInterceptTouchEvent(__v, false); } return false; } }); } private void requestDisallowParentInterceptTouchEvent(View __v, Boolean __disallowIntercept) { while (__v.getParent() != null && __v.getParent() instanceof View) { if (__v.getParent() instanceof ScrollView) { __v.getParent().requestDisallowInterceptTouchEvent(__disallowIntercept); } __v = (View) __v.getParent(); } } 

Что делает эта функция, так это добавление сенсорного прослушивателя в myScroll который отключает сенсорный перехват родителя, когда при myScroll , а затем возвращается обратно, когда касание фактически заканчивается. Вам не нужна ссылка на родительский ScrollView и он не должен быть непосредственным родителем … он будет перемещать список отображения, пока не найдет его.

Лучшее из обоих миров, на мой взгляд.

 childScrollView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { int action = event.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: // Disallow ScrollView to intercept touch events. v.getParent().requestDisallowInterceptTouchEvent(true); break; case MotionEvent.ACTION_UP: // Allow ScrollView to intercept touch events. v.getParent().requestDisallowInterceptTouchEvent(false); break; } return false; } }); 

V.getParent () = родительский scrollView.

Вот возможное решение. Когда достигнут конец дочернего элемента ScrollView, он передает элемент управления родительскому ScrollView для прокрутки. Он работает с ScrollView и ListView внутри ScrollView.

Шаг 1 – установите родительский OnTouchListener

 parentScroll.setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { v.getParent().requestDisallowInterceptTouchEvent(false); return false; } }); 

Шаг 2 – установите дочерний OnTouchListener (ScrollView или ListView)

 aChildScrollView.setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { v.getParent().requestDisallowInterceptTouchEvent(shouldRequestDisallowIntercept((ViewGroup) v, event)); return false; } }); aListView.setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { v.getParent().requestDisallowInterceptTouchEvent(shouldRequestDisallowIntercept((ViewGroup) v, event)); return false; } }); 

Шаг 3 – вот требуемые магические методы для правильной функциональности

 protected boolean shouldRequestDisallowIntercept(ViewGroup scrollView, MotionEvent event) { boolean disallowIntercept = true; float yOffset = getYOffset(event); if (scrollView instanceof ListView) { ListView listView = (ListView) scrollView; if (yOffset < 0 && listView.getFirstVisiblePosition() == 0 && listView.getChildAt(0).getTop() >= 0) { disallowIntercept = false; } else if (yOffset > 0 && listView.getLastVisiblePosition() == listView.getAdapter().getCount() - 1 && listView.getChildAt(listView.getChildCount() - 1).getBottom() <= listView.getHeight()) { disallowIntercept = false; } } else { float scrollY = scrollView.getScrollY(); disallowIntercept = !((scrollY == 0 && yOffset < 0) || (scrollView.getHeight() + scrollY == scrollView.getChildAt(0).getHeight() && yOffset >= 0)); } return disallowIntercept; } protected float getYOffset(MotionEvent ev) { final int historySize = ev.getHistorySize(); final int pointerCount = ev.getPointerCount(); if (historySize > 0 && pointerCount > 0) { float lastYOffset = ev.getHistoricalY(pointerCount - 1, historySize - 1); float currentYOffset = ev.getY(pointerCount - 1); float dY = lastYOffset - currentYOffset; return dY; } return 0; } 

[…] есть ли какое-либо официальное заявление от них, направляющее нас не делать этого?

Я думаю, что, хотя я не могу найти его в своих заметках. Я знаю, что нашел такое заявление при попытке просмотреть прокрутку в активности списка. Я думаю, что на самом деле существует логический фокус «ошибка» в том, как система Android UI работает с вложенными прокрутками, которые, вероятно, должны быть лучше обнаружены и переданы разработчику. Но мой совет …

В конце концов, в любом случае, лучше всего рассмотреть один прокручиваемый вид для пользователя. Это похоже на наличие полос прокрутки в полосах прокрутки на странице HTML; Это может быть законным, но это страшный пользовательский опыт.

На самом деле, есть официальное заявление об этом, на довольно старом видео под названием « мир ListView ». Говорят, что нельзя прокручивать прокручиваемое изображение внутри другого (когда оба находятся в одном направлении).

Однако теперь у нас есть новое представление, которое позволяет обоим представлениям прокручиваться одновременно, возможно, чтобы показать эффект:

https://developer.android.com/reference/android/support/v4/widget/NestedScrollView.html

Я не нашел никакого примера для этого, поэтому то, что я написал, – это просто догадка о том, что он делает и для чего он используется.

Я нашел очень хорошее решение. Используйте этот код.

  parentScrollView.setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { Utils.showLog("PARENT TOUCH"); findViewById(R.id.activity_mesh_child_scrollView).getParent().requestDisallowInterceptTouchEvent(false); return false; } }); childScrollView.setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { Utils.showLog("CHILD TOUCH"); // Disallow the touch request for parent scroll on touch of child view v.getParent().requestDisallowInterceptTouchEvent(true); return false; } }); 

Это, безусловно, будет работать. Пожалуйста, дайте мне знать, если не работаете.

Вы можете поместить ScrollView внутри другого ScrollView. Просто увеличьте дочерний ScrollView, чтобы переопределить метод onTouchEvent. Вот так

 import android.content.Context; import android.util.AttributeSet; import android.view.MotionEvent; public class ChildScrollView extends android.widget.ScrollView { private int parent_id; public ChildScrollView(Context context) { super(context); } public ChildScrollView(Context context, AttributeSet attrs) { super(context, attrs); } public ChildScrollView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public boolean onTouchEvent(MotionEvent event){ requestDisallowInterceptTouchEvent(true); return super.onTouchEvent(event); } } 

Здесь я создал образец проекта, связанный с ScrollView внутри ScrollView. Один вид прокручивается в обоих направлениях. Проверьте это: –

MainActivity.java –

 package com.example.dev_task_193_scrollview; import com.example.dev_task_196_scrollview.R; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.view.MotionEvent; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.HorizontalScrollView; import android.widget.ImageView; import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.ScrollView; import android.widget.Toast; public class MainActivity extends Activity implements View.OnClickListener{ ImageView imageView1,imageView2,imageView3,IVimage1,IVimage2,IVimage3,IVimage4,IVimage5,IVimage6; ListView listView1,listView2; HorizontalScrollView horizontalScrollView1,horizontalScrollView2; ScrollView parentScrollView, scrollView1; RelativeLayout relativeLayout1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); String[] values = new String[] { "Android", "iPhone", "WindowsMobile", "Blackberry", "WebOS", "Ubuntu", "Windows7", "Max OS X", "Linux", "OS/2", "Ubuntu", "Windows7", "Max OS X", "Linux", "OS/2", "Ubuntu", "Windows7", "Max OS X", "Linux", "OS/2", "Android", "iPhone", "WindowsMobileWindowsMobileWindowsMobileWindowsMobile" }; relativeLayout1 = (RelativeLayout) findViewById(R.id.relativeLayout1); imageView1 = (ImageView) findViewById(R.id.imageView1); imageView1.setBackgroundResource(R.drawable.info); imageView2 = (ImageView) findViewById(R.id.imageView2); imageView2.setBackgroundResource(R.drawable.info); imageView3 = (ImageView) findViewById(R.id.imageView3); imageView3.setBackgroundResource(R.drawable.info); listView1 = (ListView) findViewById(R.id.listView1); ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.list_item, values); listView1.setAdapter(adapter); listView2 = (ListView) findViewById(R.id.listView2); ArrayAdapter<String> adapter1 = new ArrayAdapter<String>(this, R.layout.list_item, values); listView2.setAdapter(adapter1); parentScrollView = (ScrollView) findViewById(R.id.parentScrollView); scrollView1 = (ScrollView) findViewById(R.id.scrollView1); horizontalScrollView1 = (HorizontalScrollView) findViewById(R.id.horizontalScrollView1); horizontalScrollView2 = (HorizontalScrollView) findViewById(R.id.horizontalScrollView2); IVimage1 = (ImageView) findViewById(R.id.IVimage1); IVimage2 = (ImageView) findViewById(R.id.IVimage2); IVimage3 = (ImageView) findViewById(R.id.IVimage3); IVimage4 = (ImageView) findViewById(R.id.IVimage4); IVimage5 = (ImageView) findViewById(R.id.IVimage5); IVimage6 = (ImageView) findViewById(R.id.IVimage6); scrollView1.setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { // Disallow the touch request for parent scroll on touch of child view parentScrollView.requestDisallowInterceptTouchEvent(true); return false; } }); horizontalScrollView1.setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { // Disallow the touch request for parent scroll on touch of child view parentScrollView.requestDisallowInterceptTouchEvent(true); return false; } }); listView1.setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { // Disallow the touch request for parent scroll on touch of child view parentScrollView.requestDisallowInterceptTouchEvent(true); return false; } }); listView1.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Toast.makeText(getApplicationContext(), "Clicked "+parent.getItemAtPosition(position).toString(), Toast.LENGTH_SHORT).show(); } }); listView2.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Toast.makeText(getApplicationContext(), "Clicked "+parent.getItemAtPosition(position).toString(), Toast.LENGTH_SHORT).show(); } }); listView2.setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { // Disallow the touch request for parent scroll on touch of child view parentScrollView.requestDisallowInterceptTouchEvent(true); return false; } }); horizontalScrollView2.setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { // Disallow the touch request for parent scroll on touch of child view parentScrollView.requestDisallowInterceptTouchEvent(true); return false; } }); /*imageView1.setOnClickListener(this); imageView2.setOnClickListener(this); imageView3.setOnClickListener(this);*/ IVimage1.setOnClickListener(this); IVimage2.setOnClickListener(this); IVimage3.setOnClickListener(this); IVimage4.setOnClickListener(this); IVimage5.setOnClickListener(this); IVimage6.setOnClickListener(this); imageView1.setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { // Disallow the touch request for parent scroll on touch of child view parentScrollView.requestDisallowInterceptTouchEvent(true); Toast.makeText(getApplicationContext(), "Clicked "+v.getTag(), Toast.LENGTH_SHORT).show(); return false; } }); imageView2.setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { // Disallow the touch request for parent scroll on touch of child view parentScrollView.requestDisallowInterceptTouchEvent(true); Toast.makeText(getApplicationContext(), "Clicked "+v.getTag(), Toast.LENGTH_SHORT).show(); return false; } }); imageView3.setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { // Disallow the touch request for parent scroll on touch of child view parentScrollView.requestDisallowInterceptTouchEvent(true); Toast.makeText(getApplicationContext(), "Clicked "+v.getTag(), Toast.LENGTH_SHORT).show(); return false; } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public void onClick(View v) { switch(v.getId()){ case R.id.imageView1: Toast.makeText(getApplicationContext(), "Clicked "+v.getTag(), Toast.LENGTH_SHORT).show(); break; case R.id.imageView2: Toast.makeText(getApplicationContext(), "Clicked "+v.getTag(), Toast.LENGTH_SHORT).show(); break; case R.id.imageView3: Toast.makeText(getApplicationContext(), "Clicked "+v.getTag(), Toast.LENGTH_SHORT).show(); break; case R.id.IVimage1: Toast.makeText(getApplicationContext(), "Clicked "+v.getTag(), Toast.LENGTH_SHORT).show(); break; case R.id.IVimage2: Toast.makeText(getApplicationContext(), "Clicked "+v.getTag(), Toast.LENGTH_SHORT).show(); break; case R.id.IVimage3: Toast.makeText(getApplicationContext(), "Clicked "+v.getTag(), Toast.LENGTH_SHORT).show(); break; case R.id.IVimage4: Toast.makeText(getApplicationContext(), "Clicked "+v.getTag(), Toast.LENGTH_SHORT).show(); break; case R.id.IVimage5: Toast.makeText(getApplicationContext(), "Clicked "+v.getTag(), Toast.LENGTH_SHORT).show(); break; case R.id.IVimage6: Toast.makeText(getApplicationContext(), "Clicked "+v.getTag(), Toast.LENGTH_SHORT).show(); break; } // TODO Auto-generated method stub } } 

Activity_main.xml –

 <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/parentScrollView" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_marginBottom="5dp" android:layout_marginLeft="5dp" android:layout_marginRight="5dp" android:layout_marginTop="5dp" android:background="@drawable/login_bg" > <RelativeLayout android:id="@+id/relativeLayout1" android:layout_width="match_parent" android:layout_height="wrap_content" > <ScrollView android:id="@+id/scrollView1" android:layout_width="fill_parent" android:layout_height="300dp" > <HorizontalScrollView android:id="@+id/horizontalScrollView1" android:layout_width="match_parent" android:layout_height="300dp" android:fillViewport="false" > <RelativeLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="5dp" android:background="@drawable/bg" > <ImageView android:id="@+id/imageView1" android:layout_width="300dp" android:layout_height="400dp" android:tag="imageView1" /> <ImageView android:id="@+id/imageView2" android:layout_width="300dp" android:layout_height="400dp" android:layout_toRightOf="@+id/imageView1" android:tag="imageView2" /> <ImageView android:id="@+id/imageView3" android:layout_width="300dp" android:layout_height="400dp" android:layout_toRightOf="@+id/imageView2" android:tag="imageView3" /> </RelativeLayout> </HorizontalScrollView> </ScrollView> <ListView android:id="@+id/listView1" android:layout_width="500dp" android:layout_height="400dp" android:layout_below="@+id/scrollView1" android:layout_centerHorizontal="true" android:layout_marginTop="5dp" android:background="@drawable/ic_launcherwrweq" > </ListView> <HorizontalScrollView android:id="@+id/horizontalScrollView2" android:layout_width="300dp" android:layout_height="wrap_content" android:layout_below="@+id/listView1" android:layout_centerHorizontal="true" android:layout_gravity="center" android:layout_marginTop="5dp" android:background="@drawable/claim_detail_header_bg" android:fillViewport="true" > <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" > <ImageView android:id="@+id/IVimage1" android:layout_width="125dp" android:layout_height="125dp" android:padding="15dp" android:src="@drawable/a" android:tag="a" > </ImageView> <ImageView android:id="@+id/IVimage2" android:layout_width="125dp" android:layout_height="125dp" android:padding="15dp" android:src="@drawable/b" android:tag="b" > </ImageView> <ImageView android:id="@+id/IVimage3" android:layout_width="125dp" android:layout_height="125dp" android:padding="15dp" android:src="@drawable/c" android:tag="c" > </ImageView> <ImageView android:id="@+id/IVimage4" android:layout_width="125dp" android:layout_height="125dp" android:padding="15dp" android:src="@drawable/g" android:tag="g" > </ImageView> <ImageView android:id="@+id/IVimage5" android:layout_width="125dp" android:layout_height="125dp" android:padding="15dp" android:src="@drawable/e" android:tag="e" > </ImageView> <ImageView android:id="@+id/IVimage6" android:layout_width="125dp" android:layout_height="125dp" android:padding="15dp" android:src="@drawable/f" android:tag="f" > </ImageView> </LinearLayout> </HorizontalScrollView> <ListView android:id="@+id/listView2" android:layout_width="500dp" android:layout_height="400dp" android:layout_below="@+id/horizontalScrollView2" android:layout_centerHorizontal="true" android:layout_marginTop="5dp" android:background="@drawable/ic_launcherwrweq" > </ListView> </RelativeLayout> </ScrollView> 

List_item.xml (для ListView) –

 <?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/text1" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_vertical" android:textSize="25sp" android:maxLines="1" android:singleLine="true" /> 

В библиотеке поддержки Android v4 есть класс под названием NestedScrollView.

Попробовать просмотр вложенных прокруток: http://ivankocijan.xyz/android-nestedscrollview/

Если кто-то ищет ответ на этот вопрос, у меня была немного другая реализация. Я расширил класс ScrollView и реализовал onTouchListener в дочернем элементе и задал его self в конструкторе.

В обратном вызове onTouch, если объект события движения пришел со значением для счетчика указателей как 2, я вернул true, иначе false. Таким образом, если бы два пальца двигались на экране, это считало бы его щепоткой для увеличения, в противном случае это считалось бы нормальным прокруткой. Я не просил отключить родительский сенсор и т. Д.

 @Override public boolean onTouch(View view, MotionEvent motionEvent) { if(motionEvent.getPointerCount() == 2){ mCallbacks.onPinchZoomAction(motionEvent); return true; } return false; } 

Это не только то, что Google говорит о своей плохой практике, она просто не имеет большого смысла. Предположим, у вас есть два вертикальных прокручиваемых вида, вложенных друг в друга. Когда вы перемещаете пальцем по прокручиваемым видам, какой из них вы хотите переместить, внутренний или внешний?

Вы должны переосмыслить свой пользовательский интерфейс, чтобы он не требовал этого, есть множество способов сделать отличный интерфейс и по-прежнему поддерживать его на самом деле просто.