Membuat segue secara terprogram

202

Saya memiliki kesamaan UIViewControllerbahwa semua UIViewsControllersperpanjangan saya untuk menggunakan kembali beberapa operasi umum.

Saya ingin mengatur segue pada "Common" ini UIViewControllersehingga semua yang lain UIViewControllersmewarisi.

Saya mencoba mencari tahu bagaimana saya melakukannya secara terprogram.

Saya kira pertanyaannya juga bisa bagaimana saya menetapkan seguesemua untuk saya UIViewControllerstanpa pergi ke papan cerita dan melakukannya dengan tangan.

Tiago Veloso
sumber

Jawaban:

169

Menurut definisi, segue tidak dapat benar-benar ada terlepas dari storyboard. Itu bahkan ada dalam nama kelas: UIStoryboardSegue. Anda tidak membuat segues secara terprogram - ini adalah runtime storyboard yang menciptakannya untuk Anda. Anda biasanya dapat memanggil performSegueWithIdentifier:kode pengontrol tampilan Anda, tetapi ini bergantung pada memiliki segue yang sudah disiapkan di storyboard untuk referensi.

Apa yang saya pikir Anda tanyakan adalah bagaimana Anda bisa membuat metode di pengontrol tampilan umum (kelas dasar) yang akan bertransisi ke pengontrol tampilan baru, dan akan diwarisi oleh semua kelas turunan. Anda bisa melakukan ini dengan membuat metode seperti ini ke pengontrol tampilan kelas dasar Anda:

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

    // do any setup you need for myNewVC

    [self presentModalViewController:myNewVC animated:YES];
}

dan kemudian di kelas turunan Anda, panggil metode itu ketika tombol yang sesuai diklik atau baris tabel dipilih atau apa pun.

Jonkroll
sumber
4
Terima kasih. Sayang sekali kita tidak bisa melakukannya secara terprogram. Itu benar-benar akan meningkatkan kualitas kode sumber (kurang duplikasi selalu baik). Saya akan pergi dengan saran Anda.
Tiago Veloso
2
@jonkroll apakah mungkin untuk memanggil / melakukan segue dari pernyataan switch yaitu berdasarkan indeks apa yang saya miliki?
codejunkie
5
@ codejunkie: Ya, Anda bisa melakukannya. Anda akan menggunakan UIViewControllermetode yang dinamai performSegueWithIdentifier:sender:untuk ini.
jonkroll
2
Saya telah membuat dan melakukan segue secara terprogram (lihat jawaban saya). Lalu, ada yang salah dengan kode saya, jika jawaban Anda benar?
Jean-Philippe Pellet
13
Update untuk iOS 6+: UIView's presentModalViewController:animated:sudah ditinggalkan. Dari dokumen - (Tidak digunakan di iOS 6.0. Gunakan presentViewController: animated: completion: gantinya.)
pengguna
346

Saya pikir saya akan menambahkan kemungkinan lain. Salah satu hal yang dapat Anda lakukan adalah Anda dapat menghubungkan dua adegan dalam storyboard menggunakan segue yang tidak melekat pada suatu tindakan, dan kemudian secara terprogram memicu segue di dalam controller tampilan Anda. Cara Anda melakukan ini, adalah bahwa Anda harus menyeret dari ikon pemilik file di bagian bawah adegan storyboard yang merupakan adegan segueing, dan tarik ke kanan ke adegan tujuan. Saya akan melempar gambar untuk membantu menjelaskan.

masukkan deskripsi gambar di sini

Munculan akan ditampilkan untuk "Segue Manual". Saya memilih Push sebagai tipenya. Ketuk pada kotak kecil dan pastikan Anda berada di inspektur atribut. Berikan pengenal yang akan Anda gunakan untuk merujuknya dalam kode.

masukkan deskripsi gambar di sini

Ok, selanjutnya saya akan segue menggunakan item tombol bar terprogram. Di viewDidLoad atau di tempat lain saya akan membuat item tombol pada bilah navigasi dengan kode ini:

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

Ok, perhatikan bahwa pemilihnya adalah buttonizeButtonTap :. Jadi, tulis metode kosong untuk tombol itu dan dalam metode itu Anda akan memanggil segue seperti ini:

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

Parameter pengirim diperlukan untuk mengidentifikasi tombol ketika prepForSegue dipanggil. prepForSegue adalah metode kerangka kerja di mana Anda akan instantiate adegan Anda dan memberikannya nilai apa pun yang diperlukan untuk melakukan tugasnya. Begini tampilannya metode saya:

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

Ok, baru saja mengujinya dan berfungsi. Semoga ini bisa membantu Anda.

