IPhone पर चित्र में UISplitViewController मास्टर के बजाय विस्तार कुलपति से पता चलता है


177

मैं Xcode 6 में एक यूनिवर्सल स्टोरीबोर्ड का उपयोग कर रहा हूं, iOS 7 और इसके बाद के संस्करण को लक्षित कर रहा हूं। मैंने UISplitViewControllerआईओएस 8 को चलाने वाले आईफोन पर मूल रूप से समर्थित है जो अब लागू किया है, और एक्सकोड स्वचालित रूप से इसे आईओएस 7. के लिए बैकपोर्ट करेगा। यह वास्तव में अच्छी तरह से काम कर रहा है, सिवाय जब आप आईओएस 8 पर चलने वाले आईफोन में ऐप लॉन्च करते हैं, तो विभाजन का विवरण देखें जब मैं पहली बार मास्टर व्यू कंट्रोलर देखने की अपेक्षा करता हूं तो कंट्रोलर प्रदर्शित होता है। मेरा मानना ​​था कि यह iOS 8 के साथ एक बग था क्योंकि जब आप iOS 7 पर ऐप चलाते हैं, तो यह मास्टर व्यू कंट्रोलर को सही ढंग से दिखाता है। लेकिन iOS 8 अब GM है और यह अभी भी हो रहा है। मैं इसे कैसे सेट कर सकता हूं ताकि जब स्प्लिट व्यू कंट्रोलर का पतन हो जाए (स्क्रीन पर प्रदर्शित केवल एक व्यू कंट्रोलर), जब स्प्लिट व्यू कंट्रोलर प्रदर्शित हो तो यह दिखाता है कि मास्टर व्यू कंट्रोलर डिटेल नहीं है?

मैंने इंटरफ़ेस बिल्डर में यह स्प्लिट व्यू कंट्रोलर बनाया है। स्प्लिट व्यू कंट्रोलर टैब बार कंट्रोलर के भीतर पहला व्यू कंट्रोलर होता है। मास्टर और डिटेल वीसी दोनों नेविगेशन कंट्रोलर होते हैं, जिनमें टेबल व्यू कंट्रोलर होते हैं।

जवाबों:


238

ओह यार, यह मुझे कुछ दिनों के लिए सिरदर्द बना रहा था और यह पता नहीं चल सका कि यह कैसे करना है। सबसे बुरी बात यह थी कि मास्टर-डिटेल टेम्पलेट के साथ एक नया Xcode iOS प्रोजेक्ट बनाना ठीक काम करता था। सौभाग्य से, अंत में, वह छोटा तथ्य यह था कि मुझे इसका समाधान कैसे मिला।

कुछ पोस्ट हैं, जो मुझे पता है कि समाधान नई primaryViewControllerForCollapsingSplitViewController:पद्धति को लागू करने के लिए है UISplitViewControllerDelegate। मैंने कोशिश की कि कोई फायदा न हो। काम करने के लिए लगता है कि मास्टर-विस्तार टेम्पलेट में Apple क्या करता है नए को लागू करने के लिए (यह सब कहने के लिए एक गहरी साँस लें) splitViewController:collapseSecondaryViewController:ontoPrimaryViewController:प्रतिनिधि विधि (फिर से UISplitViewControllerDelegate)। डॉक्स के अनुसार , यह विधि:

प्रतिनिधि को प्राथमिक दृश्य नियंत्रक को समायोजित करने और द्वितीयक दृश्य नियंत्रक को ढह गए इंटरफ़ेस में शामिल करने का प्रयास करता है।

अधिक विशिष्ट विवरण के लिए उस विधि के चर्चा भाग पर पढ़ना सुनिश्चित करें।

जिस तरह से Apple इसे संभालता है:

- (BOOL)splitViewController:(UISplitViewController *)splitViewController
collapseSecondaryViewController:(UIViewController *)secondaryViewController
  ontoPrimaryViewController:(UIViewController *)primaryViewController {

    if ([secondaryViewController isKindOfClass:[UINavigationController class]]
        && [[(UINavigationController *)secondaryViewController topViewController] isKindOfClass:[DetailViewController class]]
        && ([(DetailViewController *)[(UINavigationController *)secondaryViewController topViewController] detailItem] == nil)) {

        // Return YES to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded.
        return YES;

    } else {

        return NO;

    }
}

