¿Desliza UITableView a la pantalla, sigue deslizando?

Quiero una vista de tabla que comience fuera de la pantalla y que pueda desplazarse por la pantalla, llegar a la parte superior y seguir desplazándose. Hice un visual de la interacción deseada a continuación.

He intentado dos cosas y ninguno funciona exactamente como lo necesito.

Lo primero que hice fue poner la vista de tabla en una vista de desplazamiento y mover la vista de desplazamiento cuando se detecta el outlook en la vista de tabla. Esto bloquea los toques en la vista de tabla, e incluso si pudiera detectar cuándo la vista de tabla tocó la parte superior de la pantalla, no estoy seguro de cómo seguiría desplazándome.

Lo segundo que intenté fue establecer el tamaño de contenido de scrollview a la altura de la vista de tabla. Esto permite que la vista de tabla se desplace, pero solo parece que puedo recibir toques en el pequeño rectángulo inicial labeldo como "Lista de elementos 1". A medida que se desplaza la vista de tabla, no puedo agarrar el centro y desplazarlo más.

¿Cuál es la mejor manera de build esta interacción? Editar : un map rodea esta vista inferior a la izquierda, a la derecha y, en su mayoría, a la parte superior. Cuando se levanta la vista inferior, el map se puede ver a la izquierda y a la derecha.

1.)
1

2.)
2

3.) (y esto sigue desplazándose por tantos elementos como en la list).
3

Supongo que quieres algo como esto:

pequeña lista

o esto:

gran lista

Presenté mi vista de tabla sobre mi vista de map. Configuro contentInset y contentOffset la vista de contentOffset así:

 - (void)viewDidLoad { [super viewDidLoad]; self.tableView.rowHeight = 44; } - (void)viewDidLayoutSubviews { [super viewDidLayoutSubviews]; self.tableView.contentInset = (UIEdgeInsets){ .top = self.view.bounds.size.height - self.tableView.rowHeight }; self.tableView.contentOffset = CGPointMake(0, -self.tableView.contentInset.top); } 

Tenga en count que, aunque el alto de fila pnetworkingeterminado es 44, tableView.rowHeight devuelve -1 a less que lo establezca explícitamente. (Configurarlo a 44 en el guión gráfico no cambia esto).

Utilicé una subclass de UITableView en la que hice dos cosas:

  1. Establecí explícitamente self.backgroundColor = [UIColor clearColor] . Descubrí que configurar el color de background para borrar en el guión gráfico no funcionaba.

  2. pointInside:withEvent: ::

     - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { return point.y >= 0 && [super pointInside:point withEvent:event]; } 

Tenga en count que no le importa el contenido de la contentInset aquí. La vista de la tabla contentOffset.y (que es lo mismo que its bounds.origin.y ) se establece en un número negativo cuando su parte superior del contenido se expone. Se establece en 0 cuando la parte superior del elemento 0 se encuentra en el borde superior de la vista de la tabla, que no es el caso cuando el elemento se encuentra en el borde inferior de la pantalla.

Otra cosa que puede desear es evitar que la tabla se detenga a medias en la pantalla. Si el usuario arrastra el ítem 0 a la mitad de la pantalla, quiere que la tabla se desplace, por lo que el ítem 0 está completamente en la parte superior de la pantalla (si hay elementos suficientes) y si el usuario arrastra el ítem 0 a la mitad de la pantalla, Desea que la tabla se desplace para que se muestre el elemento 0.

Lo hice haciendo que mi controller de vista actúe como delegado de la vista de tabla e implementando este método de delegado, henetworkingado de UIScrollViewDelegate :

 - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset { CGFloat yMin = -self.tableView.contentInset.top; CGFloat yMax = MIN(0, self.tableView.contentSize.height - self.tableView.bounds.size.height); if (targetContentOffset->y < yMax) { if (velocity.y < 0) { targetContentOffset->y = yMin; } else { targetContentOffset->y = yMax; } } } 

Ese método se escribe cuidadosamente para que funcione en tablas demasiado cortas para llenar verticalmente la pantalla y para tablas que pueden llenar la pantalla verticalmente.

Cargué mi proyecto de testing aquí: https://github.com/mayoff/tableView-over-mapview

Actualización para tablas de lado a lado

No creo que las tablas de lado a lado sean una buena interfaz de usuario. Creo que va a ser confuso. Pero así es como lo haces.

La jerarquía de vista se ve así:

  • Vista de raíz
    • MKMapView
    • MyScrollView
      • ScrollContentView
        • MyTableView para la primera tabla
        • MyTableView para la segunda tabla
        • MyTableView para la tercera tabla
        • etc