smileBot
sumber
@MichaelRowe bagaimana ini menghilangkan kebutuhan akan segues? Seperti yang saya lihat, Anda masih harus menarik dan melepaskan Storyboard ke pengontrol tujuan ..
aherrick
@MichaelRowe ini tidak menghilangkan kebutuhan akan segues. Apa yang dilakukan adalah membiarkan Anda memisahkan antara pengontrol tampilan yang dibangun dalam kode alih-alih di pembangun antarmuka.
Matius
@Matt itu benar-benar hanya pergi saya benar-benar memikirkan kembali bagaimana saya mengatur aplikasi saya ... Setelah menulis ulang lengkap dari semua UI saya tidak lagi menggunakan segues ..
Michael Rowe
@cocoanut saya mendapatkan kesalahan karena "Aplikasi mencoba menghadirkan secara modern sebuah pengontrol aktif" bantuan apa pun mengenai hal ini ..
Bala
1
Segmen Manual "Push" sudah usang, gunakan "Show". Jawaban ini memiliki lebih banyak detail. @smileBot harap perbarui jawabannya.
NAbbas
81

Saya telah menggunakan kode ini untuk membuat instance subkelas segue khusus saya dan menjalankannya secara terprogram. Sepertinya berhasil. Ada yang salah dengan ini? Saya bingung, membaca semua jawaban lain yang mengatakan itu tidak bisa dilakukan.

UIViewController *toViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"OtherViewControllerId"];
MyCustomSegue *segue = [[MyCustomSegue alloc] initWithIdentifier:@"" source:self destination:toViewController];
[self prepareForSegue:segue sender:sender];
[segue perform];
Jean-Philippe Pellet
sumber
4
Apa yang ada di MyCustomSegue?
Victor Engel
3
Ini adalah subkelas kustom dari UIStoryboardSegue.
Jean-Philippe Pellet
7
@MarkAmery Banyak orang (termasuk saya) menghindari menggunakan storyboard. Mereka sulit untuk digabung, dan tidak ada waktu kompilasi memeriksa bahwa ID yang saya lewati performSegueWithIdentifier:benar-benar didefinisikan dalam storyboard. Saya menghindari semua masalah jika saya membuat segue sendiri.
Jean-Philippe Pellet
3
Saya setuju dengan Jean-Philippe. Mengelola storyboard adalah rasa sakit di pantat. Tentu saja mudah untuk mengeklik jalan Anda melalui kasta beberapa tampilan dan menambahkan segue di sini dan segue di sana, tetapi mengelola 6 tampilan dengan 16 segmen didefinisikan dalam XML, ketika Anda memiliki tiga pengembang semua bermain-main dengan itu mengerikan. Pokoknya, intinya adalah: kode memberi Anda kontrol, xml yang dihasilkan oleh xcode tidak.
Krystian
3
Saya melihat crash di [segue perform] di iOS7, tidak yakin apakah ada orang lain yang mengalami hal ini.
Eric Chen
45

Kira ini dijawab dan diterima, tapi saya hanya ingin menambahkan beberapa detail lagi.

Apa yang saya lakukan untuk menyelesaikan masalah di mana saya akan menyajikan tampilan login sebagai layar pertama dan kemudian ingin melakukan segmentasi ke aplikasi jika login benar. Saya membuat segue dari pengontrol tampilan masuk ke pengontrol tampilan root dan memberinya pengenal seperti "myidentifier".

Kemudian setelah memeriksa semua kode login jika login benar saya akan menelepon

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

Kesalahpahaman terbesar saya adalah bahwa saya mencoba untuk menempatkan segue pada tombol dan jenis mengganggu segue setelah ditemukan.

qrikko
sumber
4
Seperti yang saya tulis sebagai komentar lain: Saya telah membuat dan menampilkan segmen khusus secara terprogram (lihat jawaban saya).
Jean-Philippe Pellet
32

Anda harus menautkan kode Anda dengan UIStoryboardyang Anda gunakan. Pastikan Anda masuk ke YourViewController di Anda UIStoryboard, klik perbatasan di sekitarnya, dan kemudian setel identifierbidangnya ke NSStringyang Anda panggil dalam kode Anda.

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" 
                                                     bundle:nil];
YourViewController *yourViewController = 
 (YourViewController *)
  [storyboard instantiateViewControllerWithIdentifier:@"yourViewControllerID"];
[self.navigationController pushViewController:yourViewController animated:YES];
Jeff Grimes
sumber
1
Saya mendapatkan ini, tetapi bagaimana jika viewController yang ingin saya presentasikan tertanam dalam NavigationController di storyboard? Dari apa yang saya dapat temukan, saya dapat menginisialisasi NavigationController untuk menanamkannya tetapi di storyboard, saya sudah memiliki pengaturan push segues untuk tampilan yang perlu disajikan.
jhilgert00
1
dapatkah Anda menjelaskan hal ini? Saya pikir ini adalah masalah yang saya alami, tetapi sepertinya tidak dapat menemukan bagaimana / di mana melakukan ini ...
jesses.co.tt
1
Meskipun solusi ini adalah solusi yang tepat, Ini tentang menghindari segue, tetapi pertanyaannya adalah tentang segue. Dengan cara ini Anda dapat menghubungkan atau membuat transisi antara dua adegan TANPA segue di storyboard.
BootMaker
16

Untuk pengendali yang ada di storyboard.

jhilgert00 apakah ini yang Anda cari?

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

}

