web-dev-qa-db-ja.com

iOS8でUISplitViewControllerを使用してマスターView Controllerを非表示にする

Xcodeのマスター/ディテールテンプレートに基づいたiOS7アプリケーションがあり、iOS8に移植しています。大きく変わった領域の1つはUISplitViewControllerです。

ポートレートモードの場合、ユーザーが詳細ビューコントローラーをタップすると、マスタービューコントローラーは閉じられます。

enter image description here

また、ユーザーが行をタップした場合、プログラムでマスタービューコントローラーを非表示にできるようにしたいと思います。

IOS 7では、マスターView Controllerはポップオーバーとして表示され、次のように非表示にすることができました:

[self.masterPopoverController dismissPopoverAnimated:YES];

IOS 8では、マスターはポップオーバーではなくなったため、上記の手法は機能しません。

マスターView Controllerを閉じようとしました:

self.dismissViewControllerAnimated(true, completion: nil)

または、Split View Controllerに詳細View Controllerを表示するように指示します。

self.splitViewController?.showDetailViewController(bookViewController!, sender: self)

しかし、これまでのところ何も機能していません。何か案は?

43
ColinE

UISplitViewControllerを次のように拡張します。

extension UISplitViewController {
    func toggleMasterView() {
        let barButtonItem = self.displayModeButtonItem()
        UIApplication.sharedApplication().sendAction(barButtonItem.action, to: barButtonItem.target, from: nil, forEvent: nil)
    }
}

didSelectRowAtIndexPathまたはprepareForSegueで、次を実行します。

self.splitViewController?.toggleMasterView()

これにより、マスタービューがスムーズにスライドします。

this post からdisplayModeButtonItem()を使用するというアイデアを得て、 this post ごとにタップをシミュレートしています。

ハッキングのように思えるので、私はこのソリューションに本当に満足していません。しかし、それはうまく機能し、まだ代替手段がないようです。

59
phatmann

preferredDisplayModeを使用します。 didSelectRowAtIndexPathまたはprepareForSegueで:

self.splitViewController?.preferredDisplayMode = .PrimaryHidden
self.splitViewController?.preferredDisplayMode = .Automatic

残念ながら、次のようなドキュメントがあるにもかかわらず、マスタービューはスライドする代わりに突然消えます。

このプロパティの値を変更すると、現在の表示モードが実際に変更される場合、Split View Controllerは結果の変更をアニメーション化します。

実際に変更をアニメーション化するより良い方法があればいいのですが。

10
Vinay Jain

MasterViewController- prepareForSegue:sender:メソッドに次のコードを追加することで、Xcode 6.3マスター/ディテールアプリケーション(ユニバーサル)プロジェクトで目的の動作を実現できました。

if view.traitCollection.userInterfaceIdiom == .Pad && splitViewController?.displayMode == .PrimaryOverlay {
    let animations: () -> Void = {
        self.splitViewController?.preferredDisplayMode = .PrimaryHidden
    }
    let completion: Bool -> Void = { _ in
        self.splitViewController?.preferredDisplayMode = .Automatic
    }
    UIView.animateWithDuration(0.3, animations: animations, completion: completion)
}

完全な- prepareForSegue:sender:実装は次のようになります。

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if segue.identifier == "showDetail" {
        if let indexPath = self.tableView.indexPathForSelectedRow() {
            let object = objects[indexPath.row] as! NSDate
            let controller = (segue.destinationViewController as! UINavigationController).topViewController as! DetailViewController
            controller.detailItem = object
            controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem()
            controller.navigationItem.leftItemsSupplementBackButton = true

            if view.traitCollection.userInterfaceIdiom == .Pad && splitViewController?.displayMode == .PrimaryOverlay {
                let animations: () -> Void = {
                    self.splitViewController?.preferredDisplayMode = .PrimaryHidden
                }
                let completion: Bool -> Void = { _ in
                    self.splitViewController?.preferredDisplayMode = .Automatic
                }
                UIView.animateWithDuration(0.3, animations: animations, completion: completion)
            }
        }
    }
}

