restaurar - safari iphone que es
UIScrollView paginación horizontal como pestañas Mobile Safari (9)
Mobile Safari le permite cambiar de página ingresando una especie de vista de paginación horizontal UIScrollView con un control de página en la parte inferior.
Estoy tratando de replicar este comportamiento particular donde un UIScrollView desplazable horizontalmente muestra parte del contenido de la siguiente vista.
El ejemplo proporcionado por Apple: PageControl muestra cómo usar un UIScrollView para paginación horizontal, pero todas las vistas ocupan todo el ancho de la pantalla.
¿Cómo obtengo un UIScrollView para mostrar el contenido de la siguiente vista, como lo hace Safari móvil?
Establezca el tamaño del marco de scrollView ya que el tamaño de su página sería:
[self.view addSubview:scrollView];
[self.view addGestureRecognizer:mainScrollView.panGestureRecognizer];
Ahora puede hacer panorámicas en self.view
, y se desplazará el contenido en scrollView.
También use scrollView.clipsToBounds = NO;
para evitar recortar el contenido.
He realizado otra implementación que puede devolver la vista de desplazamiento automáticamente. Por lo tanto, no es necesario que tenga un IBOutlet que limitará el reuso en el proyecto.
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
if ([self pointInside:point withEvent:event]) {
for (id view in [self subviews]) {
if ([view isKindOfClass:[UIScrollView class]]) {
return view;
}
}
}
return nil;
}
Implementé la sugerencia upvoted anterior, pero el UICollectionView
I estaba considerando algo fuera del marco para estar fuera de la pantalla. Esto causó que las celdas cercanas solo se mostraran fuera de límites cuando el usuario se desplazaba hacia ellas, lo que no era ideal.
Lo que terminé haciendo fue emular el comportamiento de una vista de desplazamiento agregando el siguiente método al delegado (o UICollectionViewLayout
).
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
{
if (velocity.x > 0) {
proposedContentOffset.x = ceilf(self.collectionView.contentOffset.x / pageSize) * pageSize;
}
else {
proposedContentOffset.x = floorf(self.collectionView.contentOffset.x / pageSize) * pageSize;
}
return proposedContentOffset;
}
Esto evita la delegación de la acción deslizar completamente, que también fue una ventaja. UIScrollViewDelegate
tiene un método similar llamado scrollViewWillEndDragging:withVelocity:targetContentOffset:
que se puede usar para pasar páginas UITableViews y UIScrollViews.
La solución ClipView
anterior me funcionó, pero tuve que hacer una -[UIView hitTest:withEvent:]
diferente -[UIView hitTest:withEvent:]
. La versión de Ed Marty no logró que la interacción del usuario funcionara con scrollviews verticales que tengo dentro de la horizontal.
La siguiente versión funcionó para mí:
-(UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event
{
UIView* child = nil;
if ((child = [super hitTest:point withEvent:event]) == self)
return self.scrollView;
return child;
}
Permita activar eventos de tap en vistas secundarias de la vista de desplazamiento mientras admite la técnica de esta pregunta SO. Utiliza una referencia a la vista de desplazamiento (self.scrollView) para facilitar la lectura.
- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
UIView *hitView = nil;
NSArray *childViews = [self.scrollView subviews];
for (NSUInteger i = 0; i < childViews.count; i++) {
CGRect childFrame = [[childViews objectAtIndex:i] frame];
CGRect scrollFrame = self.scrollView.frame;
CGPoint contentOffset = self.scrollView.contentOffset;
if (childFrame.origin.x + scrollFrame.origin.x < point.x + contentOffset.x &&
point.x + contentOffset.x < childFrame.origin.x + scrollFrame.origin.x + childFrame.size.width &&
childFrame.origin.y + scrollFrame.origin.y < point.y + contentOffset.y &&
point.y + contentOffset.y < childFrame.origin.y + scrollFrame.origin.y + childFrame.size.height
){
hitView = [childViews objectAtIndex:i];
return hitView;
}
}
hitView = [super hitTest:point withEvent:event];
if (hitView == self)
return self.scrollView;
return hitView;
}
Agregue esto a su vista secundaria para capturar el evento táctil:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
(Esta es una variación de la solución de user1856273. Se limpió para facilitar la lectura e incorporó la solución de errores de Bartserk. Pensé en editar la respuesta del usuario1856273, pero era un cambio demasiado grande).
Tengo otra modificación potencialmente útil para la implementación de ClipView hitTest. No me gustó tener que proporcionar una referencia UIScrollView a ClipView. Mi implementación a continuación le permite reutilizar la clase ClipView para expandir el área de prueba de cualquier cosa, y no tener que proporcionarle una referencia.
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
if (([self pointInside:point withEvent:event]) && (self.subviews.count >= 1))
{
// An extended-hit view should only have one sub-view, or make sure the
// first subview is the one you want to expand the hit test for.
return [self.subviews objectAtIndex:0];
}
return nil;
}
Terminé yendo con UIScrollView personalizado porque era el método más rápido y simple que me pareció. Sin embargo, no vi ningún código exacto que pensé que compartiría. Mis necesidades eran para un UIScrollView que tenía un contenido pequeño y, por lo tanto, el propio UIScrollView era pequeño para lograr el efecto de paginación. Como dice la publicación, no se puede pasar. Pero ahora puedes.
Cree una clase CustomScrollView y la subclase UIScrollView. Entonces todo lo que necesita hacer es agregar esto al archivo .m:
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
return (point.y >= 0 && point.y <= self.frame.size.height);
}
Esto le permite desplazarse de un lado a otro (horizontal). Ajuste los límites según corresponda para configurar el área táctil de deslizamiento / deslizamiento. ¡Disfrutar!
mi versión presionando el botón que se encuentra en el desplazamiento - work =)
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
UIView* child = nil;
for (int i=0; i<[[[[self subviews] objectAtIndex:0] subviews] count];i++) {
CGRect myframe =[[[[[self subviews] objectAtIndex:0] subviews]objectAtIndex:i] frame];
CGRect myframeS =[[[self subviews] objectAtIndex:0] frame];
CGPoint myscroll =[[[self subviews] objectAtIndex:0] contentOffset];
if (myframe.origin.x < point.x && point.x < myframe.origin.x+myframe.size.width &&
myframe.origin.y+myframeS.origin.y < point.y+myscroll.y && point.y+myscroll.y < myframe.origin.y+myframeS.origin.y +myframe.size.height){
child = [[[[self subviews] objectAtIndex:0] subviews]objectAtIndex:i];
return child;
}
}
child = [super hitTest:point withEvent:event];
if (child == self)
return [[self subviews] objectAtIndex:0];
return child;
}
pero solo [[self subviews] objectAtIndex: 0] debe ser un desplazamiento
Un UIScrollView
con paginación habilitada se detendrá en múltiplos de su ancho de cuadro (o alto). Entonces, el primer paso es averiguar qué tan ancho quiere que sean sus páginas. Haz que el ancho de UIScrollView
. A continuación, configure los tamaños de la subvista por más grandes que los necesite, y configure sus centros en función de los múltiplos del ancho de UIScrollView
.
Entonces, dado que desea ver las otras páginas, por supuesto, configure clipsToBounds
en NO
como mhjoy declaró. La parte del truco ahora es hacer que se desplace cuando el usuario inicie el arrastre fuera del rango del marco de UIScrollView
. Mi solución (cuando tuve que hacer esto muy recientemente) fue la siguiente:
Cree una subclase UIView
(es decir, ClipView
) que contendrá UIScrollView
y sus subvistas. Básicamente, debería tener el marco de lo que supondría que tendría UIScrollView
en circunstancias normales. Coloque el UIScrollView
en el centro de ClipView
. Asegúrese de que ClipView
clipsToBounds
está configurado en YES
si su ancho es menor que el de su vista principal. Además, ClipView
necesita una referencia a UIScrollView
.
El último paso es anular - (UIView *)hitTest:withEvent:
dentro de ClipView
.
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
return [self pointInside:point withEvent:event] ? scrollView : nil;
}
Esto básicamente expande el área táctil de UIScrollView
al marco de la vista principal, exactamente lo que necesita.
Otra opción sería subclase UIScrollView
y anular su - (BOOL)pointInside:(CGPoint) point withEvent:(UIEvent *) event
método de - (BOOL)pointInside:(CGPoint) point withEvent:(UIEvent *) event
, sin embargo, todavía necesitará una vista de contenedor para hacer el recorte, y puede ser difícil determinar cuándo para regresar YES
basado solo en el marco de UIScrollView
.
NOTA: También debe echar un vistazo a HitTest : withEvent: modification de Juri Pakaste si tiene problemas con la interacción del usuario de subvista.