pageviewcontroller page uikit ios5

uikit - ¿Es posible convertir la página mediante programación en UIPageViewController?



swift 4 pageviewcontroller (15)

¿Es posible pasar página programáticamente en UIPageViewController ?


¿Qué pasa con el uso de métodos de dataSource?

UIViewController *controller = [pageViewController.dataSource pageViewController:self.pageViewController viewControllerAfterViewController:pageViewController.viewControllers.firstObject]; [pageViewController setViewControllers:@[controller] direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:nil];

Analógicamente para atrás.


Aquí hay otro ejemplo de código para una sola vista paginada. La implementación de viewControllerAtIndex se omite aquí, debe devolver el controlador de vista correcto para el índice dado.

- (void)changePage:(UIPageViewControllerNavigationDirection)direction { NSUInteger pageIndex = ((FooViewController *) [_pageViewController.viewControllers objectAtIndex:0]).pageIndex; if (direction == UIPageViewControllerNavigationDirectionForward) { pageIndex++; } else { pageIndex--; } FooViewController *viewController = [self viewControllerAtIndex:pageIndex]; if (viewController == nil) { return; } [_pageViewController setViewControllers:@[viewController] direction:direction animated:YES completion:nil]; }

Las páginas se pueden cambiar llamando

[self changePage:UIPageViewControllerNavigationDirectionReverse]; [self changePage:UIPageViewControllerNavigationDirectionForward];


Como @samwize señaló, la forma de paginar es mediante el uso de

setViewControllers:array

Así es como lo hice: tengo mi fuente de datos y el delegado por separado. Puede llamar a este método y solo cambiar la vista "siguiente". Anteriormente debe aplicar las reglas de búsqueda. Es decir, debe verificar la dirección y el siguiente controlador. Si usa ese método con su fuente de datos personalizada, la matriz de controladores que está mostrando no cambiará (ya que usará una matriz personalizada en una subclase NSObject).

Usando su propia fuente de datos, el método simplemente establece una nueva vista (con una dirección específica). Como todavía controlará las páginas que se mostrarán cuando se pase normalmente.


Como necesitaba esto también, entraré en más detalles sobre cómo hacer esto.

Nota: Supongo que utilizó el formulario de plantilla estándar para generar su estructura UIPageViewController , que tiene tanto el modelViewController como el modelViewController dataViewController creados al invocarlo. Si no comprende lo que escribí, vuelva y cree un nuevo proyecto que use UIPageViewController como base. Lo entenderás entonces.

Por lo tanto, la necesidad de pasar a una página en particular implica la configuración de las diversas piezas del método enumerado anteriormente. Para este ejercicio, supongo que es una vista de paisaje con dos vistas. Además, implementé esto como un IBAction para que se pudiera hacer desde la pulsación de un botón o lo que no, es igual de fácil hacer la llamada al selector y pasar los elementos necesarios.

Por lo tanto, para este ejemplo necesita los dos controladores de vista que se mostrarán, y opcionalmente, si avanza en el libro o hacia atrás.

Tenga en cuenta que simplemente codifiqué dónde ir a las páginas 4 y 5 y uso un resbalón hacia adelante. Desde aquí puede ver que todo lo que necesita hacer es pasar las variables que lo ayudarán a obtener estos elementos ...

