สร้าง segue โดยทางโปรแกรม


202

ฉันมีส่วนร่วมUIViewControllerที่ส่วนUIViewsControllersขยายของฉันทั้งหมดเพื่อนำการดำเนินการทั่วไปมาใช้ซ้ำ

ฉันต้องการตั้งค่าการต่อยอดให้กับ "สามัญ" นี้UIViewControllerเพื่อให้ผู้อื่นUIViewControllersได้รับมรดก

ฉันกำลังพยายามหาวิธีที่ฉันจะเขียนโปรแกรม

ฉันเดาว่าคำถามอาจเป็นไปได้อย่างไรที่ฉันจะตั้งค่าให้segueกับทุกคนUIViewControllersโดยไม่ต้องเข้าไปในกระดานเรื่องราวและทำด้วยมือ

คำตอบ:


169

ตามคำนิยามความหมายไม่สามารถแยกจากสตอรี่บอร์ดได้ มันยังอยู่ในนามของชั้นเรียน: UIStoryboardSegue. คุณไม่ได้สร้าง segues โดยทางโปรแกรม - มันคือ runtime บอร์ดเรื่องราวที่สร้างขึ้นมาเพื่อคุณ โดยปกติคุณสามารถโทรperformSegueWithIdentifier:ในรหัสของตัวควบคุมมุมมองของคุณ แต่ขึ้นอยู่กับการตั้งค่า segue แล้วในกระดานเรื่องราวเพื่ออ้างอิง

สิ่งที่ฉันคิดว่าคุณถามคือวิธีที่คุณสามารถสร้างวิธีในตัวควบคุมมุมมองทั่วไปของคุณ (คลาสพื้นฐาน) ที่จะเปลี่ยนเป็นตัวควบคุมมุมมองใหม่และจะได้รับการสืบทอดโดยคลาสที่ได้รับทั้งหมด คุณสามารถทำได้โดยการสร้างวิธีการเช่นนี้กับตัวควบคุมมุมมองคลาสพื้นฐานของคุณ:

- (IBAction)pushMyNewViewController
{
    MyNewViewController *myNewVC = [[MyNewViewController alloc] init];

    // do any setup you need for myNewVC

    [self presentModalViewController:myNewVC animated:YES];
}

แล้วในคลาสที่ได้รับของคุณให้เรียกเมธอดนั้นเมื่อคลิกปุ่มที่เหมาะสมหรือเลือกแถวของตารางหรืออะไรก็ตาม


4
ขอบคุณ มันเป็นความอัปยศที่เราไม่สามารถทำได้ทางโปรแกรม มันจะช่วยเพิ่มคุณภาพของซอร์สโค้ด (การทำสำเนาน้อยกว่านั้นดีเสมอ) ฉันจะไปด้วยคำแนะนำของคุณ
Tiago Veloso

2
@ Jonkroll มันเป็นไปได้ที่จะเรียก / ดำเนินการต่อจากคำสั่งเปลี่ยนเช่นขึ้นอยู่กับสิ่งที่ดัชนีฉันมี?
codejunkie

5
@codejunkie: ใช่คุณสามารถทำได้ คุณจะใช้UIViewControllerวิธีการตั้งชื่อperformSegueWithIdentifier:sender:สำหรับนี้
jonkroll

2
ฉันได้รับการสร้างและดำเนินการต่อการเขียนโปรแกรม (ดูคำตอบของฉัน) มีอะไรผิดปกติกับรหัสของฉันถ้าคำตอบของคุณถูกต้อง?
Jean-Philippe Pellet

13
อัปเดตสำหรับ iOS 6: UIView's presentModalViewController:animated:จะเลิก จากเอกสาร - (คัดค้านใน iOS 6.0 ใช้ presentViewController: เคลื่อนไหว: เสร็จสมบูรณ์: แทน)
ผู้ใช้

346

ฉันคิดว่าฉันจะเพิ่มความเป็นไปได้อีกอย่าง หนึ่งในสิ่งที่คุณสามารถทำได้คือคุณสามารถเชื่อมต่อสองฉากในกระดานเรื่องราวโดยใช้ส่วนต่อพ่วงที่ไม่ได้แนบมากับการกระทำ วิธีที่คุณทำเช่นนี้คือคุณต้องลากจากไอคอนเจ้าของไฟล์ที่ด้านล่างของฉากกระดานเรื่องราวที่เป็นฉากต่อเนื่องและลากขวาไปยังฉากปลายทาง ฉันจะโยนภาพเพื่อช่วยอธิบาย

