dentro - listview scroll android
¿Cómo puedo poner un ListView en un ScrollView sin colapsar? (27)
He buscado soluciones para este problema, y la única respuesta que puedo encontrar parece ser " no poner un ListView en un ScrollView ". Aún no he visto ninguna explicación real de por qué . La única razón por la que parece que puedo encontrar es que Google no cree que debas querer hacer eso. Bueno lo hago, así lo hice.
Entonces, la pregunta es, ¿cómo se puede colocar un ListView en un ScrollView sin colapsar a su altura mínima?
Aquí está mi solución. Soy bastante nuevo en la plataforma Android, y estoy seguro de que esto es un poco caprichoso, especialmente en la parte sobre la llamada a .measure directamente, y la configuración de la propiedad LayoutParams.height
directamente, pero funciona.
Todo lo que tiene que hacer es llamar a Utility.setListViewHeightBasedOnChildren(yourListView)
y su tamaño cambiará para adaptarse exactamente a la altura de sus elementos.
public class Utility {
public static void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) {
// pre-condition
return;
}
int totalHeight = listView.getPaddingTop() + listView.getPaddingBottom();
for (int i = 0; i < listAdapter.getCount(); i++) {
View listItem = listAdapter.getView(i, null, listView);
if (listItem instanceof ViewGroup) {
listItem.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
}
listItem.measure(0, 0);
totalHeight += listItem.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
}
}
Aquí hay una pequeña modificación en la answer que necesito para que funcione correctamente:
public static void setListViewHeightBasedOnChildren(ListView listView)
{
ListAdapter listAdapter = listView.getAdapter();
if(listAdapter == null) return;
if(listAdapter.getCount() <= 1) return;
int desiredWidth = MeasureSpec.makeMeasureSpec(listView.getWidth(), MeasureSpec.AT_MOST);
int totalHeight = 0;
View view = null;
for(int i = 0; i < listAdapter.getCount(); i++)
{
view = listAdapter.getView(i, view, listView);
view.measure(desiredWidth, MeasureSpec.UNSPECIFIED);
totalHeight += view.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
listView.requestLayout();
}
Aunque los métodos sugeridos de setListViewHeightBasedOnChildren () funcionan en la mayoría de los casos, en algunos casos, especialmente con muchos elementos, noté que no se muestran los últimos elementos. Así que decidí imitar una versión simple del comportamiento de ListView para reutilizar cualquier código del Adaptador, aquí está la alternativa de ListView:
import android.content.Context;
import android.database.DataSetObserver;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.ListAdapter;
public class StretchedListView extends LinearLayout {
private final DataSetObserver dataSetObserver;
private ListAdapter adapter;
private OnItemClickListener onItemClickListener;
public StretchedListView(Context context, AttributeSet attrs) {
super(context, attrs);
setOrientation(LinearLayout.VERTICAL);
this.dataSetObserver = new DataSetObserver() {
@Override
public void onChanged() {
syncDataFromAdapter();
super.onChanged();
}
@Override
public void onInvalidated() {
syncDataFromAdapter();
super.onInvalidated();
}
};
}
public void setAdapter(ListAdapter adapter) {
ensureDataSetObserverIsUnregistered();
this.adapter = adapter;
if (this.adapter != null) {
this.adapter.registerDataSetObserver(dataSetObserver);
}
syncDataFromAdapter();
}
protected void ensureDataSetObserverIsUnregistered() {
if (this.adapter != null) {
this.adapter.unregisterDataSetObserver(dataSetObserver);
}
}
public Object getItemAtPosition(int position) {
return adapter != null ? adapter.getItem(position) : null;
}
public void setSelection(int i) {
getChildAt(i).setSelected(true);
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
public ListAdapter getAdapter() {
return adapter;
}
public int getCount() {
return adapter != null ? adapter.getCount() : 0;
}
private void syncDataFromAdapter() {
removeAllViews();
if (adapter != null) {
int count = adapter.getCount();
for (int i = 0; i < count; i++) {
View view = adapter.getView(i, null, this);
boolean enabled = adapter.isEnabled(i);
if (enabled) {
final int position = i;
final long id = adapter.getItemId(position);
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (onItemClickListener != null) {
onItemClickListener.onItemClick(null, v, position, id);
}
}
});
}
addView(view);
}
}
}
}
Convertí la Utility
@ DougW en C # (usada en Xamarin). Lo siguiente funciona bien para los artículos de altura fija en la lista, y estará bien en su mayoría, o al menos un buen comienzo, si solo algunos de los artículos son un poco más grandes que el artículo estándar.
// You will need to put this Utility class into a code file including various
// libraries, I found that I needed at least System, Linq, Android.Views and
// Android.Widget.
using System;
using System.Linq;
using Android.Views;
using Android.Widget;
namespace UtilityNamespace // whatever you like, obviously!
{
public class Utility
{
public static void setListViewHeightBasedOnChildren (ListView listView)
{
if (listView.Adapter == null) {
// pre-condition
return;
}
int totalHeight = listView.PaddingTop + listView.PaddingBottom;
for (int i = 0; i < listView.Count; i++) {
View listItem = listView.Adapter.GetView (i, null, listView);
if (listItem.GetType () == typeof(ViewGroup)) {
listItem.LayoutParameters = new LinearLayout.LayoutParams (ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.WrapContent);
}
listItem.Measure (0, 0);
totalHeight += listItem.MeasuredHeight;
}
listView.LayoutParameters.Height = totalHeight + (listView.DividerHeight * (listView.Count - 1));
}
}
}
Gracias @DougW, esto me sacó de un lugar difícil cuando tuve que trabajar con OtherPeople''sCode. :-)
Esta es una combinación de las respuestas de DougW, Good Guy Greg y Paul. Descubrí que todo era necesario cuando intentaba usar esto con un adaptador de vista de lista personalizado y elementos de lista no estándar; de lo contrario, la vista de lista bloqueaba la aplicación (también se bloqueó con la respuesta de Nex):
public void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) {
return;
}
int totalHeight = listView.getPaddingTop() + listView.getPaddingBottom();
for (int i = 0; i < listAdapter.getCount(); i++) {
View listItem = listAdapter.getView(i, null, listView);
if (listItem instanceof ViewGroup)
listItem.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
listItem.measure(0, 0);
totalHeight += listItem.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
}
Gracias al código de Vinay, aquí está mi código para cuando no puede tener una vista de lista dentro de una vista de desplazamiento, pero necesita algo así.
LayoutInflater li = LayoutInflater.from(this);
RelativeLayout parent = (RelativeLayout) this.findViewById(R.id.relativeLayoutCliente);
int recent = 0;
for(Contatto contatto : contatti)
{
View inflated_layout = li.inflate(R.layout.header_listview_contatti, layout, false);
inflated_layout.setId(contatto.getId());
((TextView)inflated_layout.findViewById(R.id.textViewDescrizione)).setText(contatto.getDescrizione());
((TextView)inflated_layout.findViewById(R.id.textViewIndirizzo)).setText(contatto.getIndirizzo());
((TextView)inflated_layout.findViewById(R.id.textViewTelefono)).setText(contatto.getTelefono());
((TextView)inflated_layout.findViewById(R.id.textViewMobile)).setText(contatto.getMobile());
((TextView)inflated_layout.findViewById(R.id.textViewFax)).setText(contatto.getFax());
((TextView)inflated_layout.findViewById(R.id.textViewEmail)).setText(contatto.getEmail());
RelativeLayout.LayoutParams relativeParams = new RelativeLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
if (recent == 0)
{
relativeParams.addRule(RelativeLayout.BELOW, R.id.headerListViewContatti);
}
else
{
relativeParams.addRule(RelativeLayout.BELOW, recent);
}
recent = inflated_layout.getId();
inflated_layout.setLayoutParams(relativeParams);
//inflated_layout.setLayoutParams( new RelativeLayout.LayoutParams(source));
parent.addView(inflated_layout);
}
El relativeLayout permanece dentro de un ScrollView para que todo se pueda desplazar :)
Hay muchas situaciones en las que tiene mucho sentido tener ListView en un ScrollView.
Aquí está el código basado en la sugerencia de DougW ... funciona en un fragmento, requiere menos memoria.
public static void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) {
return;
}
int desiredWidth = MeasureSpec.makeMeasureSpec(listView.getWidth(), MeasureSpec.AT_MOST);
int totalHeight = 0;
View view = null;
for (int i = 0; i < listAdapter.getCount(); i++) {
view = listAdapter.getView(i, view, listView);
if (i == 0) {
view.setLayoutParams(new ViewGroup.LayoutParams(desiredWidth, LayoutParams.WRAP_CONTENT));
}
view.measure(desiredWidth, MeasureSpec.UNSPECIFIED);
totalHeight += view.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
listView.requestLayout();
}
llame a setListViewHeightBasedOnChildren (vista de lista) en cada vista de lista incrustada.
Hay dos problemas al usar un ListView dentro de un ScrollView.
1- ListView debe expandirse completamente a su altura infantil. este ListView resuelve esto:
public class ListViewExpanded extends ListView
{
public ListViewExpanded(Context context, AttributeSet attrs)
{
super(context, attrs);
setDividerHeight(0);
}
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST));
}
}
La altura del divisor debe ser 0, use el relleno en filas en su lugar.
2- El ListView consume eventos táctiles, por lo que ScrollView no se puede desplazar como de costumbre. Este ScrollView resuelve este problema:
public class ScrollViewInterceptor extends ScrollView
{
float startY;
public ScrollViewInterceptor(Context context, AttributeSet attrs)
{
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent e)
{
onTouchEvent(e);
if (e.getAction() == MotionEvent.ACTION_DOWN) startY = e.getY();
return (e.getAction() == MotionEvent.ACTION_MOVE) && (Math.abs(startY - e.getY()) > 50);
}
}
¡Esta es la mejor manera que encontré para hacer el truco!
Hay un ajuste incorporado para ello. En el ScrollView:
android:fillViewport="true"
En java
mScrollView.setFillViewport(true);
Romain Guy lo explica en profundidad aquí: http://www.curious-creature.org/2010/08/15/scrollviews-handy-trick/
Instados de colocar ListView
dentro de un ScrollView
, podemos usar ListView
como un ScrollView
. Las cosas que tienen que estar en ListView
se pueden poner dentro de ListView
. Se pueden colocar otros diseños en la parte superior e inferior de ListView
agregando diseños al encabezado y al pie de página de ListView
. Así que todo el ListView
le dará una experiencia de desplazamiento.
ListView en realidad ya es capaz de medirse a sí mismo para ser lo suficientemente alto como para mostrar todos los elementos, pero no hace esto cuando simplemente especifica wrap_content (MeasureSpec.UNSPECIFIED). Hará esto cuando se le dé una altura con MeasureSpec.AT_MOST. Con este conocimiento, puede crear una subclase muy simple para resolver este problema que funciona mucho mejor que cualquiera de las soluciones publicadas anteriormente. Aún debe usar wrap_content con esta subclase.
public class ListViewForEmbeddingInScrollView extends ListView {
public ListViewForEmbeddingInScrollView(Context context) {
super(context);
}
public ListViewForEmbeddingInScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ListViewForEmbeddingInScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 4, MeasureSpec.AT_MOST));
}
}
Manipular el heightMeasureSpec para que sea AT_MOST con un tamaño muy grande (Integer.MAX_VALUE >> 4) hace que el ListView mida todos sus hijos hasta la altura dada (muy grande) y establezca su altura en consecuencia.
Esto funciona mejor que las otras soluciones por varias razones:
- Mide todo correctamente (relleno, separadores).
- Mide el ListView durante el pase de medida.
- Debido al # 2, maneja los cambios en el ancho o el número de elementos correctamente sin ningún código adicional
En el lado negativo, podría argumentar que hacer esto es confiar en un comportamiento no documentado en el SDK que podría cambiar. Por otro lado, podría argumentar que así es como wrap_content debería funcionar realmente con ListView y que el comportamiento de wrap_content actual está roto.
Si le preocupa que el comportamiento pueda cambiar en el futuro, simplemente copie la función onMeasure y las funciones relacionadas fuera de ListView.java y en su propia subclase, luego haga que la ruta AT_MOST a través de onMeasure también se ejecute para UNSPECIFIED.
Por cierto, creo que este es un enfoque perfectamente válido cuando se trabaja con un pequeño número de elementos de la lista. Puede ser ineficiente en comparación con LinearLayout, pero cuando el número de elementos es pequeño, usar LinearLayout es una optimización innecesaria y, por lo tanto, una complejidad innecesaria.
No debe poner un ListView en un ScrollView porque un ListView ya es un ScrollView. Entonces eso sería como poner un ScrollView en un ScrollView.
¿Qué está tratando de lograr?
No podríamos usar dos desplazamientos simultáneos. Tendremos la longitud total de ListView y expandir listview con la altura total. Luego podremos agregar ListView en ScrollView directamente o usando LinearLayout porque ScrollView tiene directamente un hijo. copie el método setListViewHeightBasedOnChildren (lv) en su código y amplíe la vista de lista para luego usar la vista de lista dentro de scrollview. / layout xml file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#1D1D1D"
android:orientation="vertical"
android:scrollbars="none" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#1D1D1D"
android:orientation="vertical" >
<TextView
android:layout_width="fill_parent"
android:layout_height="40dip"
android:background="#333"
android:gravity="center_vertical"
android:paddingLeft="8dip"
android:text="First ListView"
android:textColor="#C7C7C7"
android:textSize="20sp" />
<ListView
android:id="@+id/first_listview"
android:layout_width="260dp"
android:layout_height="wrap_content"
android:divider="#00000000"
android:listSelector="#ff0000"
android:scrollbars="none" />
<TextView
android:layout_width="fill_parent"
android:layout_height="40dip"
android:background="#333"
android:gravity="center_vertical"
android:paddingLeft="8dip"
android:text="Second ListView"
android:textColor="#C7C7C7"
android:textSize="20sp" />
<ListView
android:id="@+id/secondList"
android:layout_width="260dp"
android:layout_height="wrap_content"
android:divider="#00000000"
android:listSelector="#ffcc00"
android:scrollbars="none" />
</LinearLayout>
</ScrollView>
</LinearLayout>
Método onCreate en la clase de actividad:
import java.util.ArrayList;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListAdapter;
import android.widget.ListView;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.listview_inside_scrollview);
ListView list_first=(ListView) findViewById(R.id.first_listview);
ListView list_second=(ListView) findViewById(R.id.secondList);
ArrayList<String> list=new ArrayList<String>();
for(int x=0;x<30;x++)
{
list.add("Item "+x);
}
ArrayAdapter<String> adapter=new ArrayAdapter<String>(getApplicationContext(),
android.R.layout.simple_list_item_1,list);
list_first.setAdapter(adapter);
setListViewHeightBasedOnChildren(list_first);
list_second.setAdapter(adapter);
setListViewHeightBasedOnChildren(list_second);
}
public static void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) {
// pre-condition
return;
}
int totalHeight = 0;
for (int i = 0; i < listAdapter.getCount(); i++) {
View listItem = listAdapter.getView(i, null, listView);
listItem.measure(0, 0);
totalHeight += listItem.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight
+ (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
}
Usar un ListView
para que no se desplace es extremadamente costoso y va en contra de todo el propósito de ListView
. NO debes hacer esto. Solo usa un LinearLayout
en LinearLayout
lugar.
Usted crea ListView personalizado que no es desplazable
public class NonScrollListView extends ListView {
public NonScrollListView(Context context) {
super(context);
}
public NonScrollListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NonScrollListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int heightMeasureSpec_custom = MeasureSpec.makeMeasureSpec(
Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, heightMeasureSpec_custom);
ViewGroup.LayoutParams params = getLayoutParams();
params.height = getMeasuredHeight();
}
}
En su archivo de recursos de diseño
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<!-- com.Example Changed with your Package name -->
<com.Example.NonScrollListView
android:id="@+id/lv_nonscroll_list"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</com.Example.NonScrollListView>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/lv_nonscroll_list" >
<!-- Your another layout in scroll view -->
</RelativeLayout>
</RelativeLayout>
En el archivo de Java
Cree un objeto de su customListview en lugar de ListView como: NonScrollListView non_scroll_list = (NonScrollListView) findViewById (R.id.lv_nonscroll_list);
hey tuve un problema similar Quería mostrar una vista de lista que no se desplazaba y descubrí que la manipulación de los parámetros funcionaba pero era ineficiente y se comportaría de manera diferente en diferentes dispositivos. Como resultado, esta es una parte de mi código de programación que realmente lo hace de manera muy eficiente. .
db = new dbhelper(this);
cursor = db.dbCursor();
int count = cursor.getCount();
if (count > 0)
{
LinearLayout linearLayout = (LinearLayout) findViewById(R.id.layoutId);
startManagingCursor(YOUR_CURSOR);
YOUR_ADAPTER(**or SimpleCursorAdapter **) adapter = new YOUR_ADAPTER(this,
R.layout.itemLayout, cursor, arrayOrWhatever, R.id.textViewId,
this.getApplication());
int i;
for (i = 0; i < count; i++){
View listItem = adapter.getView(i,null,null);
linearLayout.addView(listItem);
}
}
Nota: si utiliza esto, notifyDataSetChanged();
no funcionará según lo previsto ya que las vistas no se volverán a dibujar. Haga esto si necesita un trabajo alrededor
adapter.registerDataSetObserver(new DataSetObserver() {
@Override
public void onChanged() {
super.onChanged();
removeAndRedrawViews();
}
});
intente esto, esto funciona para mí, olvidé dónde lo encontré, en algún lugar de la pila de desbordamiento, no estoy aquí para explicarle por qué no funciona, pero esta es la respuesta :).
final ListView AturIsiPulsaDataIsiPulsa = (ListView) findViewById(R.id.listAturIsiPulsaDataIsiPulsa);
AturIsiPulsaDataIsiPulsa.setOnTouchListener(new ListView.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;
}
// Handle ListView touch events.
v.onTouchEvent(event);
return true;
}
});
AturIsiPulsaDataIsiPulsa.setClickable(true);
AturIsiPulsaDataIsiPulsa.setAdapter(AturIsiPulsaDataIsiPulsaAdapter);
EDIT!, Finalmente descubrí donde obtuve el código. aquí ! : ListView dentro de ScrollView no se desplaza en Android
This biblioteca es la solución más fácil y rápida al problema.
Esto definitivamente funcionará ............
<com.tmd.utils.VerticalScrollview > </com.tmd.utils.VerticalScrollview >
reemplazar su <ScrollView ></ScrollView>
en el archivo XML de diseño con este Custom ScrollView
como <com.tmd.utils.VerticalScrollview > </com.tmd.utils.VerticalScrollview >
package com.tmd.utils;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.ScrollView;
public class VerticalScrollview extends ScrollView{
public VerticalScrollview(Context context) {
super(context);
}
public VerticalScrollview(Context context, AttributeSet attrs) {
super(context, attrs);
}
public VerticalScrollview(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
switch (action)
{
case MotionEvent.ACTION_DOWN:
Log.i("VerticalScrollview", "onInterceptTouchEvent: DOWN super false" );
super.onTouchEvent(ev);
break;
case MotionEvent.ACTION_MOVE:
return false; // redirect MotionEvents to ourself
case MotionEvent.ACTION_CANCEL:
Log.i("VerticalScrollview", "onInterceptTouchEvent: CANCEL super false" );
super.onTouchEvent(ev);
break;
case MotionEvent.ACTION_UP:
Log.i("VerticalScrollview", "onInterceptTouchEvent: UP super false" );
return false;
default: Log.i("VerticalScrollview", "onInterceptTouchEvent: " + action ); break;
}
return false;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
super.onTouchEvent(ev);
Log.i("VerticalScrollview", "onTouchEvent. action: " + ev.getAction() );
return true;
}
}
Esto es lo único que me funcionó:
en Lollipop en adelante puedes usar
yourtListView.setNestedScrollingEnabled(true);
Esto habilita o inhabilita el desplazamiento anidado para esta vista si necesita compatibilidad con versiones anteriores del sistema operativo, tendrá que usar RecyclerView.
Todo este problema simplemente desaparecería si LinearLayout tuviera un método setAdapter, porque entonces cuando le dijera a alguien que lo usara, la alternativa sería trivial.
Si realmente desea un ListView de desplazamiento dentro de otra vista de desplazamiento, esto no ayudará, pero de lo contrario, por lo menos le dará una idea.
Debe crear un adaptador personalizado para combinar todo el contenido que desea desplazar y configurar el adaptador de ListView para eso.
No tengo código de ejemplo a mano, pero si quieres algo así.
<ListView/>
(other content)
<ListView/>
Entonces necesitas crear un adaptador que represente todo ese contenido. Los ListView / Adapters son lo suficientemente inteligentes como para manejar diferentes tipos también, pero usted necesita escribir el adaptador usted mismo.
La API de la interfaz de usuario de Android no es tan madura como casi todo lo demás, por lo que no tiene las mismas sutilezas que otras plataformas. Además, cuando hagas algo en Android, debes estar en una mentalidad de Android (Unix) en la que esperas que para hacer cualquier cosa probablemente tengas que ensamblar la funcionalidad de partes más pequeñas y escribir un montón de tu propio código para hacerlo trabajo.
Una solución que utilizo es agregar todo el Contenido de ScrollView (lo que debería estar arriba y debajo de listView) como headerView y footerView en ListView.
Así funciona, también se vuelve a convertir el convertview como debería ser.
¡Todas estas respuestas están equivocadas! Si está intentando colocar una vista de lista en una vista de desplazamiento, debe replantearse su diseño. Está intentando colocar un ScrollView en un ScrollView. Interferir con la lista afectará el rendimiento de la lista. Fue diseñado para ser así por Android.
Si realmente desea que la lista esté en el mismo desplazamiento que los otros elementos, todo lo que tiene que hacer es agregar los otros elementos en la parte superior de la lista mediante una simple instrucción de cambio en su adaptador:
class MyAdapter extends ArrayAdapter{
public MyAdapter(Context context, int resource, List objects) {
super(context, resource, objects);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewItem viewType = getItem(position);
switch(viewType.type){
case TEXTVIEW:
convertView = layouteInflater.inflate(R.layout.textView1, parent, false);
break;
case LISTITEM:
convertView = layouteInflater.inflate(R.layout.listItem, parent, false);
break; }
return convertView;
}
}
El adaptador de lista puede manejar todo, ya que solo muestra lo que está visible.
Antes no era posible. Pero con el lanzamiento de nuevas bibliotecas Appcompat y bibliotecas de diseño, esto se puede lograr.
Solo tiene que usar NestedScrollView https://developer.android.com/reference/android/support/v4/widget/NestedScrollView.html
No sé si funcionará con Listview o no, pero funciona con RecyclerView.
Fragmento de código:
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.v4.widget.NestedScrollView>
Aquí está mi versión del código que calcula la altura total de la vista de lista. Esta funciona para mí:
public static void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null || listAdapter.getCount() < 2) {
// pre-condition
return;
}
int totalHeight = 0;
int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(BCTDApp.getDisplaySize().width, View.MeasureSpec.AT_MOST);
int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
for (int i = 0; i < listAdapter.getCount(); i++) {
View listItem = listAdapter.getView(i, null, listView);
if (listItem instanceof ViewGroup) listItem.setLayoutParams(lp);
listItem.measure(widthMeasureSpec, heightMeasureSpec);
totalHeight += listItem.getMeasuredHeight();
}
totalHeight += listView.getPaddingTop() + listView.getPaddingBottom();
totalHeight += (listView.getDividerHeight() * (listAdapter.getCount() - 1));
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight;
listView.setLayoutParams(params);
listView.requestLayout();
}
Cuando colocamos en su ListView
interior ScrollView
surgen dos problemas. Uno ScrollView
mide a sus hijos en el modo NO ESPECIFICADO, así que ListView
establece su propia altura para acomodar solo un elemento (no sé por qué), otro es ScrollView
intercepta el evento táctil y ListView
no se desplaza.
Pero nosotros podemos colocar ListView
en el interior ScrollView
con un poco de solución. Este post , por mi, explica la solución. Mediante esta solución también podemos conservar ListView
la función de reciclaje.
En lugar de colocar la vista de lista dentro de Scrollview, ponga el resto del contenido entre la vista de lista y la apertura de la vista de desplazamiento como una vista separada y establezca esa vista como el encabezado de la vista de lista. Así que finalmente terminarás solo con la vista de lista que se hará cargo de Scroll.