यह कार्यान्वयन मूल रूप से निम्नलिखित करता है:

  1. यदि secondaryViewControllerहम जो उम्मीद कर रहे हैं (ए UINavigationController), और यह दिखा रहा है कि हम क्या उम्मीद कर रहे हैं ( DetailViewController- आपके विचार नियंत्रक), लेकिन कोई मॉडल ( detailItem) नहीं है, तो " Return YES to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded."
  2. अन्यथा, " NOस्प्लिट व्यू कंट्रोलर को विभाजित करने दें और द्वितीयक व्यू कंट्रोलर की सामग्री को ढह गए इंटरफ़ेस में शामिल करने दें"

परिणाम चित्र में iPhone के लिए निम्नलिखित हैं (या तो चित्र में शुरू या चित्र के लिए घूर्णन - या अधिक सटीक रूप से कॉम्पैक्ट आकार वर्ग):

  1. अगर आपका नजरिया सही है
    • और एक मॉडल है, विवरण दृश्य नियंत्रक दिखाएं
    • लेकिन कोई मॉडल नहीं है, मास्टर व्यू कंट्रोलर दिखाएं
  2. अगर आपका नजरिया सही नहीं है
    • मास्टर दृश्य नियंत्रक दिखाएं

कीचड़ की तरह साफ़।


8
शानदार जवाब! मैंने बस उप-वर्गित किया UISplitViewControllerऔर हमेशा YESउस विधि से वापस लौटा , फिर बस स्टोरीबोर्ड में विभाजन दृश्य वर्ग को बदल दिया, क्योंकि मैं हमेशा चित्र में iPhone पर मास्टर दिखाना चाहता हूं। :)
जॉर्डन एच।

2
मैं चाहता हूं कि मेरा मास्टर व्यू कंट्रोलर छिपा हो अगर "आईफोन" "पोर्ट्रेट" मोड में है क्योंकि मेरे पास डिफॉल्ट डिटेल व्यू कंट्रोलर सेटअप है। मैं उसे कैसे कर सकता हूँ। मेरे गुरु और विवरण दोनों ही कुलपति के हैं। विशेष रूप से मेरा विवरण MMDrawerController है। कृपया मदद करें
हर्षित गुप्ता

3
मैंने जॉय के उपवर्ग के सुझाव की कोशिश की, UISplitViewControllerलेकिन पाया कि काम नहीं किया: splitViewController:collapseSecondaryViewController:ontoPrimaryViewController:कभी नहीं बुलाया गया था। इसके बजाय मैंने Apple के टेम्पलेट को कॉपी किया और AppDelagate में डाल दिया। इसने UISplitViewController बनाने के application didFinishLaunchingWithOptions:साथ-साथ (जहाँ मैंने Apple के टेम्प्लेट की नकल भी की थी) बनाने के लिए कुछ बदलावों की आवश्यकता थी ।
निक

7
@ जॉय की टिप्पणी स्वयं को स्थापित करने के साथ काम करती है। viewdidload में! और .h Thankyou में <UISplitViewControllerDelegate> जोड़ रहा है!
साथीवर्मिसटाइज़न

2
यह मेरे लिए सही उत्तर की तरह लगता है, क्योंकि मुझे ठीक वही समस्या है। हालाँकि, किसी कारण से मेरे splitViewController:collapseSecondaryViewController:ontoPrimaryViewController:कभी नहीं बुलाया जाता है। ऐसा प्रतीत होता है कि प्रतिनिधि मेरे ऐप प्रतिनिधि के applicationDidFinishLaunchingWithOptions:तरीके को ठीक से निर्धारित कर रहा है । किसी और को इस समस्या को देखा है और इस समाधान काम नहीं किया था?
टिम डीन

60

यहाँ स्विफ्ट में स्वीकृत उत्तर है। बस इस उपवर्ग को बनाएं और इसे अपने स्टोरीबोर्ड में अपने स्प्लिट व्यू कॉन्ट्रोलर को असाइन करें।

//GlobalSplitViewController.swift

import UIKit

class GlobalSplitViewController: UISplitViewController, UISplitViewControllerDelegate {

  override func viewDidLoad() {
    super.viewDidLoad()

    self.delegate = self
  }

  func splitViewController(splitViewController: UISplitViewController, collapseSecondaryViewController secondaryViewController: UIViewController!, ontoPrimaryViewController primaryViewController: UIViewController!) -> Bool{
    return true
  }

}

