É possível transformar página por meio de programação em UIPageViewController?

É possível transformar página por meio de programação no UIPageViewController ?

Sim, é possível com o método:

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

Esse é o mesmo método usado para configurar o primeiro controlador de exibição na página. Similar, você pode usá-lo para ir para outras páginas.

Pergunto-me porque viewControllers é uma matriz e não um controlador de visualização única?

Isso porque um controlador de exibição de página pode ter uma “espinha” (como no iBooks), exibindo duas páginas de conteúdo de cada vez. Se você exibir 1 página de conteúdo por vez, basta passar em uma matriz de 1 elemento.

Um exemplo no Swift:

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

Como eu também precisava disso, vou entrar em mais detalhes sobre como fazer isso.

Nota: Suponho que você tenha usado o formulário de modelo padrão para gerar sua estrutura UIPageViewController – que possui modelViewController e dataViewController criados quando você o invoca. Se você não entende o que eu escrevi – volte e crie um novo projeto que usa o UIPageViewController como base. Você vai entender então.

Assim, a necessidade de mudar para uma determinada página envolve a configuração das várias partes do método listado acima. Para este exercício, estou assumindo que é uma vista de paisagem com duas exibições. Além disso, implementei isso como um IBAction para que pudesse ser feito a partir de um botão ou não – é tão fácil fazer a chamada seletiva e passar os itens necessários.

Então, para este exemplo, você precisa dos dois controladores de visualização que serão exibidos – e, opcionalmente, se você está indo para frente no livro ou para trás.

Note que eu simplesmente codifiquei onde ir para as páginas 4 e 5 e use um recado. A partir daqui você pode ver que tudo que você precisa fazer é passar as variables ​​que ajudarão você a obter esses itens …

 -(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! } 

Aqui está outro exemplo de código para uma única visualização paginada. Implementação para viewControllerAtIndex é omitida aqui, ele deve retornar o controlador de exibição correto para o índice fornecido.

 - (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]; } 

As páginas podem ser alteradas chamando

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

Este código funcionou muito bem para mim, obrigado.

Isso é o que eu fiz com isso. Alguns methods para avançar ou retroceder e um para ir diretamente para uma determinada página. É para um documento de 6 páginas no modo retrato. Ele funcionará bem se você colá-lo na implementação do RootController do modelo 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]; } } 

Eu poderia estar perdendo algo aqui, mas essa solução parece muito mais simples do que muitas outras propostas.

 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) } } } } 

Que tal usar methods de dataSource?

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

Analogicamente para trás.

Em 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 } } } 

Swift 4:

Eu precisava ir para o próximo controlador quando eu tocava em seguida em um controlador de exibição de pagecontroller e também atualizava o índice pageControl, então essa era a melhor e mais direta solução para mim :

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

No entanto, o uso dessa chamada de método ‘self.pageViewController setViewControllers’ não chama ‘viewDidDissapear’ no viewController para a página que foi desviada, ao passo que a conversão manual de uma página chama viewDidDissapear na página desviada. Eu acredito que esta é a causa do meu acidente

“O número de controladores de visualização fornecidos (0) não corresponde ao número requerido (1) para a transição solicitada”

Eu também precisava de um botão para navegar à esquerda em um PageViewController, que deveria fazer exatamente o que você esperaria do movimento de furto.

Como eu tinha algumas regras em vigor dentro de ” pageViewController: viewControllerBeforeViewController ” para lidar com a navegação de furto natural, queria que o botão reutilizasse todo esse código e simplesmente não poderia usar índices específicos para alcançar páginas como o anterior respostas fez. Então, eu tive que tomar uma solução alternativa.

Por favor, note que o código a seguir é para um controlador de exibição de página que é uma propriedade dentro do meu ViewController personalizado e tem sua coluna definida como mid.

Aqui está o código que escrevi para o botão Navegar para a esquerda:

 - (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]; } } 

Você pode fazer algo muito semelhante para fazer um botão de navegação à direita a partir daqui.

Para a página única, acabei de editar a resposta do @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]; } 

No caso, se PAGE CONTROL para indicar a página atual é O && Você quer que as páginas naveguem por rolagem e também clicando em botões personalizados no Page ViewController, abaixo pode 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]; } 

// Delegar chamado viewControllerAfterViewController quando o usuário rolar para a próxima página

 - (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 do botão personalizado (anterior e seguinte)

 -(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;} 
 - (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]; } 

// agora chama esse método

[self moveToPage];

Eu espero que dê certo 🙂

Como @samwize apontou, a maneira de paginar é usando

 setViewControllers:array 

Aqui está o jeito que eu fiz: eu tenho minha fonte de dados e o delegado separado. Você pode chamar esse método e alterar somente a visualização “próximo”. Anteriormente você tem que aplicar as regras de paginação. Ou seja, você precisa verificar a direção e o próximo controlador. Se você usar esse método com sua origem de dados personalizada, a matriz de controladores que você está exibindo não mudará (já que você usará uma matriz personalizada em uma subclass NSObject).

Usando sua própria fonte de dados, o método apenas define uma nova visão (com direção específica). Desde que você ainda vai controlar as páginas que serão exibidas quando normalmente passando.

Eu estou trabalhando nisso desde ontem e finalmente fiz isso funcionar. Eu não pude usar o template padrão totalmente, porque eu tenho três viewControllers diferentes como childviews:

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

Eu precisava de um botão de gatilho apenas no primeiro VC, então adicionei uma propriedade para pageViewController e model:

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

Eu reescrevi o método init do modelo para passar o storyboard e o pageViewController como parâmetros, para que eu pudesse configurá-los para o meu 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, eu adicionei um IBAction no meu vc1 para acionar o 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]; } 

Note que eu não preciso encontrar índices de VCs, meu botão me leva ao meu segundo VC, mas não é difícil obter todos os índices e manter o controle de seus childviews:

 - (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 ajude você!