ATAU...

[self performSegueWithIdentifier:@"loginMainSegue" sender:self];
pengguna1723341
sumber
3

Saya ingin menambahkan klarifikasi ...

Kesalahpahaman yang umum, pada kenyataannya salah satu yang saya miliki untuk beberapa waktu, adalah bahwa segue storyboard dipicu oleh prepareForSegue:sender:metode ini. Bukan itu. Segue papan cerita akan tampil, terlepas dari apakah Anda telah menerapkan prepareForSegue:sender:metode untuk pengontrol tampilan (berangkat dari).

Saya belajar ini dari kuliah iTunesU Paul Hegarty yang luar biasa . Saya minta maaf tapi sayangnya tidak bisa mengingat kuliah mana.

Jika Anda menghubungkan segue antara dua pengontrol tampilan di storyboard, tetapi jangan mengimplementasikan a prepareForSegue:sender: metode, segue akan tetap segue ke pengontrol tampilan target. Namun itu akan segue ke controller tampilan yang tidak siap.

Semoga ini membantu.

andrewbuilder
sumber
3

Segit Storyboard tidak boleh dibuat di luar storyboard. Anda harus memasangnya, meskipun ada kekurangannya.

Referensi UIStoryboardSegue dengan jelas menyatakan:

Anda tidak membuat objek segue secara langsung. Alih-alih, runtime storyboard menciptakannya saat harus melakukan pemisahan antara dua pengontrol tampilan. Anda masih dapat memulai segue secara terprogram menggunakan performSegueWithIdentifier: sender: metode UIViewController jika Anda mau. Anda mungkin melakukannya untuk memulai segue dari sumber yang ditambahkan secara terprogram dan karenanya tidak tersedia di Interface Builder.

Anda masih dapat secara programatik menceritakan storyboard untuk menyajikan pengontrol tampilan menggunakan segue using presentModalViewController:atau pushViewController:animated:panggilan, tetapi Anda membutuhkan instance storyboard.

Anda dapat memanggil UIStoryboardmetode kelas untuk mendapatkan storyboard bernama dengan bundel nil untuk bundel utama.

storyboardWithName:bundle:

Cameron Lowell Palmer
sumber
2

Pertama, misalkan Anda memiliki dua tampilan berbeda di storyboard, dan Anda ingin menavigasi dari satu layar ke layar lainnya, jadi ikuti langkah-langkah ini:

1). Tentukan semua tampilan Anda dengan file kelas dan juga storyboard id di inspektur identitas.

2). Pastikan Anda menambahkan pengontrol navigasi ke tampilan pertama. Pilih di Storyboard lalu Editor> Embed In> Navigation Controller

3). Di kelas pertama Anda, impor "secondClass.h"

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

4). Tambahkan perintah ini di IBAction yang harus melakukan segue

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

5). @"second"adalah kelas kontroler pandangan kedua, storyboard id.

Sanket Chauhan
sumber
self.storyboardseharusnya:UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
masipcat
@masipcat dan nama papan cerita mungkin tergantung pada bagaimana Anda mengatur proyek Xcode Anda, di tambang itu adalah "Main.storyboard" jadi saya menggunakanstoryboardWithName:@"Main"
ammianus
@ sanket-chauhan jika pengontrol pertama Anda tidak tertanam dalam Pengontrol Navigasi, Anda juga dapat menampilkan tampilan berikutnya menggunakan [self showDetailViewController:next sender:self];atau[self showViewController:next sender:self];
ammianus
1

Saya merekayasa balik dan membuat implementasi open source (kembali) dari segit UIStoryboard: https://github.com/acoomans/Segway

Dengan perpustakaan itu, Anda dapat mendefinisikan segues secara terprogram (tanpa papan cerita apa pun).

Semoga ini bisa membantu.

acoomans
sumber
0

Beberapa masalah, sebenarnya:

Pertama, dalam proyek yang Anda unggah untuk kami, segue tidak mengandung pengidentifikasi "segue1":

tidak ada pengidentifikasi

Anda harus mengisi pengenal itu jika belum.

Kedua, saat Anda mendorong dari tampilan tabel ke tampilan tabel, Anda memanggil initWithNibName untuk membuat controller tampilan. Anda benar-benar ingin menggunakan instantiateViewControllerWithIdentifier.

jaydip
sumber
0

Berikut ini contoh kode untuk 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()
    }
    ...
}
jqgsninimo
sumber
Anda menelepon self.prepare(for: self.commonSegue, sender: self)dari metode tindakan Anda. Lalu apa gunanya membandingkan if self.commonSegue == segue {...}dalam prepare(for:sender)metode?
nayem
@nayem: Di prepare(for:sender:), Anda dapat mengonfigurasikan pengontrol tampilan tujuan sebelum ditampilkan. Tentu saja Anda juga bisa melakukannya actionFunction.
jqgsninimo
@ nayem: Alasan saya melakukan ini adalah untuk mencoba untuk konsisten dengan penanganan segmen lainnya.
jqgsninimo