3
महान, यह बहुत मदद करता है। लेकिन एक नई समस्या खड़ी हो गई। बैकबटन जो मुझे मास्टर के पास ले जाता है अब गायब हो जाता है (कभी नहीं दिखाता है)। मैं इसे वापस कैसे लूं? संपादित करें: कोई बात नहीं, अपने आप को लगा :-)। ? अन्य उपयोगकर्ताओं के लिए: detailView में जोड़ें: self.navigationItem.leftBarButtonItem = self.splitViewController .displayModeButtonItem () self.navigationItem.leftItemsSupplementBackButton सच =
टॉम Tallak Solbu

3
अब स्विफ्ट में जो कुछ भी हैfunc splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, onto primaryViewController: UIViewController) -> Bool {
दान Rosenstark

2
ऐसा लगता है कि प्रतिनिधि विधि केवल तब कहा जा रहा है जब वर्ग आकार कॉम्पैक्ट है। इसे आईफोन पर नहीं बल्कि आईपैड पोर्ट्रेट पर कॉल किया जा रहा है, जिसका अर्थ है कि यह समस्या को हल नहीं करता है, क्योंकि आईपैड पोर्ट्रेट भी मोड में है। IOS 12.1 के साथ परीक्षण किया गया
डैनियल

21

मार्क एस 'सही उत्तर का स्विफ्ट संस्करण

जैसा कि Apple के मास्टर-डिटेल टेम्पलेट द्वारा दिया गया है।

func splitViewController(splitViewController: UISplitViewController, collapseSecondaryViewController secondaryViewController:UIViewController, ontoPrimaryViewController primaryViewController:UIViewController) -> Bool {
    guard let secondaryAsNavController = secondaryViewController as? UINavigationController else { return false }
    guard let topAsDetailController = secondaryAsNavController.topViewController as? DetailViewController else { return false }
    if topAsDetailController.detailItem == nil {
        // Return true to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded.
        return true
    }
    return false
}

स्पष्टीकरण

(मार्क एस ने जो कहा वह थोड़ा भ्रमित करने वाला था)

इस प्रतिनिधि पद्धति को कहा जाता है splitViewController: collapseSecondaryViewController: ontoPrimaryViewController:, क्योंकि यह वही करता है। अधिक कॉम्पैक्ट चौड़ाई के आकार में बदलते समय (उदाहरण के लिए परिदृश्य से चित्र के लिए फोन को घुमाते समय), इसे विभाजित दृश्य नियंत्रक को उनमें से केवल एक में ढहाने की आवश्यकता होती है।

यह फ़ंक्शन बूलियन को यह तय करने के लिए लौटाता है कि क्या इसे विस्तार को संक्षिप्त करना चाहिए और मास्टर को दिखाना चाहिए या नहीं।

इसलिए हमारे मामले में, हम इस आधार पर निर्णय लेंगे कि क्या कोई विवरण चयनित था या नहीं। हमें कैसे पता चलेगा कि हमारा विवरण चुना गया है? यदि हम Apple के मास्टर-डिटेल टेम्पलेट का अनुसरण करते हैं, तो डिटेल व्यू कंट्रोलर में डिटेल जानकारी होने के लिए एक वैकल्पिक वैरिएबल होना चाहिए, इसलिए यदि यह शून्य (। कोई भी) है, तो अभी तक कुछ भी नहीं चुना गया है और हमें मास्टर दिखाना चाहिए ताकि उपयोगकर्ता कुछ चुन सके।

बस।


बस स्पष्ट करने के लिए कि मैं @ sschale के संपादन से क्यों लुढ़का। उस कोड से एक उद्धरण है Apple's Master-Detail template, यह महान या संक्षिप्त होने का इरादा नहीं है, बस तथ्यात्मक है। :)
21

10

से प्रलेखन , आप एक प्रतिनिधि के उपयोग करने के लिए बताने की आवश्यकता UISplitViewController नहीं "ढह इंटरफ़ेस" (यानी "पोर्ट्रेट मोड" अपने मामले में) में विवरण दृश्य शामिल करने के लिए। स्विफ्ट 4 में, उसके लिए लागू करने के लिए प्रतिनिधि विधि का नाम बदल दिया गया है:

func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController:UIViewController, onto primaryViewController:UIViewController) -> Bool {
    return true
}

9
   #import <UIKit/UIKit.h>

    @interface SplitProductView : UISplitViewController<UISplitViewControllerDelegate>




    @end

।म:

#import "SplitProductView.h"
#import "PriceDetailTableView.h"

