2014-01-10 28 views
56

關於此tutorial by AppCoda about how to implement a app with UIPageViewController我想在頁面頂部而不是底部使用自定義頁面控制元素。如何將UIPageControl元素放在UIPageViewController中的滑動頁面的頂部?

當我將一個頁面控制元素放置在將要顯示的單個視圖之上時,邏輯結果是控件元素與頁面視圖一起滾動離開屏幕。

如何將控制元素置於視圖頂部,以便頁面視圖處於全屏狀態(如與圖像一樣),以便用戶可以在固定控件元素下看到視圖?

我裝戴例子截圖 - 信用AppCoda and Path

enter image description here

回答

49

經過進一步調查和搜索I found a solution,也計算器。

的關鍵是將以下消息發送到定製UIPageControl元件:

[self.view bringSubviewToFront:self.pageControl]; 

The AppCoda tutorial is the foundation for this solution

添加UIPageControl元件上的RootViewController的頂部 - 帶箭頭的視圖控制器。

在您的ViewController.m中創建一個相關IBOutlet元素。

viewDidLoad方法中,您應該添加以下代碼作爲添加所有子視圖後調用的最後一個方法。

[self.view bringSubviewToFront:self.pageControl]; 

要分配根據您可以添加以下到UIPageViewControllerDataSource方法的當前內容視圖的PageIndex的當前頁面:

- (UIPageViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController 
{ 
    // ... 
    index--; 
    [self.pageControl setCurrentPage:index]; 

    return [self viewControllerAtIndex:index]; 
} 

- (UIPageViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController 
{ 
    // ... 
    index++; 
    [self.pageControl setCurrentPage:index]; 

    // ... 
    return [self viewControllerAtIndex:index]; 
} 
+2

奇怪的是,設置頁面控制頁面之前增加/減少索引工作。我從該方法獲得的viewController是**新的視圖控制器,而不是轉換前**。 – Gokul

+0

這並不奇怪;它是預期的。這些方法在* current *視圖控制器上調用,以確定接下來出現的內容。 –

+0

@ sn3ek如何創建相關的IBOutlet元素。 – VJVJ

27

sn3ek你的回答讓我最那裏的方式。雖然我沒有使用viewControllerCreation方法設置當前頁面。

我讓我的ViewController also代表UIPageViewController。然後我在該方法中設置了PageControlCurrentPage。使用pageIndex保持我在原始文章中提到的ContentViewController

- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed 
{ 
    APPChildViewController *currentViewController = pageViewController.viewControllers[0]; 
    [self.pageControl setCurrentPage:currentViewController.pageIndex]; 
} 

不要忘了將它添加到viewDidLoad

self.pageViewController.delegate = self; 

要跟進的Propellerhead的評論對ViewController界面將有形式

@interface ViewController : UIViewController <UIPageViewControllerDataSource, UIPageViewControllerDelegate> 
+2

只是要清楚。 UIPageViewController的代表是UIPageViewControllerDelegate,所以你的ViewController的接口看起來是這樣的: '''@interface ViewController:UIViewController ''' – PropellerHead

+1

這是正確的。 – Coderdad

2

同樣的效果可以是簡單地通過子類化UIPageViewController和覆蓋viewDidLayoutSubviews實現,如下所示:

-(void)viewDidLayoutSubviews { 
    UIView* v = self.view; 
    NSArray* subviews = v.subviews; 
    if([subviews count] == 2) { 
     UIScrollView* sv = nil; 
     UIPageControl* pc = nil; 
     for(UIView* t in subviews) { 
      if([t isKindOfClass:[UIScrollView class]]) { 
       sv = (UIScrollView*)t; 
      } else if([t isKindOfClass:[UIPageControl class]]) { 
       pc = (UIPageControl*)t; 
      } 
     } 
     if(sv != nil && pc != nil) { 
      // expand scroll view to fit entire view 
      sv.frame = v.bounds; 
      // put page control in front 
      [v bringSubviewToFront:pc]; 
     } 
    } 
    [super viewDidLayoutSubviews]; 
} 

然後沒有必要保持一個單獨的UIPageControl等。

+2

我其實很喜歡這個答案。它運作良好。直到我穿上運行iOS 7.1的iPhone 4S。在那一點上它變得無限。不知道爲什麼,但要小心。 –

48

我沒有代表發表此評論的回覆,但我非常喜歡。我提高了代碼,並將其轉換爲SWIFT爲UIPageViewController的以下子類:

class UIPageViewControllerWithOverlayIndicator: UIPageViewController { 
    override func viewDidLayoutSubviews() { 
     for subView in self.view.subviews as! [UIView] { 
      if subView is UIScrollView { 
       subView.frame = self.view.bounds 
      } else if subView is UIPageControl { 
       self.view.bringSubviewToFront(subView) 
      } 
     } 
     super.viewDidLayoutSubviews() 
    } 
} 

乾淨,效果很好。不需要維護任何東西,只需在故事板中將您的頁面視圖控制器設置爲此類的一個實例,或者使您的自定義頁面視圖控制器類繼承此類。

+0

當我把這個for循環ViewDidLoad我可以找到scrollView但不是UIPageControl視圖。我錯過了什麼嗎? – Hakim

+0

@Hakim或許控制器缺少UIPageViewController類型?沒有一個確切情況的例子很難說。 –

+1

我要把這個加入書籤,只是爲了說明這是多麼多麼有用。 Thankx非常感謝! –

0

以上是基於@ zerotool上面的答案的Swifty 2的答案。只需子類UIPageViewController,然後添加此重寫以查找滾動視圖並調整其大小。然後抓住頁面控件並將其移動到其他任何位置的頂部。您還需要設置頁面控件背景顏色以清除。最後兩行可以放在您的應用程序代理中。

override func viewDidLayoutSubviews() { 

    super.viewDidLayoutSubviews() 

    var sv:UIScrollView? 
    var pc:UIPageControl? 

    for v in self.view.subviews{ 

     if v.isKindOfClass(UIScrollView) { 

      sv = v as? UIScrollView 

     }else if v.isKindOfClass(UIPageControl) { 

      pc = v as? UIPageControl 
     } 
    } 

    if let newSv = sv { 

     newSv.frame = self.view.bounds 
    } 

    if let newPc = pc { 

     self.view.bringSubviewToFront(newPc) 
    } 
} 

let pageControlAppearance = UIPageControl.appearance() 
pageControlAppearance.backgroundColor = UIColor.clearColor() 

順便說一句 - 我沒有發現任何無限循環,如上所述。

1

您必須實施自定義UIPageControl並將其添加到視圖中。正如其他人所說,必須調用view.bringSubviewToFront(pageControl)

我有一個視圖控制器的example所有上設置自定義UIPageControl(在故事板)與UIPageViewController

的代碼有兩種方法,你需要實現設置當前頁面指示符。

func pageViewController(pageViewController: UIPageViewController, willTransitionToViewControllers pendingViewControllers: [UIViewController]) { 
    pendingIndex = pages.indexOf(pendingViewControllers.first!) 
} 

func pageViewController(pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) { 
    if completed { 
     currentIndex = pendingIndex 
     if let index = currentIndex { 
      pageControl.currentPage = index 
     } 
    } 
} 
1

這是一個RxSwift/RxCocoa答案,我看了其他答覆後放在一起。

let pages = Variable<[UIViewController]>([]) 
let currentPageIndex = Variable<Int>(0) 
let pendingPageIndex = Variable<(Int, Bool)>(0, false) 

let db = DisposeBag() 

override func viewDidLoad() { 
    super.viewDidLoad() 
    pendingPageIndex 
     .asDriver() 
     .filter { $0.1 } 
     .map { $0.0 } 
     .drive(currentPageIndex) 
     .addDisposableTo(db) 

    currentPageIndex.asDriver() 
     .drive(pageControl.rx.currentPage) 
     .addDisposableTo(db) 
} 

func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) { 
    if let index = pages.value.index(of: pendingViewControllers.first!) { 
     pendingPageIndex.value = (index, false) 
    } 
} 

func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) { 
    pendingPageIndex.value = (pendingPageIndex.value.0, completed) 
} 
相關問題