android - programacion - Pase el evento de movimiento al principal Vista de desplazamiento cuando Lista vista en la parte superior/inferior
manual android studio avanzado (3)
No debe poner ListView dentro de ScrollView, pero puede lograr su requerimiento usando ExpandibleHeightListView . Esto hará que Listview de altura completa dentro de ScrollView. No es necesario agregar TouchListener.
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<!-- your content -->
</RelativeLayout>
<my.widget.ExpandableHeightListView
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</ScrollView>
Y otra forma de lograr su requisito es RecyclerView con encabezado.
Tengo un ListView
en ScrollView
para mostrar comentarios y me gustaría hacer lo siguiente:
Cuando el usuario se desliza hacia abajo, primero ScrollView
debe ScrollView
hacia abajo, ya que la lista está en la parte inferior. Una vez que esté completamente inactivo, Listiew
debería comenzar a desplazarse.
De manera similar, cuando el usuario se desplaza hacia arriba, primero ListView
(¡orden invertida aquí!) Debe desplazarse hacia arriba, antes de que ScrollView
comience a desplazarse.
Hasta ahora he hecho lo siguiente:
listView.setOnTouchListener(new View.OnTouchListener() {
// Setting on Touch Listener for handling the touch inside ScrollView
@Override
public boolean onTouch(View v, MotionEvent event) {
// If going up but the list is already at up, return false indicating we did not consume it.
if(event.getAction() == MotionEvent.ACTION_UP) {
if (listView.getChildCount() == 0 && listView.getChildAt(0).getTop() == 0) {
Log.e("Listview", "At top!");
return false;
}
}
// Similar behaviour but when going down check if we are at the bottom.
if( event.getAction() == MotionEvent.ACTION_DOWN) {
if (listView.getLastVisiblePosition() == listView.getAdapter().getCount() - 1 &&
listView.getChildAt(listView.getChildCount() - 1).getBottom() <= listView.getHeight()) {
Log.e("Listview","At bottom!");
v.getParent().requestDisallowInterceptTouchEvent(false);
return false;
}
}
v.getParent().requestDisallowInterceptTouchEvent(true);
return false;
}
});
Los registros se disparan en el momento correcto, sin embargo, el ScrollView
no se moverá a pesar de que devuelvo falso.
También intenté agregar v.getParent().requestDisallowInterceptTouchEvent(false);
a las declaraciones, pero eso tampoco funcionó.
¿Cómo puedo hacer que funcione?
Prueba esto:
Primero encuentra si alcanzaste en scrollview Bottom. Registre onScrollChanged en su vista de desplazamiento
@Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { // Grab the last child placed in the ScrollView, we need it to determinate the bottom position. View view = (View) getChildAt(getChildCount()-1); // Calculate the scrolldiff int diff = (view.getBottom()-(getHeight()+getScrollY())); // if diff is zero, then the bottom has been reached if( diff == 0 ) { // notify that we have reached the bottom // Add code here to start scrolling the ListView Log.d(ScrollTest.LOG_TAG, "MyScrollView: Bottom has been reached" ); } super.onScrollChanged(l, t, oldl, oldt); }
Compruebe si llega a la parte superior de ListView. Compruebe si firstVisibleItem es 0: -
tableListView.setOnScrollListener(new OnScrollListener() { public void onScrollStateChanged(AbsListView view, int scrollState) { } public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { if (visibleItemCount == 0) // you have reached at top of lustView { java.lang.System.out.println("you have reached at top of lustView!"); } else { if ((firstVisibleItem + visibleItemCount) == totalItemCount) { // put your stuff here java.lang.System.out.println("end of the line reached!"); } } } });
Espero que esto funcione para ti. Si enfrenta algún problema, hágamelo saber.
Puede crear un ScrollView
personalizado y ListView
y anular
onInterceptTouchEvent(MotionEvent event)
Me gusta esto:
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
View view = (View) getChildAt(getChildCount()-1);
int diff = (view.getBottom()-(getHeight()+getScrollY()));
if( event.getAction() == MotionEvent.ACTION_DOWN) {
if (diff ==0) {
return false;
}
}
return super.onInterceptTouchEvent(event);
}
De esta forma, cada Abajo Toque en el ListView
mientras se encuentra en la parte inferior de ScrollView
irá a ListView
.
Esta es solo una implementación de boceto, pero creo que podría comenzar con esto haciendo lo mismo para detectar cuando se encuentra en la parte superior de ListView
Como nota, probaría una implementación más sencilla usando solo ListView
con el contenido actual de ScrollView
agregado como encabezado de ListView usando listView.addHeaderView(scrollViewContent)
. No sé si esto se adapta a tus necesidades.
EDITAR:
Detectando cuándo debería comenzar a desplazarse por ScrollView
. Mantener una referencia de ListView
en ScrollView
. Cuando el usuario se desplaza hacia arriba y el ListView
está en la parte superior, el ScrollView
consume el evento.
private void init(){
ViewConfiguration vc = ViewConfiguration.get(getContext());
mTouchSlop = vc.getScaledTouchSlop();
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
final int action = MotionEventCompat.getActionMasked(event);
switch (action) {
case MotionEvent.ACTION_DOWN:{
yPrec = event.getY();
}
case MotionEvent.ACTION_MOVE: {
final float dy = event.getY() - yPrec;
if (dy > mTouchSlop) {
// Start scrolling!
mIsScrolling = true;
}
break;
}
}
if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
mIsScrolling = false;
}
// Calculate the scrolldiff
View view = (View) getChildAt(getChildCount()-1);
int diff = (view.getBottom()-(getHeight()+getScrollY()));
if ((!mIsScrolling || !listViewReference.listIsAtTop()) && diff == 0) {
if (event.getAction() == MotionEvent.ACTION_MOVE) {
return false;
}
}
return super.onInterceptTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
final int action = MotionEventCompat.getActionMasked(ev);
if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
mIsScrolling = false;
}
return super.onTouchEvent(ev);
}
public void setListViewReference(MyListView listViewReference) {
this.listViewReference = listViewReference;
}
El método listIsAtTop en ListView se ve así:
public boolean listIsAtTop() {
if(getChildCount() == 0) return true;
return (getChildAt(0).getTop() == 0 && getFirstVisiblePosition() ==0);
}