@interface SplitProductView ()

@end

@implementation SplitProductView

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.delegate = self;
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/
- (BOOL)splitViewController:(UISplitViewController *)splitViewController
collapseSecondaryViewController:(UIViewController *)secondaryViewController
  ontoPrimaryViewController:(UIViewController *)primaryViewController {

    if ([secondaryViewController isKindOfClass:[UINavigationController class]]
        && [[(UINavigationController *)secondaryViewController topViewController] isKindOfClass:[PriceDetailTableView class]]

        //&& ([(PriceDetailTableView *)[(UINavigationController *)secondaryViewController topViewController] detailItem] == nil)

        ) {

        // Return YES to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded.
        return YES;

    } else {

        return NO;

    }
}
@end

9

मेरा ऐप स्विफ्ट 2.x में लिखा गया था और अच्छी तरह से चल सकता है। इसे स्विफ्ट 3.0 (XCode कनवर्टर का उपयोग करके) में परिवर्तित करने के बाद, यह पोर्ट्रेट मोड में मास्टर के बजाय पहले विस्तार दिखाना शुरू कर देता है। समस्या फ़ंक्शन का नाम है स्प्लिट व्यू कॉन्ट्रोलर को UISplitViewController.elegate के नए से मिलान करने के लिए नहीं बदला गया है।

उस फ़ंक्शन का नाम मैन्युअल रूप से बदलने के बाद, मेरा ऐप अब सही ढंग से काम कर सकता है:

func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController:UIViewController, onto primaryViewController:UIViewController) -> Bool {
    guard let secondaryAsNavController = secondaryViewController as? UINavigationController else { return false }
    guard let topAsDetailController = secondaryAsNavController.topViewController as? DetailViewController else { return false }
    if topAsDetailController.game == nil {
        // Return true to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded.
        return true
    }
    return false
}

मुझे आपके समान ही समस्या हो रही है, लेकिन मैं आपके समाधान को नहीं समझता। मुझे आपके द्वारा यहां पोस्ट किए गए कोड में कोई बदलाव नहीं दिखाई दे रहा है। क्या आप अधिक विस्तार से बताएंगे। धन्यवाद
बाइबल

कई तरीकों को थोड़ा नाम दिया गया है।
डेव

टोनी का जवाब है स्विफ्ट 3 सिंटैक्स टू @ NiñoScript का जवाब (जो पिछले स्विफ्ट संस्करणों के लिए लिखा गया है)
HelloJffy

2
तेजी से 3 के लिए, डाल करने के लिए मत भूलना self.delegate = selfपर viewDidLoadविधि।
फेर

7

यदि आपके पास विस्तार दृश्य नियंत्रक में दिखाने के लिए डिफ़ॉल्ट मान नहीं हैं, तो आप बस स्प्लिट व्यू कॉंट्रोलर और स्टोरी बोर्ड में आपके डिटेल UIViewController के बीच डिफ़ॉल्ट सेग को हटा सकते हैं। यह पहले मास्टर व्यू कंट्रोलर में हमेशा प्रवेश करेगा।

इसका साइड इफेक्ट यह है कि लैंडस्केप में दो दृश्य देखने के बजाय, आप एक दृश्य को स्प्लिट व्यू कॉंट्रोलर में पूरे आकार में देखेंगे, जब तक कि मास्टर व्यू कंट्रोलर में शो डिटेल सेग को निकाल नहीं दिया जाता।


अच्छी चाल। मेरा ऐप केवल पोर्ट्रेट मोड में है और मैं यह कर सकता हूं।
पीसमून

लैंडस्केप ओरिएंटेशन को छोड़कर यह सही है, आप संभवतः ग्रे भरे हुए दृश्य के खाली दाहिने हिस्से को देखेंगे।
वेदरानो

4

उन सभी लोगों के लिए जो cs193p का फ्राइडे सेक्शन नहीं पा सके:

स्विफ्ट 3.1.1 में UISplitViewController का एक उपवर्ग बना रही है और इसके एक प्रतिनिधि तरीके को लागू करना मेरे लिए एक आकर्षण की तरह काम कर रहा है:

class MainSplitViewController: UISplitViewController, UISplitViewControllerDelegate {

override func viewDidLoad() {
    super.viewDidLoad()
    self.delegate = self
}

func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, onto primaryViewController: UIViewController) -> Bool {
    return true
} }

