swift - doesn - Cómo hacer que el desplazamiento de un TableView dentro de ScrollView se comporte naturalmente
uiscrollview programmatically swift (10)
Creo que hay dos opciones.
Como conoce el tamaño de la vista de desplazamiento y la vista principal, no puede saber si la vista de desplazamiento tocó el fondo o no.
if (scrollView.contentOffset.y >= (scrollView.contentSize.height - scrollView.frame.size.height)) {
// reach bottom
}
Entonces cuando golpeó; básicamente estableciste
[contentScrollView setScrollEnabled:NO];
y al revés para su tableView.
La otra cosa, que es más precisa, creo, es agregar gestos a sus puntos de vista.
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc]
initWithTarget:self action:@selector(respondToTapGesture:)];
// Specify that the gesture must be a single tap
tapRecognizer.numberOfTapsRequired = 1;
// Add the tap gesture recognizer to the view
[self.view addGestureRecognizer:tapRecognizer];
// Do any additional setup after loading the view, typically from a nib
Entonces, cuando agrega Gesture, simplemente puede controlar la vista activa cambiando
setScrollEnabled
en
respondToTapGesture
.
Necesito hacer esta aplicación que tiene una configuración extraña.
Como se muestra en la siguiente imagen, la vista principal es un UIScrollView. Luego, dentro de este debe tener un UIPageView, y cada página del PageView debe tener un UITableView.
He hecho todo esto hasta ahora. Pero mi problema es que quiero que el desplazamiento se comporte de forma natural .
Lo siguiente es lo que quiero decir naturalmente . Actualmente, cuando me desplazo en uno de los UITableViews, desplaza la vista de tabla (no la vista de desplazamiento). Pero quiero que desplace ScrollView a menos que la vista de desplazamiento no se pueda desplazar porque llegó a su parte superior o inferior (en ese caso, me gustaría que desplazara la vista de tabla).
Por ejemplo, supongamos que mi vista de desplazamiento se desplaza actualmente a la parte superior. Luego puse mi dedo sobre la vista de la mesa (de la página actual que se muestra) y comencé a desplazarme hacia abajo . En este caso, quiero que la vista de desplazamiento se desplace (no la vista de tabla). Si sigo desplazando hacia abajo mi vista de desplazamiento y llega a la parte inferior, si quito mi dedo de la pantalla y lo vuelvo a colocar sobre la vista de teble y me desplazo hacia abajo nuevamente, quiero que mi vista de tabla se desplace hacia abajo ahora porque la vista de desplazamiento llegó a su parte inferior y no está capaz de seguir desplazándose.
¿Tienen alguna idea sobre cómo implementar este desplazamiento?
Estoy REALMENTE perdido con esto. Cualquier ayuda será muy apreciada :(
¡Gracias!
Después de muchas pruebas y errores, esto es lo que mejor funcionó para mí. La solución tiene que resolver dos necesidades 1) determinar quién debe usar la propiedad de desplazamiento; tableView o scrollView? 2) asegúrese de que tableView no otorgue autoridad a scrollView hasta que haya alcanzado la parte superior de su tabla / contenido.
Para ver si la vista de desplazamiento debe usarse para desplazarse frente a la vista de tabla, verifiqué si la vista UIView justo encima de mi vista de tabla estaba dentro del marco. Si el UIView está dentro del marco, es seguro decir que scrollView debería tener autoridad para desplazarse. Si el UIView no está dentro del marco, eso significa que el TableView está ocupando toda la ventana y, por lo tanto, debe tener autoridad para desplazarse.
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView.bounds.intersects(UIView.frame) == true {
//the UIView is within frame, use the UIScrollView''s scrolling.
if tableView.contentOffset.y == 0 {
//tableViews content is at the top of the tableView.
tableView.isUserInteractionEnabled = false
tableView.resignFirstResponder()
print("using scrollView scroll")
} else {
//UIView is in frame, but the tableView still has more content to scroll before resigning its scrolling over to ScrollView.
tableView.isUserInteractionEnabled = true
scrollView.resignFirstResponder()
print("using tableView scroll")
}
} else {
//UIView is not in frame. Use tableViews scroll.
tableView.isUserInteractionEnabled = true
scrollView.resignFirstResponder()
print("using tableView scroll")
}
}
¡Espero que esto ayude a alguien!
Encontré una biblioteca impresionante MXParallaxHeader
En Storyboard simplemente configure la clase
UIScrollView
en
MXScrollView
luego ocurre la magia.
UIPageViewController
esta clase para manejar mi
UIScrollView
cuando
UIPageViewController
una vista de contenedor
UIPageViewController
.
incluso puede insertar una vista de encabezado de paralaje para obtener más detalles.
Además, esta biblioteca proporciona
Cocoapods
y
Carthage
Adjunto una imagen a continuación que representa la Jerarquía de
UIView
.
Jerarquía MXScrollView
La solución para manejar simultáneamente la vista de desplazamiento y la vista de tabla gira en torno al
UIScrollViewDelegate
.
Por lo tanto, haga que su controlador de vista cumpla con ese protocolo:
class ViewController: UIViewController, UIScrollViewDelegate {
Representaré la vista de desplazamiento y la vista de tabla como salidas:
@IBOutlet weak var scrollView: UIScrollView!
@IBOutlet weak var tableView: UITableView!
También necesitaremos rastrear la altura del contenido de la vista de desplazamiento, así como la altura de la pantalla. Verás por qué más tarde.
let screenHeight = UIScreen.mainScreen().bounds.height
let scrollViewContentHeight = 1200 as CGFloat
Se necesita una pequeña configuración en
viewDidLoad:
::
override func viewDidLoad() {
super.viewDidLoad()
scrollView.contentSize = CGSizeMake(scrollViewContentWidth, scrollViewContentHeight)
scrollView.delegate = self
tableView.delegate = self
scrollView.bounces = false
tableView.bounces = false
tableView.scrollEnabled = false
}
donde he desactivado el rebote para mantener las cosas simples. La configuración clave son los delegados para la vista de desplazamiento y la vista de tabla, y al principio se desactiva el desplazamiento de la vista de tabla.
Estos son necesarios para que el método
scrollViewDidScroll:
delegado pueda manejar llegar al final de la vista de desplazamiento y llegar a la parte superior de la vista de tabla.
Aquí está ese método:
func scrollViewDidScroll(scrollView: UIScrollView) {
let yOffset = scrollView.contentOffset.y
if scrollView == self.scrollView {
if yOffset >= scrollViewContentHeight - screenHeight {
scrollView.scrollEnabled = false
tableView.scrollEnabled = true
}
}
if scrollView == self.tableView {
if yOffset <= 0 {
self.scrollView.scrollEnabled = true
self.tableView.scrollEnabled = false
}
}
}
Lo que está haciendo el método delegado es detectar cuándo la vista de desplazamiento ha llegado a su parte inferior. Cuando eso ha sucedido, la vista de tabla se puede desplazar. También está detectando cuándo la vista de tabla alcanza la parte superior donde se vuelve a habilitar la vista de desplazamiento.
Creé un GIF para demostrar los resultados:
Ninguna de las respuestas aquí funcionó perfectamente para mí. Cada uno tenía su propio problema matizado (la necesidad de hacer un deslizamiento repetido cuando una vista de desplazamiento tocaba el fondo, o el indicador de desplazamiento no se veía correcto, etc.), así que pensé en arrojar otra respuesta.
Ole Begemann tiene una excelente redacción sobre cómo hacer esto exactamente https://oleb.net/blog/2014/05/scrollviews-inside-scrollviews/
A pesar de ser una publicación anterior, los conceptos aún se aplican a las API actuales. Además, hay una implementación mantenida (compatible con Xcode 9) de Objective-C de su enfoque https://github.com/eyeem/OLEContainerScrollView
Probé la solución marcada como la respuesta correcta, pero no funcionaba correctamente. El usuario debe hacer clic dos veces en la vista de tabla para desplazarse y después de eso no pude volver a desplazar toda la pantalla. Así que acabo de aplicar el siguiente código en viewDidLoad ():
tableView.addGestureRecognizer(UISwipeGestureRecognizer(target: self, action: #selector(tableViewSwiped)))
scrollView.addGestureRecognizer(UISwipeGestureRecognizer(target: self, action: #selector(scrollViewSwiped)))
Y el siguiente código es la implementación de las acciones:
func tableViewSwiped(){
scrollView.isScrollEnabled = false
tableView.isScrollEnabled = true
}
func scrollViewSwiped(){
scrollView.isScrollEnabled = true
tableView.isScrollEnabled = false
}
Se modificó la respuesta de Daniel para hacerlo más eficiente y libre de errores.
@IBOutlet weak var scrollView: UIScrollView!
@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var tableHeight: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
//Set table height to cover entire view
//if navigation bar is not translucent, reduce navigation bar height from view height
tableHeight.constant = self.view.frame.height-64
self.tableView.isScrollEnabled = false
//no need to write following if checked in storyboard
self.scrollView.bounces = false
self.tableView.bounces = true
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 20
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let label = UILabel(frame: CGRect(x: 0, y: 0, width: tableView.frame.width, height: 30))
label.text = "Section 1"
label.textAlignment = .center
label.backgroundColor = .yellow
return label
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = "Row: /(indexPath.row+1)"
return cell
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView == self.scrollView {
tableView.isScrollEnabled = (self.scrollView.contentOffset.y >= 200)
}
if scrollView == self.tableView {
self.tableView.isScrollEnabled = (tableView.contentOffset.y > 0)
}
}
El proyecto completo se puede ver aquí: https://gitlab.com/vineetks/TableScroll.git
Tal vez fuerza bruta, pero funciona perfectamente: por cierto, uso el diseño automático.
para tableView (o collectionView o lo que sea), establezca una altura arbitraria en el guión gráfico y haga una salida a la clase. Donde sea apropiado, (viewDidLoad () o ...) establezca la altura de tableView lo suficientemente grande como para que tableView no necesite desplazarse. (necesita saber el número de filas por adelantado) Entonces solo el scrollView externo se desplazará muy bien.
También estaba luchando con este problema. Hay una solución muy simple.
En el generador de interfaces:
- crear ViewController simple
-
agregue una vista simple, será nuestro encabezado y constráigala a la vista general
- es la vista roja en el ejemplo a continuación
- He agregado 12px desde arriba, izquierda y derecha, y configuré la altura fija en 128px
- incrustar un PageViewController, asegurándose de que esté restringido a la supervista, y no al encabezado
Ahora, aquí viene la parte divertida: por cada página que agregue, asegúrese de que su TableView tenga un desplazamiento desde la parte superior. Eso es. Puede hacerlo si con este código, por ejemplo (suponiendo que use UITableViewController como página):
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let tables = viewControllers.compactMap { $0 as? UITableViewController }
tables.forEach {
$0.tableView.contentInset = UIEdgeInsets(top: headerView.bounds.height, left: 0, bottom: 0, right: 0)
$0.tableView.contentOffset = CGPoint(x: 0, y: -headerView.bounds.height)
}
}
Sin desplazamiento desordenado dentro de desplazamiento dentro de la vista de tabla, sin destrozar delegados, sin desplazamientos duplicados, comportamiento perfectamente natural. Si no puede ver el encabezado, probablemente se deba al color de fondo tableView. Debe configurarlo para borrar, para que el encabezado sea visible desde debajo de la vista de tabla.
CGFloat tableHeight = 0.0f;
YourArray =[response valueForKey:@"result"];
tableHeight = 0.0f;
for (int i = 0; i < [YourArray count]; i ++) {
tableHeight += [self tableView:self.aTableviewDoc heightForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
}
self.aTableviewDoc.frame = CGRectMake(self.aTableviewDoc.frame.origin.x, self.aTableviewDoc.frame.origin.y, self.aTableviewDoc.frame.size.width, tableHeight);