traitCollectionを使用することは、一部のプロジェクトでdisplayModeの代替/補足になる場合もあります。たとえば、次のコードはXcode 6.3マスター/ディテールアプリケーション(ユニバーサル)プロジェクトでも機能します。

let traits = view.traitCollection
if traits.userInterfaceIdiom == .Pad && traits.horizontalSizeClass == .Regular {
    let animations: () -> Void = {
        self.splitViewController?.preferredDisplayMode = .PrimaryHidden
    }
    let completion: Bool -> Void = { _ in
        self.splitViewController?.preferredDisplayMode = .Automatic
    }
    UIView.animateWithDuration(0.3, animations: animations, completion: completion)
}
9
Imanou Petit

以下のコードは、アニメーションでマスタービューを非表示にします

UIView.animateWithDuration(0.5) { () -> Void in
            self.splitViewController?.preferredDisplayMode = .PrimaryHidden
        }
7
jithinroy

ここにリストされている答えを少し改善するだけで、次のコードが適切に機能し、アニメーションもスムーズに処理されます:

extension UISplitViewController {
    func toggleMasterView() {
        var nextDisplayMode: UISplitViewControllerDisplayMode
        switch(self.preferredDisplayMode){
        case .PrimaryHidden:
            nextDisplayMode = .AllVisible
        default:
            nextDisplayMode = .PrimaryHidden
        }
        UIView.animateWithDuration(0.5) { () -> Void in
            self.preferredDisplayMode = nextDisplayMode
        }
    }
}

そして、前述のように、View Controllerのどこでも拡張機能を使用するだけです

self.splitViewController?.toggleMasterView()
5

Swift 4アップデート:

Prepareに挿入します(セグエの場合:...

if splitViewController?.displayMode == .primaryOverlay {
    let animations: () -> Void = {
        self.splitViewController?.preferredDisplayMode = .primaryHidden
    }
    let completion: (Bool) -> Void = { _ in
        self.splitViewController?.preferredDisplayMode = .automatic
    }
    UIView.animate(withDuration: 0.3, animations: animations, completion: completion)
}
1
Andy G

試してみる

let svc = self.splitViewController 
 svc.preferredDisplayMode = UISplitViewControllerDisplayMode.PrimaryHidden
1
daren

上記の回答を変更するだけで、ビューを構成した詳細ビューコントローラーのメソッドで必要になります。

 [self.splitViewController setPreferredDisplayMode:UISplitViewControllerDisplayModePrimaryHidden];

もちろん、アニメーションの恵みを欠いています。

1
Tim

iPadの場合、このようなメニューボタンを追加します

UIBarButtonItem *menuButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"burger_menu"]
                                                                       style:UIBarButtonItemStylePlain
                                                                      target:self.splitViewController.displayModeButtonItem.target
                                                                      action:self.splitViewController.displayModeButtonItem.action];
[self.navigationItem setLeftBarButtonItem:menuButtonItem];

これは、ランドスケープモードとポートレートモードの両方でうまく機能します。プログラムでポップオーバーvcを閉じるには、このようなボタンアクションを強制する必要があります。

[self.splitViewController.displayModeButtonItem.target performSelector:appDelegate.splitViewController.displayModeButtonItem.action];
0
coder1087

Swift 1.2での私の解決策

  override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath){
    var screen = UIScreen.mainScreen().currentMode?.size.height
    if (UIDevice.currentDevice().userInterfaceIdiom == UIUserInterfaceIdiom.Pad) || screen >= 2000 && UIDevice.currentDevice().orientation.isLandscape == true  && (UIDevice.currentDevice().userInterfaceIdiom == .Phone){
        performSegueWithIdentifier("showDetailParse", sender: nil)
        self.splitViewController?.preferredDisplayMode = UISplitViewControllerDisplayMode.PrimaryHidden
    } else if (UIDevice.currentDevice().userInterfaceIdiom == .Phone) {
        performSegueWithIdentifier("showParse", sender: nil)
    }
}
0