La vista del map y la vista de desplazamiento tienen los mismos frameworks. La vista de desplazamiento maneja el desplazamiento lateral y cada vista de tabla se desplaza verticalmente de forma independiente.

Dado que la vista de desplazamiento solo debe capturar los toques que aterrizan en una de las vistas de la tabla, necesita un hitTest:withEvent: personalizado hitTest:withEvent: devuelve nil para toques fuera de cualquiera de las vistas de la tabla:

 @implementation MyScrollView - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { UIView *hitView = [super hitTest:point withEvent:event]; return hitView == self ? nil : hitView; } @end 

Pero esto no hará el trabajo, porque (en mi implementación) la vista de desplazamiento tiene una sola subvista grande, ScrollContentView . Entonces, debemos hacer lo mismo en ScrollContentView :

 @implementation ScrollContentView - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { UIView *hitView = [super hitTest:point withEvent:event]; return hitView == self ? nil : hitView; } 

Eso es suficiente para pasar los toques a la vista del map si aterrizan fuera de las tablas.

También utilizo ScrollContentView para diseñar las tablas y configurar el tamaño de contenido de la vista de desplazamiento:

 - (void)layoutSubviews { [super layoutSubviews]; // Layout of subviews horizontally: // [gutter/2][gutter][subview][gutter][subview][gutter][subview][gutter][gutter/2] // where 3 * gutter + subview = width of superview CGSize superSize = self.superview.bounds.size; CGFloat x = kGutterWidth * 3 / 2; CGFloat subWidth = superSize.width - kGutterWidth * 3; for (UITableView *subview in self.subviews) { subview.frame = CGRectMake(x, 0, subWidth, superSize.height); x += subWidth + kGutterWidth; CGFloat topInset = superSize.height - subview.rowHeight; subview.contentInset = (UIEdgeInsets){ .top = topInset }; subview.contentOffset = CGPointMake(0, -topInset); } x += kGutterWidth / 2; self.frame = CGRectMake(0, 0, x, superSize.height); ((UIScrollView *)self.superview).contentSize = self.bounds.size; _pageWidth = subWidth + kGutterWidth; } 

También hice que mi controller de vista fuera el delegado de la vista de desplazamiento e implementé un método de delegado para forzar la vista de desplazamiento a detenerse en los límites de la "página" (tabla):

 - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset { CGFloat pageWidth = contentView.pageWidth; // Force scroll view to stop on a page boundary. CGFloat pageNumber = targetContentOffset->x / pageWidth; if (velocity.x < 0) { pageNumber = floor(pageNumber); } else { pageNumber = ceil(pageNumber); } pageNumber = MAX(0, MIN(pageNumber, contentView.subviews.count - 1)); targetContentOffset->x = pageNumber * pageWidth; } 

El resultado:

múltiples mesas lado a lado

He actualizado el repository git con esta versión.

Debería poder hacer esto fácilmente configurando el contenido superior de su vista de contentInset en algo alto (como se sugiere en los comentarios) y luego convirtiendo su UITableView en una subclass para que pueda anular -pointInside:withEvent: Usando eso y el contenido actual, puede determinar si el evento entrante está dentro del área que desea desplazarse y devolver SÍ o NO en consecuencia; Si devuelve NO, el toque debe pasar a la vista del map según lo previsto.

¿Por qué no cambiar esto por completo? Dijiste que tienes un map "debajo" de la vista de tabla. Entonces, cuando se desplaza hacia arriba, el map estará oculto por la vista de la tabla. Supongo que cuando vuelvas a bajar, ¿se revelará el map?

Debería poder hacerlo usando el encabezado UITableView . Ya sea un encabezado de sección o un encabezado de vista de tabla. Se comportan de manera ligeramente diferente al desplazarse.

Quizás lo haría de esta manera …

Use un table view header en la tabla. En este encabezado, coloque la vista de map.

De manera pnetworkingeterminada, esto se fijará en la parte superior de la tabla, por lo que si desplaza la tabla hacia arriba, el map se deslizará hacia la parte superior de la pantalla.

Sin embargo, si luego intercepta el método de delegado de vista de desplazamiento - (void)scrollViewDidScroll:(UIScrollView *)scrollView; entonces puede resolver si la tabla se desplaza hacia arriba y se compensa la vista del map para que permanezca donde está.

es decir, si la tabla se desplaza hacia (0, 10), entonces se puede desplazar el map a (0, -10) para que parezca que no se ha movido.

Esto le dará la function de desplazamiento de input y salida de la vista de tabla y mantendrá el map a la vista y responderá a los toques.