-(IBAction) flipToPage:(id)sender { // Grab the viewControllers at position 4 & 5 - note, your model is responsible for providing these. // Technically, you could have them pre-made and passed in as an array containing the two items... DataViewController *firstViewController = [self.modelController viewControllerAtIndex:4 storyboard:self.storyboard]; DataViewController *secondViewController = [self.modelController viewControllerAtIndex:5 storyboard:self.storyboard]; // Set up the array that holds these guys... NSArray *viewControllers = nil; viewControllers = [NSArray arrayWithObjects:firstViewController, secondViewController, nil]; // Now, tell the pageViewContoller to accept these guys and do the forward turn of the page. // Again, forward is subjective - you could go backward. Animation is optional but it''s // a nice effect for your audience. [self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:NULL]; // Voila'' - c''est fin! }


En Swift :

import UIKit extension HomeViewController { // MARK: - Carousel management. func startTimerForMovingCarousel(let numberOfSecondsBetweenFiringsOfTheTimer: NSTimeInterval) { if (self.timerForMovingCarousel == nil) { self.timerForMovingCarousel = NSTimer.scheduledTimerWithTimeInterval(numberOfSecondsBetweenFiringsOfTheTimer, target: self, selector: "moveCarousel", userInfo: nil, repeats: true) } } func moveCarousel() { println("I move the carousel.") let currentContentViewControllerDisplayed = self.pageViewController!.viewControllers[0] as! ContentViewController var index: Int = currentContentViewControllerDisplayed.index if index == self.arrayViewControllers.count - 1 { index = 0 } else { ++index } let contentViewControllerToDisplay = self.arrayViewControllers[index] as! ContentViewController self.pageViewController.setViewControllers([contentViewControllerToDisplay], direction: UIPageViewControllerNavigationDirection.Forward, animated: true, completion: nil) self.pageControl.currentPage = contentViewControllerToDisplay.index } func invalidateTimerForMovingCarousel() { if (self.timerForMovingCarousel != nil) { self.timerForMovingCarousel.invalidate() self.timerForMovingCarousel = nil } } }


En caso de que PAGE CONTROL para indicar la página actual sea O &&. Usted quiere que las páginas naveguen por scroll y también haciendo clic en los botones personalizados en Page ViewController, a continuación puede ser útil.

//Set Delegate & Data Source for PageView controller [Say in View Did Load] self.pageViewController.dataSource = self; self.pageViewController.delegate = self; // Delegates called viewControllerBeforeViewController when User Scroll to previous page - (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController{ [_nextBtn setTitle:@"Next" forState:UIControlStateNormal]; NSUInteger index = ((PageContentViewController*) viewController).pageIndex; if (index == NSNotFound){ return nil; }else if (index > 0){ index--; }else{ return nil; } return [self viewControllerAtIndex:index]; }

// El delegado llamó a viewControllerAfterViewController cuando el usuario se desplaza a la página siguiente

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController{ NSUInteger index = ((PageContentViewController*) viewController).pageIndex; if (index == NSNotFound){ return nil; }else if (index < 3){ index++; }else{ return nil; } return [self viewControllerAtIndex:index];} //Delegate called while transition of pages. The need to apply logic in this delegate is to maintain the index of current page. - (void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray *)pendingViewControllers{ buttonIndex = (int)((PageContentViewController*) pendingViewControllers.firstObject).pageIndex;

}

-(void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed{ if (buttonIndex == 0){ _backButton.hidden = true; }else if (buttonIndex == [self.pageImages count] - 1){ _backButton.hidden = false; [_nextBtn setTitle:@"Begin" forState:UIControlStateNormal]; }else{ _backButton.hidden = false; }

}

// Lógica del botón personalizado (anterior y siguiente)

-(void)backBtnClicked:(id)sender{ if (buttonIndex > 0){ buttonIndex -= 1; } if (buttonIndex < 1) { _backButton.hidden = YES; } if (buttonIndex >=0) { [_nextBtn setTitle:@"Next" forState:UIControlStateNormal]; PageContentViewController *startingViewController = [self viewControllerAtIndex:buttonIndex]; NSArray *viewControllers = @[startingViewController]; [self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil]; }

}

-(void)nextBtnClicked:(id)sender{ if (buttonIndex < 3){ buttonIndex += 1; } if(buttonIndex == _pageImages.count){ //Navigate Outside Pageview controller }else{ if (buttonIndex ==3) { [_nextBtn setTitle:@"Begin" forState:UIControlStateNormal]; } _backButton.hidden = NO; PageContentViewController *startingViewController = [self viewControllerAtIndex:buttonIndex]; NSArray *viewControllers = @[startingViewController]; [self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil]; }

}

//BUTTON INDEX & MAX COUNT -(NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController{ return [self.pageImages count];} -(NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController{ return buttonIndex;}


Este código funcionó bien para mí, gracias.

Esto es lo que hice con eso. Algunos métodos para avanzar o retroceder y uno para ir directamente a una página en particular. Es para un documento de 6 páginas en vista vertical. Funcionará bien si lo pegas en la implementación del RootController de la plantilla pageViewController.

-(IBAction)pageGoto:(id)sender { //get page to go to NSUInteger pageToGoTo = 4; //get current index of current page DataViewController *theCurrentViewController = [self.pageViewController.viewControllers objectAtIndex:0]; NSUInteger retreivedIndex = [self.modelController indexOfViewController:theCurrentViewController]; //get the page(s) to go to DataViewController *targetPageViewController = [self.modelController viewControllerAtIndex:(pageToGoTo - 1) storyboard:self.storyboard]; DataViewController *secondPageViewController = [self.modelController viewControllerAtIndex:(pageToGoTo) storyboard:self.storyboard]; //put it(or them if in landscape view) in an array NSArray *theViewControllers = nil; theViewControllers = [NSArray arrayWithObjects:targetPageViewController, secondPageViewController, nil]; //check which direction to animate page turn then turn page accordingly if (retreivedIndex < (pageToGoTo - 1) && retreivedIndex != (pageToGoTo - 1)){ [self.pageViewController setViewControllers:theViewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:NULL]; } if (retreivedIndex > (pageToGoTo - 1) && retreivedIndex != (pageToGoTo - 1)){ [self.pageViewController setViewControllers:theViewControllers direction:UIPageViewControllerNavigationDirectionReverse animated:YES completion:NULL]; } } -(IBAction)pageFoward:(id)sender { //get current index of current page DataViewController *theCurrentViewController = [self.pageViewController.viewControllers objectAtIndex:0]; NSUInteger retreivedIndex = [self.modelController indexOfViewController:theCurrentViewController]; //check that current page isn''t first page if (retreivedIndex < 5){ //get the page to go to DataViewController *targetPageViewController = [self.modelController viewControllerAtIndex:(retreivedIndex + 1) storyboard:self.storyboard]; //put it(or them if in landscape view) in an array NSArray *theViewControllers = nil; theViewControllers = [NSArray arrayWithObjects:targetPageViewController, nil]; //add page view [self.pageViewController setViewControllers:theViewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:NULL]; } } -(IBAction)pageBack:(id)sender { //get current index of current page DataViewController *theCurrentViewController = [self.pageViewController.viewControllers objectAtIndex:0]; NSUInteger retreivedIndex = [self.modelController indexOfViewController:theCurrentViewController]; //check that current page isn''t first page if (retreivedIndex > 0){ //get the page to go to DataViewController *targetPageViewController = [self.modelController viewControllerAtIndex:(retreivedIndex - 1) storyboard:self.storyboard]; //put it(or them if in landscape view) in an array NSArray *theViewControllers = nil; theViewControllers = [NSArray arrayWithObjects:targetPageViewController, nil]; //add page view [self.pageViewController setViewControllers:theViewControllers direction:UIPageViewControllerNavigationDirectionReverse animated:YES completion:NULL]; } }


Estoy trabajando en eso desde ayer y finalmente lo hice. No pude usar la plantilla estándar por completo, porque tengo tres diferentes controles de vista como vistas de niños:

1 - rootViewController; 2 - model; 3 - viewControllers 3.1 - VC1; 3.2 - VC2; 3.3 - VC3. Note: all of VCs has Storyboard ID.

Necesitaba un botón disparador solo en el primer VC, así que agregué una propiedad para pageViewController y el modelo:

#import <UIKit/UIKit.h> #import "Model.h" @interface VC1 : UIViewController @property (nonatomic, strong) UIPageViewController *thePageViewController; @property (nonatomic, strong) SeuTimePagesModel *theModel; @end

Reescribí el método init del modelo para pasar storyboard y pageViewController como parámetros, así que pude establecerlos en mi VC1:

- (id)initWithStoryboard:(UIStoryboard *)storyboard andPageViewController:(UIPageViewController *)controller { if (self = [super init]) { VC1 *vc1 = [storyboard instantiateViewControllerWithIdentifier:@"VC1"]; vc1.pageViewController = controller; vc1.model = self; VC2 *vc2 = [storyboard instantiateViewControllerWithIdentifier:@"VC2"]; VC3 *vc3 = [storyboard instantiateViewControllerWithIdentifier:@"VC3"]; self.pageData = [[NSArray alloc] initWithObjects:vc1, vc2, vc3, nil]; } return self; }

Finalmente, agregué un IBAction en mi vc1 para activar el método pageViewController setViewControllers: direction: animated: completion ::

- (IBAction)go:(id)sender { VC2 *vc2 = [_model.pages objectAtIndex:1]; NSArray *viewControllers = @[vc2]; [_pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:nil]; }

Tenga en cuenta que no necesito encontrar índices de VCs, mi botón me lleva a mi segundo VC, pero no es difícil obtener todos los índices y hacer un seguimiento de sus vistas de niños:

- (IBAction)selecionaSeuTime:(id)sender { NSUInteger index = [_model.pages indexOfObject:self]; index++; VC2 *vc2 = [_model.pages objectAtIndex:1]; NSArray *viewControllers = @[vc2]; [_pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:nil]; }

¡Espero que te ayude!


Me podría faltar algo aquí, pero esta solución parece mucho más simple que muchas otras propuestas.

extension UIPageViewController { func goToNextPage(animated: Bool = true, completion: ((Bool) -> Void)? = nil) { if let currentViewController = viewControllers?[0] { if let nextPage = dataSource?.pageViewController(self, viewControllerAfter: currentViewController) { setViewControllers([nextPage], direction: .forward, animated: animated, completion: completion) } } } }


Para una sola página, acabo de editar la respuesta de @Jack Humphries

-(void)viewDidLoad { counter = 0; } -(IBAction)buttonClick:(id)sender { counter++; DataViewController *secondVC = [self.modelController viewControllerAtIndex:counter storyboard:self.storyboard]; NSArray *viewControllers = nil; viewControllers = [NSArray arrayWithObjects:secondVC, nil]; [self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:NULL]; }


Sí, es posible con el método:

- (void)setViewControllers:(NSArray *)viewControllers direction:(UIPageViewControllerNavigationDirection)direction animated:(BOOL)animated completion:(void (^)(BOOL finished))completion;`

Ese es el mismo método utilizado para configurar el primer controlador de vista en la página. Similarmente, puede usarlo para ir a otras páginas.

¿ viewControllers preguntas por qué viewControllers es una matriz y no un controlador de vista único?

Esto se debe a que un controlador de vista de página podría tener un "lomo" (como en iBooks), mostrando 2 páginas de contenido a la vez. Si muestra 1 página de contenido a la vez, simplemente pase una matriz de 1 elemento.

Un ejemplo en Swift:

pageContainer.setViewControllers([displayThisViewController], direction: .Forward, animated: true, completion: nil)


Sin embargo, al utilizar este método ''self.pageViewController setViewControllers'' no se llama ''viewDidDissapear'' en viewController para la página que se ha rechazado, mientras que al girar manualmente una página se llama a viewDidDissapear en la página rechazada. Creo que esta es la causa de mi accidente

"La cantidad de controladores de vista proporcionados (0) no coincide con el número requerido (1) para la transición solicitada"


También necesitaba un botón para navegar hacia la izquierda en un PageViewController, uno que debería hacer exactamente lo que esperaría del movimiento de deslizamiento.

Como ya tenía algunas reglas en " pageViewController: viewControllerBeforeViewController " para tratar con la navegación de barrido natural, quería que el botón reutilizara todo ese código, y simplemente no podía permitirse usar índices específicos para llegar a las páginas como el anterior las respuestas lo hicieron Entonces, tuve que tomar una solución alternativa.

Tenga en cuenta que el siguiente código es para un Controlador de vista de página que es una propiedad dentro de mi ViewController personalizado, y tiene su spine establecido en medio.

Aquí está el código que escribí para mi botón Navigate Left:

- (IBAction)btnNavigateLeft_Click:(id)sender { // Calling the PageViewController to obtain the current left page UIViewController *currentLeftPage = [_pageController.viewControllers objectAtIndex:0]; // Creating future pages to be displayed NSArray *newDisplayedPages = nil; UIViewController *newRightPage = nil; UIViewController *newLeftPage = nil; // Calling the delegate to obtain previous pages // My "pageViewController:viewControllerBeforeViewController" method returns nil if there is no such page (first page of the book). newRightPage = [self pageViewController:_pageController viewControllerBeforeViewController:currentLeftPage]; if (newRightPage) { newLeftPage = [self pageViewController:_pageController viewControllerBeforeViewController:newRightPage]; } if (newLeftPage) { newDisplayedPages = [[NSArray alloc] initWithObjects:newLeftPage, newRightPage, nil]; } // If there are two new pages to display, show them with animation. if (newDisplayedPages) { [_pageController setViewControllers:newDisplayedPages direction:UIPageViewControllerNavigationDirectionReverse animated:YES completion:nil]; } }

Puede hacer algo muy similar para hacer un botón de navegación a la derecha desde aquí.


Swift 4:

Necesitaba ir al siguiente controlador cuando toco el siguiente en un controlador de vista de controlador de página y también actualicé el índice pageControl, así que esta fue la mejor y más directa solución para mí :

let pageController = self.parent as! PageViewController pageController.setViewControllers([parentVC.orderedViewControllers[1]], direction: .forward, animated: true, completion: nil) pageController.pageControl.currentPage = 1


- (void)moveToPage { NSUInteger pageIndex = ((ContentViewController *) [self.pageViewController.viewControllers objectAtIndex:0]).pageIndex; pageIndex++; ContentViewController *viewController = [self viewControllerAtIndex:pageIndex]; if (viewController == nil) { return; } [self.pageViewController setViewControllers:@[viewController] direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:nil]; }

// ahora llamamos a este método

[self moveToPage];

Espero que funcione :)