मेरा स्टोरीबोर्ड


जैसा कि @olito ने बताया है, स्विफ्ट 4 में इसके लिए वाक्यविन्यास बदल गया है: public func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, onto primaryViewController: UIViewController) -> Bool
21

3

मेरी राय में आपको इस समस्या को अधिक सामान्य रूप से हल करना चाहिए। आप UISplitViewController को उप-वर्ग कर सकते हैं और एम्बेडेड दृश्य नियंत्रकों में एक प्रोटोकॉल लागू कर सकते हैं।

class MasterShowingSplitViewController: UISplitViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        delegate = self
    }
}

extension MasterShowingSplitViewController: UISplitViewControllerDelegate {
    func splitViewController(splitViewController: UISplitViewController,
                             collapseSecondaryViewController secondaryViewController: UIViewController,
                             ontoPrimaryViewController primaryViewController: UIViewController) -> Bool {
        guard let masterNavigationController = primaryViewController as? UINavigationController,
                  master = masterNavigationController.topViewController as? SplitViewControllerCollapseProtocol else {
            return true
        }
        return master.shouldShowMasterOnCollapse()

    }
}

protocol SplitViewControllerCollapseProtocol {
    func shouldShowMasterOnCollapse() -> Bool
}

UITableViewController में उदाहरण कार्यान्वयन:

extension SettingsTableViewController: SplitViewControllerCollapseProtocol {
    func shouldShowMasterOnCollapse() -> Bool {
        return tableView.indexPathForSelectedRow == nil
    }
}

आशा करता हूँ की ये काम करेगा। तो आप इस वर्ग का पुन: उपयोग कर सकते हैं और बस एक प्रोटोकॉल लागू करने की आवश्यकता है।


प्रतिनिधि विधि कभी नहीं कहा जाता है!
K_Mohit

यह iPad और iPhone 6/7/8 प्लस पर नहीं कहा जाता है। क्या यह आपकी समस्या है? एक नज़र है: stackoverflow.com/questions/29767614/…
Maik639

2

जब आपको मास्टर से शुरू करने की आवश्यकता होती है, तो केवल SplitView नियंत्रकों से DetailViewController को हटा दें।

UISplitViewController *splitViewController = (UISplitViewController *)[self.storyboard instantiateViewControllerWithIdentifier:@"SETTINGS"];
splitViewController.delegate = self;
[self.navigationController presentViewController:splitViewController animated:YES completion:nil];
if (IPHONE) {
    NSMutableArray * cntlrs = [splitViewController.viewControllers mutableCopy];
    [cntlrs removeLastObject];
    splitViewController.viewControllers = cntlrs;
}

2

इसने मेरे लिए iOS-11 और स्विफ्ट 4 पर काम किया:

//Following code in application didFinishLaunching (inside Application Delegate)
guard let splitViewController = window?.rootViewController as? UISplitViewController,
            let masterNavVC = splitViewController.viewControllers.first as? UINavigationController,
            let masterVC = masterNavVC.topViewController as? MasterViewController
else { fatalError() }
splitViewController.delegate = masterVC

//Following code in MasterViewController class
extension MasterViewController:UISplitViewControllerDelegate {
    func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, onto primaryViewController: UIViewController) -> Bool {
        return true
    }
}

2

फ़ंक्शन का नाम स्विफ्ट के नए संस्करणों में दिया गया है, इसलिए यह कोड स्विफ़्ट 4 पर काम करता है:

import UIKit

class GlobalSplitViewController: UISplitViewController, UISplitViewControllerDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()
        self.delegate = self
    }

    func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, onto primaryViewController: UIViewController) -> Bool {
        return true
    }

}

0

Xamarin / C # समाधान

public partial class MainSplitViewController : UISplitViewController
{
    public MainSplitViewController(IntPtr handle) : base(handle)
    {
    }

    public override void ViewDidLoad()
    {
        base.ViewDidLoad();

        Delegate = new MainSplitViewControllerDelegate();
    }
}

public class MainSplitViewControllerDelegate : UISplitViewControllerDelegate
{
    public override bool CollapseSecondViewController(UISplitViewController splitViewController, UIViewController secondaryViewController, UIViewController primaryViewController)
    {
        return true;
    }
}

0

बस सेट preferredDisplayModeकी संपत्ति UISplitViewControllerके लिए.allVisible

class MySplitViewController: UISplitViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        self.preferredDisplayMode = .allVisible
    }

}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.