ป้อนคำอธิบายรูปภาพที่นี่

ป๊อปอัพจะปรากฏขึ้นสำหรับ "Manual Segue" ฉันเลือก Push เป็นประเภท แตะที่สี่เหลี่ยมเล็ก ๆ และตรวจสอบให้แน่ใจว่าคุณอยู่ในผู้ตรวจสอบคุณสมบัติ ให้มันเป็นตัวระบุซึ่งคุณจะใช้เพื่ออ้างถึงในรหัส

ป้อนคำอธิบายรูปภาพที่นี่

ตกลงต่อไปฉันจะทำต่อโดยใช้รายการปุ่มแถบโปรแกรม ใน viewDidLoad หรือที่อื่นฉันจะสร้างรายการปุ่มบนแถบนำทางด้วยรหัสนี้:

UIBarButtonItem *buttonizeButton = [[UIBarButtonItem alloc] initWithTitle:@"Buttonize"
                                                                    style:UIBarButtonItemStyleDone
                                                                   target:self
                                                                   action:@selector(buttonizeButtonTap:)];
self.navigationItem.rightBarButtonItems = @[buttonizeButton];

ตกลงสังเกตว่าตัวเลือกคือ buttonizeButtonTap: ดังนั้นเขียนเมธอด void สำหรับปุ่มนั้นและภายในเมธอดนั้นคุณจะเรียก segue ดังนี้:

-(void)buttonizeButtonTap:(id)sender{
    [self performSegueWithIdentifier:@"Associate" sender:sender];
    }

จำเป็นต้องใช้พารามิเตอร์ผู้ส่งเพื่อระบุปุ่มเมื่อมีการเตรียมฟอเรสต์egegue prepareForSegue เป็นวิธีเฟรมเวิร์กที่คุณจะสร้างอินสแตนซ์ของฉากและส่งผ่านค่าใด ๆ ที่จำเป็นสำหรับการทำงาน นี่เป็นวิธีการของฉัน:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([[segue identifier] isEqualToString:@"Associate"])
    {
        TranslationQuizAssociateVC *translationQuizAssociateVC = [segue destinationViewController];
        translationQuizAssociateVC.nodeID = self.nodeID; //--pass nodeID from ViewNodeViewController
        translationQuizAssociateVC.contentID = self.contentID;
        translationQuizAssociateVC.index = self.index;
        translationQuizAssociateVC.content = self.content;
    }
}

ตกลงเพิ่งทดสอบและใช้งานได้ หวังว่ามันจะช่วยคุณ


@MichaelRowe วิธีนี้ขจัดความจำเป็นในการแยกหรือไม่ ที่ผมเห็นมันคุณยังมีการลากและวางบนกระดานเพื่อควบคุมปลายทาง ..
aherrick

@MichaelRowe นี้ไม่ได้กำจัดความจำเป็นในการแยก สิ่งนี้จะช่วยให้คุณแยกความแตกต่างระหว่างตัวควบคุมมุมมองที่สร้างขึ้นในรหัสแทนในตัวสร้างส่วนต่อประสาน
Matthew

@Matt จริง ๆ แล้วแค่ไปฉันคิดใหม่อย่างสมบูรณ์ว่าฉันติดตั้งแอพของฉัน ... หลังจากเขียน UI ใหม่ทั้งหมดฉันไม่ได้ใช้ส่วนอื่น ๆ อีกต่อไป ..
Michael Rowe

@cocoanut ฉันได้รับข้อผิดพลาดขณะที่ "แอพลิเคชันพยายามที่จะนำเสนอ modally ตัวควบคุมที่ใช้งาน" ความช่วยเหลือใด ๆ เกี่ยวกับเรื่องนี้ ..
Bala

1
Segue แบบแมนนวล "Push" ถูกเลิกใช้แล้วใช้ "Show" คำตอบนี้มีรายละเอียดเพิ่มเติม @smileBot โปรดอัปเดตคำตอบ
NAbbas

81

ฉันใช้รหัสนี้เพื่อยกตัวอย่างซับคลาสคลาสย่อยที่กำหนดเองของฉันและเรียกใช้โดยทางโปรแกรม ดูเหมือนว่าจะทำงาน มีอะไรผิดปกติหรือ? ฉันงงอ่านคำตอบทั้งหมดโดยบอกว่ามันทำไม่ได้

UIViewController *toViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"OtherViewControllerId"];
MyCustomSegue *segue = [[MyCustomSegue alloc] initWithIdentifier:@"" source:self destination:toViewController];
[self prepareForSegue:segue sender:sender];
[segue perform];

