webentwicklung-frage-antwort-db.com.de

Wie wird das UIPageControl-Element in einem UIPageViewController oben auf den Seiten angezeigt?

Zu diesem Tutorial von AppCoda zur Implementierung einer App mit UIPageViewController möchte ich ein benutzerdefiniertes Seitensteuerelement oben auf den Seiten und nicht unten verwenden. 

Wenn ich einfach ein Seitensteuerelement auf die einzelnen Ansichten platziere, die angezeigt werden, ist das logische Ergebnis, dass die Steuerelemente mit der Seitenansicht vom Bildschirm weg scrollen. 

Wie ist es möglich, das Steuerelement über den Ansichten zu platzieren, sodass die Seitenansichten wie bei einem Bild im Vollbildmodus angezeigt werden, sodass der Benutzer die Ansichten unter dem festen Steuerelement sehen kann?

Ich habe ein Beispiel-Screenshot angehängt - Credits an AppCoda und Path :

enter image description here

58
sn3ek

Nach weiterer Untersuchung und Suche habe ich eine Lösung gefunden , auch bei stackoverflow.

Der Schlüssel ist die folgende Nachricht, die an ein benutzerdefiniertes UIPageControl-Element gesendet werden soll:

[self.view bringSubviewToFront:self.pageControl];

Das AppCoda-Tutorial ist die Grundlage für diese Lösung :

Fügen Sie ein UIPageControl-Element über der RootViewController hinzu - dem Ansichtscontroller mit dem Pfeil.

Erstellen Sie ein verwandtes IBOutlet-Element in Ihrem ViewController.m

In der viewDidLoad-Methode sollten Sie dann den folgenden Code als letzte Methode hinzufügen, die Sie nach dem Hinzufügen aller Unteransichten aufrufen.

[self.view bringSubviewToFront:self.pageControl];

Um die aktuelle Seite basierend auf dem pageIndex der aktuellen Inhaltsansicht zuzuweisen, können Sie den UIPageViewControllerDataSource-Methoden Folgendes hinzufügen:

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

Ich hatte nicht die Vertreterin, um die Antwort zu kommentieren, die hier entstand, aber ich mag sie wirklich. Ich habe den Code verbessert und in Swift für die folgende Unterklasse von UIPageViewController konvertiert:

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

Sauber und es funktioniert gut. Sie brauchen nichts zu pflegen, machen Sie aus Ihrem Page-View-Controller lediglich eine Instanz dieser Klasse im Storyboard oder lassen Sie stattdessen Ihre benutzerdefinierte Page-View-Controller-Klasse von dieser Klasse erben.

50
Eric F.

sn3ek Deine Antwort hat mich am meisten dort hin gebracht. Ich habe die aktuelle Seite jedoch nicht mit den viewControllerCreation-Methoden eingestellt.

Ich habe meinen ViewController also zum Delegierten der UIPageViewController gemacht. Dann setze ich das PageControl des CurrentPage in dieser Methode. Mit der pageIndex-Pflege werde ich die ContentViewController-Erwähnung im Originalartikel erwähnen.

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

vergiss nicht, dies zu viewDidLoad hinzuzufügen.

self.pageViewController.delegate = self;

Um den Kommentar von PropellerHead zu verfolgen, wird das Interface für ViewController das Formular haben

@interface ViewController : UIViewController <UIPageViewControllerDataSource, UIPageViewControllerDelegate>
27
Coderdad

Der gleiche Effekt kann einfach durch Unterklasse von UIPageViewController und durch Überschreiben von viewDidLayoutSubviews wie folgt erzielt werden:

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

Dann brauchen Sie keine separate UIPageControl und so weiter.

3
zeroimpl

Hier ist eine Antwort von RxSwift/RxCocoa, die ich zusammengestellt habe, nachdem ich mir die anderen Antworten angesehen hatte.

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

Sie müssen eine benutzerdefinierte UIPageControl implementieren und der Ansicht hinzufügen. Wie bereits erwähnt, muss view.bringSubviewToFront(pageControl) aufgerufen werden.

Ich habe ein Beispiel eines View-Controllers mit dem gesamten Code zum Einrichten einer benutzerdefinierten UIPageControl (im Storyboard) mit UIPageViewController

Es gibt zwei Methoden, die Sie implementieren müssen, um das Kennzeichen für die aktuelle Seite festzulegen.

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
samwize

Hier ist die Antwort von Swifty 2, die auf der Antwort von @ zerotool basiert. Fügen Sie einfach UIPageViewController hinzu und fügen Sie diese Überschreibung hinzu, um die Bildlaufansicht zu finden und deren Größe zu ändern. Dann schnappen Sie sich das Seitensteuerelement und verschieben Sie es an die Spitze von allem anderen. Sie müssen auch die Hintergrundfarbe der Seitensteuerelemente auf "Löschen" setzen. Diese letzten beiden Zeilen könnten in Ihrem App-Delegierten enthalten sein.

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

Übrigens: Ich sehe keine Endlosschleifen, wie oben erwähnt. 

0
Lee Probert