4
MyCustomSegue คืออะไร
Victor Engel

3
มันเป็น subclass UIStoryboardSegueกำหนดเอง
Jean-Philippe Pellet

7
@ MarkAmery ผู้คนจำนวนมาก (รวมถึงฉัน) หลีกเลี่ยงการใช้กระดานเรื่องราว พวกมันยากที่จะผสานและไม่มีการตรวจสอบเวลาคอมไพล์ว่า ID ที่ฉันกำลังส่งไปperformSegueWithIdentifier:นั้นถูกกำหนดไว้ในกระดานเรื่องราวจริงๆ ฉันหลีกเลี่ยงปัญหาทั้งหมดหากฉันสร้างส่วนต่อขยายเอง
Jean-Philippe Pellet

3
ฉันเห็นด้วยกับ Jean-Philippe การจัดการกระดานเรื่องราวเป็นความเจ็บปวดในก้น แน่นอนว่ามันง่ายที่จะคลิกวิธีของคุณในการสร้างมุมมองไม่กี่มุมมองและเพิ่มส่วนต่อท้ายที่นี่และส่วนต่อขยายที่มี แต่จัดการ 6 มุมมองด้วย 16 ส่วนที่กำหนดไว้ใน XML เมื่อคุณมีสามนักพัฒนาเล่นซอทั้งหมด อย่างไรก็ตามประเด็นคือ: รหัสให้คุณควบคุม xml ที่สร้างโดย xcode ไม่ได้
Krystian

3
ฉันเห็นความผิดพลาดใน [ทำต่อ] ใน iOS7 ไม่แน่ใจว่ามีใครประสบปัญหานี้หรือไม่
Eric Chen

45

เดาว่านี่เป็นคำตอบและได้รับการยอมรับ แต่ฉันแค่อยากจะเพิ่มรายละเอียดอีกเล็กน้อย

สิ่งที่ฉันทำเพื่อแก้ไขปัญหาที่ฉันจะนำเสนอมุมมองการเข้าสู่ระบบเป็นหน้าจอแรกจากนั้นต้องการแยกแอปพลิเคชันถ้าการเข้าสู่ระบบถูกต้อง ฉันสร้าง segue จากตัวควบคุมการเข้าสู่ระบบดูไปยังตัวควบคุมมุมมองรากและให้ตัวระบุเช่น "myidentifier"

จากนั้นหลังจากตรวจสอบรหัสเข้าสู่ระบบทั้งหมดหากเข้าสู่ระบบถูกต้องฉันจะโทร

[self performSegueWithIdentifier: @"myidentifier" sender: self];

ความเข้าใจผิดที่ใหญ่ที่สุดของฉันคือฉันพยายามใส่ปุ่มบนปุ่มและขัดจังหวะการบันทึกเมื่อพบ


4
ในขณะที่ฉันเขียนเป็นความคิดเห็นอื่น: ฉันได้รับการสร้างและดำเนินการส่วนย่อยที่กำหนดเองโดยทางโปรแกรม (ดูคำตอบของฉัน)
Jean-Philippe Pellet

32

คุณต้องเชื่อมโยงรหัสของคุณกับสิ่งUIStoryboardที่คุณกำลังใช้ ตรวจสอบให้แน่ใจว่าคุณเข้าสู่YourViewControllerในของคุณUIStoryboardคลิกที่เส้นขอบรอบ ๆ จากนั้นตั้งค่าidentifierเขตข้อมูลให้เป็นรหัสNSStringที่คุณโทรหา

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" 
                                                     bundle:nil];
YourViewController *yourViewController = 
 (YourViewController *)
  [storyboard instantiateViewControllerWithIdentifier:@"yourViewControllerID"];
[self.navigationController pushViewController:yourViewController animated:YES];

1
ฉันได้รับสิ่งนี้ แต่จะเกิดอะไรขึ้นถ้า viewController ที่ฉันต้องการนำเสนอฝังอยู่ใน NavigationController ในกระดานเรื่องราว จากสิ่งที่ฉันสามารถค้นหาได้ฉันสามารถเริ่มต้น NavigationController เพื่อฝังไว้ในกระดานเรื่องราวฉันได้ตั้งค่าการตั้งค่า segues สำหรับมุมมองที่จำเป็นต้องนำเสนอแล้ว
jhilgert00

1
คุณสามารถทำอย่างละเอียดเกี่ยวกับเรื่องนี้? ผมคิดว่าปัญหานี้เป็นปัญหาที่ผมมี แต่ไม่สามารถดูเหมือน t พบวิธีการ / สถานที่ที่จะทำเช่นนี้ ...
jesses.co.tt

1
แม้วิธีนี้จะเป็นวิธีที่ถูกต้อง แต่ก็เกี่ยวกับการหลีกเลี่ยงการทำซ้ำ แต่คำถามเกี่ยวกับการทำต่อ ด้วยวิธีนี้คุณสามารถเชื่อมต่อหรือทำการเปลี่ยนระหว่างสองฉากโดยไม่ต้องต่อในกระดานเรื่องราว
BootMaker

16

สำหรับตัวควบคุมที่อยู่ในกระดานเรื่องราว

jhilgert00 นี่คือสิ่งที่คุณกำลังมองหา?

-(IBAction)nav_goHome:(id)sender {
UIViewController *myController = [self.storyboard instantiateViewControllerWithIdentifier:@"HomeController"];
[self.navigationController pushViewController: myController animated:YES];

}

หรือ...

[self performSegueWithIdentifier:@"loginMainSegue" sender:self];

3

ดีคุณสามารถสร้างและยังสามารถ subclass UIStoryBoardSegue คลาสย่อยนั้นส่วนใหญ่จะใช้สำหรับการสร้างภาพเคลื่อนไหวการเปลี่ยนแปลงที่กำหนดเอง

คุณสามารถดูวิดีโอของ wwdc 2011 ที่แนะนำ StoryBoard มันมีอยู่ใน youtube ด้วย

http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIStoryboardSegue_Class/Reference/Reference.html#//apple_ref/occ/cl/UIStoryboardSegue


3

ฉันต้องการเพิ่มคำอธิบาย ...

ความเข้าใจผิดที่พบบ่อยในความเป็นจริงที่ฉันมีบางครั้งก็คือการเล่าเรื่องราวในกระดานเรื่องราวถูกกระตุ้นโดยprepareForSegue:sender:วิธีการ มันไม่ใช่. ทำต่อในสตอรีบอร์ดจะดำเนินการไม่ว่าคุณจะใช้prepareForSegue:sender:วิธีการสำหรับตัวควบคุมมุมมอง (ออกจาก) หรือไม่

ฉันได้เรียนรู้สิ่งนี้จากการบรรยาย iTunesU ที่ยอดเยี่ยมของ Paul Hegartyบรรยายฉันขอโทษ แต่น่าเสียดายที่ไม่สามารถจำได้ว่าการบรรยายใด

หากคุณเชื่อมต่อส่วนต่อขยายระหว่างตัวควบคุมมุมมองสองตัวในกระดานเรื่องราว แต่ไม่ได้ใช้prepareForSegue:sender:วิธีการตัวดำเนินการจะยังคงทำต่อไปยังตัวควบคุมมุมมองเป้าหมาย อย่างไรก็ตามมันจะทำต่อกับตัวควบคุมมุมมองนั้นไม่ได้เตรียมไว้

หวังว่านี่จะช่วยได้


3

ไม่ควรสร้างเซ็กเมนต์กระดานเรื่องราวนอกกระดานเรื่องราว คุณจะต้องวางสายแม้จะมีข้อเสีย

UIStoryboardSegue การอ้างอิงอย่างชัดเจนระบุ:

คุณไม่ได้สร้างวัตถุต่อเนื่องโดยตรง สตอรี่บอร์ดแบบรันไทม์จะสร้างขึ้นมาแทนเมื่อต้องทำงานแยกจากกันระหว่างตัวควบคุมมุมมองสองตัว คุณยังสามารถเริ่มต้น segue แบบเป็นโปรแกรมได้โดยใช้เมธอด performSegueWithIdentifier: sender: ของ UIViewController หากคุณต้องการ คุณอาจทำเช่นนั้นเพื่อเริ่มต้น segue จากแหล่งที่ถูกเพิ่มโดยทางโปรแกรมและดังนั้นจึงไม่สามารถใช้ได้ใน Interface Builder

คุณยังคงสามารถบอกกระดานเรื่องราวให้ทางโปรแกรมนำเสนอมุมมองตัวควบคุมโดยใช้การใช้งานpresentModalViewController:หรือการpushViewController:animated:โทร แต่คุณจะต้องใช้อินสแตนซ์ของกระดานเรื่องราว

คุณสามารถเรียกUIStoryboardวิธีการเรียนของ s เพื่อรับกระดานเรื่องราวที่มีชื่อพร้อมกับมัดศูนย์สำหรับกลุ่มหลัก

storyboardWithName:bundle:


2

ก่อนอื่นสมมติว่าคุณมีมุมมองสองแบบที่แตกต่างกันในกระดานเรื่องราวและคุณต้องการนำทางจากหน้าจอหนึ่งไปอีกหน้าจอหนึ่งดังนั้นให้ทำตามขั้นตอนนี้:

1) กำหนดมุมมองทั้งหมดของคุณด้วยไฟล์คลาสและสตอรี่บอร์ด id ในตัวตรวจสอบตัวตน

2) ตรวจสอบให้แน่ใจว่าคุณเพิ่มตัวควบคุมการนำทางไปยังมุมมองแรก เลือกในกระดานเรื่องราวแล้วเลือกตัวแก้ไข> ฝังใน> ตัวควบคุมการนำทาง

3) ในชั้นแรกของคุณนำเข้า "secondClass.h"

#import "ViewController.h
#import "secondController.h"

4) เพิ่มคำสั่งนี้ใน IBAction ที่ต้องทำตามคำสั่ง

secondController *next=[self.storyboard instantiateViewControllerWithIdentifier:@"second"];
[self.navigationController pushViewController:next animated:YES];

5) @"second"เป็นคลาสคอนโทรลเลอร์ secondview id สตอรีบอร์ด


self.storyboardควรเป็น:UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
masipcat

@masipcat และชื่อกระดานเรื่องราวอาจขึ้นอยู่กับวิธีที่คุณตั้งค่าโครงการ Xcode ของคุณในเหมืองมันเป็น "Main.storyboard" ดังนั้นฉันใช้storyboardWithName:@"Main"
ammianus

@ sanket-chauhan หากตัวควบคุมแรกของคุณไม่ได้ถูกฝังอยู่ใน Navigation Controller คุณสามารถแสดงมุมมองถัดไปโดยใช้[self showDetailViewController:next sender:self];หรือ[self showViewController:next sender:self];
ammianus

1

ฉันย้อนกลับวิศวกรรมและทำให้การใช้งานโอเพนซอร์ซ (อีกครั้ง) ของส่วนย่อยของ UIStoryboard: https://github.com/acoomans/Segway

ด้วยไลบรารีนั้นคุณสามารถกำหนดส่วนย่อยแบบเป็นโปรแกรม (ไม่มีกระดานเรื่องราว)

หวังว่ามันจะช่วยได้


0

ปัญหาสองสามข้อจริง:

ขั้นแรกในโครงการที่คุณอัปโหลดให้เราส่วนต่อท้ายจะไม่แสดงตัวระบุ "segue1":

ไม่มีตัวระบุ

คุณควรกรอกตัวระบุนั้นถ้าคุณยังไม่ได้ทำ

ประการที่สองในขณะที่คุณผลักจากมุมมองตารางไปยังมุมมองตารางคุณกำลังเรียก initWithNibName เพื่อสร้างตัวควบคุมมุมมอง คุณต้องการใช้ instantiateViewControllerWithIdentifier จริงๆ


0

นี่คือตัวอย่างโค้ดสำหรับCreating a segue programmatically:

class ViewController: UIViewController {
    ...
    // 1. Define the Segue
    private var commonSegue: UIStoryboardSegue!
    ...
    override func viewDidLoad() {
        ...
        // 2. Initialize the Segue
        self.commonSegue = UIStoryboardSegue(identifier: "CommonSegue", source: ..., destination: ...) {
            self.commonSegue.source.showDetailViewController(self.commonSegue.destination, sender: self)
        }
        ...
    }
    ...
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // 4. Prepare to perform the Segue
        if self.commonSegue == segue {
            ...
        }
        ...
    }
    ...
    func actionFunction() {
        // 3. Perform the Segue
        self.prepare(for: self.commonSegue, sender: self)
        self.commonSegue.perform()
    }
    ...
}

คุณกำลังโทรself.prepare(for: self.commonSegue, sender: self)จากวิธีการกระทำของคุณ แล้ววิธีการเปรียบเทียบif self.commonSegue == segue {...}ในprepare(for:sender)วิธีคืออะไร?
nayem

@nayem: ในprepare(for:sender:)คุณสามารถกำหนดค่าตัวควบคุมมุมมองปลายทางก่อนที่จะแสดง actionFunctionแน่นอนคุณสามารถทำมันได้ใน
jqgsninimo

@nayem: เหตุผลที่ฉันทำเช่นนี้คือพยายามให้สอดคล้องกับการจัดการส่วนอื่น ๆ
jqgsninimo
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.