Soru Objective-C'de kendi UIViewController olan bir alt görünüm nasıl eklenir?


Kendi kendine sahip olan alt görüntülerle uğraşıyorum UIViewControllers. Benim bir UIViewController bir görünümde (açık pembe) ve iki düğmeli toolbar. İlk butona basıldığında mavi ekranın görüntülenmesini ve ikinci tuş ile gösterilecek sarı görüntünün basılmasını istiyorum. Sadece bir görüntüyü görüntülemek istesem kolay olmalı. Fakat mavi görünüm bir tablo içerecektir, bu yüzden kendi denetleyicisine ihtiyacı vardır. Bu benim ilk dersimdi. Ben başladım bu so soru öğrendim ki masa için bir kontrolöre ihtiyacım vardı.

Bu yüzden, ben burada yedekleyip bebek adımlarını atacağım. Aşağıda, Yardımcı Programım ile basit bir başlangıç ​​noktasının resmi var ViewController (ana görünüm denetleyicisi) ve diğer iki denetleyici (mavi ve sarı). Faydalı olunca düşünün ViewController (ana görünüm) ilk görüntülenirken pembe görünümün bulunduğu yerde mavi (varsayılan) görünüm görüntülenir. Kullanıcılar ileri geri gitmek için iki düğmeyi tıklayabilecekler ve pembe görünüm ASLA görüntülenmeyecektir. Sadece mavi görünümün pembe görünümün olduğu yere gitmesini ve pembe görünümün nereye gittiğini göstermesini istiyorum. Umarım bu mantıklı gelir.

Simple Storyboard image

Kullanmaya çalışıyorum addChildViewController. Gördüğüm kadarıyla, bunu yapmanın iki yolu var: storyboard veya addChildViewController programlı. Programlı olarak yapmak istiyorum. Kullanmak istemiyorum NavigationController veya bir Sekme çubuğu. Sadece ilgili butona basıldığında kontrol cihazını eklemek ve doğru görünümü pembe görünüme sokmak istiyorum.

Şimdiye kadar sahip olduğum kod aşağıdadır. Tek yapmak istediğim pembe görünümün olduğu mavi görünümü göstermektir. Gördüğüm kadarıyla sadece addChildViewController ve addSubView. Bu kod benim için bunu yapmıyor. Benim karışıklığım benden daha iyi oluyor. Birisi pembe görünümün görüntülendiği mavi görünümü göstermeme yardımcı olabilir mi?

Bu kod, viewDidLoad'daki mavi görünümü göstermekten başka bir şey yapmak için tasarlanmamıştır.

IDUtilityViewController.h

#import <UIKit/UIKit.h>

@interface IDUtilityViewController : UIViewController
@property (strong, nonatomic) IBOutlet UIView *utilityView;
@end

IDUtilityViewController.m

#import "IDUtilityViewController.h"
#import "IDAboutViewController.h"

@interface IDUtilityViewController ()
@property (nonatomic, strong) IDAboutViewController *aboutVC;
@end

@implementation IDUtilityViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.aboutVC = [[IDAboutViewController alloc]initWithNibName:@"AboutVC" bundle:nil];
    [self addChildViewController:self.aboutVC];
    [self.aboutVC didMoveToParentViewController:self];
    [self.utilityView addSubview:self.aboutVC.aboutView];
}

@end

--------------------------DÜZENLE----------------------- -------

Self.aboutVC.aboutView sıfırdır. Ama ben onu storyboard. Hala bunu başlatmam gerekiyor mu?

enter image description here


44
2018-04-30 22:21


Menşei


Yaşadığınız asıl sorun nedir? - Abhi Beckert
Görünüm yüklendiğinde, pembe görünümü görüyorum. Tahminimce doğru kodlamamalıyım. - Patricia
Tamam peki. Her şeyden önce, bir defada kod bir satır adım ve nesnelerin hiçbiri olmadığından emin olun nil. Specificalyl self.aboutVC, self.utilityView ve self.aboutVC.aboutView. - Abhi Beckert
Haklısın. Self.aboutVC.aboutView sıfırdır. Ama ben her şeyi hikaye tahtasına bağladım. Sorumu görüntü ile güncelleyeceğim. - Patricia
İlk buton nedir ve ikinci düğmen nedir? Ve pembenin bulunduğu mavi ekran deyince ... mavi ekran ekranda olduğunda - hala 'X' ve '?' Manzaranın üstünde asılı mı? - Honey


Cevaplar:


Modern iOS'un ilk günlerinden kalma bu gönderi, genellikle şu anda Swift 4 gibi son sözdizimine sahiptir. İOS, autolayout vb. İle başlıyorsanız, size ulaşacaksınız.

İOS’ta bugün "her şey bir konteyner görünümüdür". Bugün uygulama yapmanın temel yoludur.

Bir uygulama o kadar basit olabilir ki sadece bir görünümü var. Ancak bu durumda bile, ekranda her "şey" bir konteyner görünümüdür.

Bu kolay ...


(A) Bir konteyner görünümünü sahneye sürükleyin ...

Bir konteyner görünümünü sahne görünümünüze sürükleyin. (Tıpkı bir UIButton'a girdiğiniz gibi.)

Konteyner görüntüsü, bu görüntüdeki kahverengi şeydir. Aslında içeride sizin sahne görünümü

enter image description here

Bir konteyner görünümünü sahne görünümünüze sürüklediğinizde, Xcode otomatik olarak size verir. iki şey:

  1. Konteyner görünümünü olsun sahne görünümünde, ve,

  2. yepyeni UIViewController hangisi sadece hikaye tahtasının beyazında bir yerde oturmak.

İkisi bağlı "Masonik Sembol" şeyiyle - aşağıda açıklanmıştır!


(B) Bu yeni görüntü denetleyicisini tıklayın (Xcode, sizin için beyaz alanda bir yerde yaptığınız yeni şey, senin sahnenin içindeki şey değil) ... ve sınıfı değiştir!

Gerçekten bu kadar basit.

Sen bittin.


İşte görsel olarak aynı şey açıklandı.

Dikkat edin konteyner görünümü en (A).

Dikkat edin kontrolör en (B).

shows a container view and the associated view controller

B'ye tıklayın (Bu B - A değil!)

Sağ üstteki denetçiye git. "UIViewController" yazdığına dikkat edin

[enter image description here] [3]

Bir UIViewController olan kendi özel sınıfınıza değiştirin.

enter image description here

Yani, bir Swift sınıfım var Snap hangisi UIViewController.

enter image description here

Yani Müfettiş "UIViewController" yazdığı yerde "Snap" yazdım.

(Her zamanki gibi, Xcode "Snap ..." yazarken "Snap" işlemini otomatik olarak tamamlayacaktır.)

Hepsi bu kadar var - işiniz bitti.


Kapsayıcı görünüm nasıl değiştirilir - bir tablo görünümüne.

Bir kapsayıcı görünüm eklemek için tıkladığınızda, Apple otomatik olarak size film şeridinde oturan bağlantılı bir görünüm denetleyicisi verir.

Olduğu gibi (2017): bunu yapar UIViewController varsayılan olarak.

Bu aptalca: ihtiyacınız olan türü sormalı. Örneğin, çoğu zaman bir tablo görünümüne ihtiyacınız vardır. Bunu farklı bir şeye nasıl değiştireceğiniz aşağıda açıklanmıştır:

Yazarken, Xcode size bir UIViewController varsayılan olarak. Diyelim ki bir UICollectionViewController yerine:

(i) Bir konteyner görünümünü sahnenize sürükleyin. Xcode'un size varsayılan olarak verdiği film şeridindeki UIViewController'a bakın.

(ii) Yeni bir sürükle UICollectionViewController Film şeridinin ana beyaz alanındaki herhangi bir yere.

(iii) Sahnenin içindeki konteyner görünümünü tıklayın. Bağlantı denetçisine tıklayın. Bir "Tetiklemiş Segue" olduğuna dikkat edin. Fare bitti "Tetiklenmiş Segue" ve Xcode'a dikkat edin vurgular tüm istenmeyen UIViewController.

(iv) "x" i tıkladığınızda silmek Bu tetikledi Segue.

(V) Dan sürükleyin Tetiklenen Segue (viewDidLoad tek seçenek). Hikaye panosunu yeni UICollectionViewController'ınıza sürükleyin. Bırak gidip bir pop-up görünür. Seçmelisiniz Göm.

(vi) Basitçe silmek tüm istenmeyen UIViewController. Sen bittin.

Kısa versiyon: istenmeyen UIViewController'ı silin. Yeni koy UICollectionViewController film şeridinde. Kontrol sürükleyin: konteyner görünümünün Bağlantıları - Tetik Segue - viewDidLoad, yeni kontrol cihazınıza. Açılır pencerede "yerleştir" seçeneğini seçtiğinizden emin olun.


Metin tanıtıcısını giriliyor ...

Bunlardan birine sahip olacaksın "kare kare" Masonik semboller şeyler: konteyner görünümünüzü görünüm kontrolörü ile birleştiren "bendy çizgisi" üzerindedir.

"Masonik sembol" şey segue.

enter image description here

Tıklayarak segue seçin üzerinde "masonik sembol" şey.

Sağa bak.

Sen MUST yazın metin tanımlayıcısı segue için.

İsme karar verdin. Herhangi bir metin dizesi olabilir. Mantıklı bir seçim genellikle "segueClassName" dir.

Bu modeli takip ederseniz, tüm segues, segueClockView, seguePersonSelector, segueSnap, segueCards vb.

Ardından, bu metin tanımlayıcısını nerelerde kullanıyorsunuz?


Çocuk denetleyicisine nasıl bağlanır ...

Ardından, kodun tamamını, tüm sahnenin ViewController bölümünde yapın.

Diyelim ki sahnede üç konteyner manzarası var. Her konteyner görünümü farklı bir kontrolöre sahiptir, "Snap", "Clock" ve "Other" deyin.

En son Swift3 sözdizimi (2017)

var snap:Snap?
var clock:Clock?
var other:Other?

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if (segue.identifier == "segueSnap")
            { snap = (segue.destination as! Snap) }
    if (segue.identifier == "segueClock")
            { clock = (segue.destination as! Clock) }
    if (segue.identifier == "segueOther")
            { other = (segue.destination as! Other) }
}

Bu kadar basit. Denetleyicilere başvurmak için bir değişken bağlayabilirsiniz. prepareForSegue aramak.


Ebeveyne kadar 'diğer yönde' nasıl bağlanır ...

Kapsayıcı görünümde koyduğunuz denetleyicide "içeri" olduğunuzu varsayalım (örnekte "Snap").

Yukarıdaki "patron" görüntü denetleyicisine ulaşmak için kafa karıştırıcı olabilir (örnekte "Dash"). Neyse ki, bu basit:

// Dash is the overall scene.
// Here we are in Snap. Snap is one of the container views inside Dash.

class Snap {

var myBoss:Dash?    
override func viewDidAppear(_ animated: Bool) { // MUST be viewDidAppear
    super.viewDidAppear(animated)
    myBoss = self.parent as? Dash
}

Kritik: Sadece çalışır viewDidAppear veya daha sonra. İşe yaramaz viewDidLoad.

Sen bittin.


Önemli: bu bir tek konteyner görünümleri için çalışır.

Önemli gelişmiş ipucu: Unutmayın, bu sadece kapsayıcı görünümler için çalışır.

Film şeridi tanımlayıcıları olan bu günlerde, ekranda yeni görünümler yayınlamak oldukça yaygındır (Android geliştirmede olduğu gibi). Öyleyse kullanıcının bir şeyi düzenlemek istediğini varsayalım.

    // let's just pop a view on the screen.
    // this has nothing to do with container views
    //
    let e = ...instantiateViewController(withIdentifier: "Edit") as! Edit
    e.modalPresentationStyle = .overCurrentContext
    self.present(e, animated: false, completion: nil)

Konteyner görünümü kullanırken, BT GARANTİLİ Dash, Snap'in ana görünüm denetleyicisi olacak.

Ancak bu OLMAYAN DURUMDA DEĞİL instantiateViewController kullandığınızda.

Çok kafa karıştırıcı, iOS'ta ana görünüm denetleyicisi alakasız bunu başlatan sınıfa. (O belki aynı olmak, ama genellikle aynı değildir.) self.parent desen bir tek konteyner görünümleri için.

(InstantiateViewController modelinde benzer bir sonuç için, bir temsilci ve zayıf bir bağlantı olacağını hatırlayarak bir temsilci ve bir temsilci kullanmanız gerekir.)


prepareForSegue kötü adlandırılmış ...

"PrepareForSegue" nin bir Gerçekten kötü isim!

"prepareForSegue", iki amaç için kullanılır: konteynır görünümlerini yükleme ve sahneler arasında gezinme.

Ama pratikte sen sahneler arasında çok nadir görülür! Oysa neredeyse her uygulamanın bir çok, çok sayıda kapsayıcı görünümü var.

"PrepareForSegue" "loadingContainerView" gibi bir şey çağrıldığında daha mantıklı olur.


Birden fazla...

Yaygın bir durum: Ekranda, farklı görüntü denetleyicilerinden birini göstermek istediğiniz küçük bir alanınız var. Örneğin, dört widget’tan biri.

Bunu yapmanın en basit yolu: sadece dört farklı konteyner manzarası hepsi otururken aynı özdeş alan. Kodunuzda, sadece dördünü gizleyin ve görünür olmasını istediğinizi açın.

Hikaye panosunda, sadece dört konteyner görünümünü tutan bir boş "tutucu" UIView var. Daha sonra, "tutucu" 'yı boyutlandırarak veya taşıyarak dörtlü tümünü aynı anda boyutlandırabilir veya taşıyabilirsiniz. Kodunda sadece dört tane var UIView çıkışlar, konteyner görünümlerinin her biri için bir tane. İçindeki dört görüntü denetleyicisini bağlamak için yukarıdaki kodu kopyalayın ve "Alt denetleyiciye nasıl bağlanır" bölümüne yapıştırın.


Not - Storyboard Referansları geliyor!

SimplGy'nin altını çizdiği gibi "iOS 9’lar Storyboard Referansları konteyner görünümlerini daha da harika hale getirin. Yeniden kullanılabilir görünümünüzü (denetleyici) istediğiniz yerde tanımlayabilir ve çoklu, modüler öykülerde herhangi bir kapsayıcı görünümden referans alabilirsiniz.

Çok fazla kafa karıştırıcı bir şekilde - çok dikkat edin - genellikle bugün konteyner manzarası ile uğraşmayın!

Sen sadece instantiateViewController#withIdentifier birçok durumda.

Ama "gotchya" hakkında .parent yukarıda açıklanmıştır. Kapsayıcı görünümlerin tüm noktası, anında ve basitçe ebeveyn zincirinin güvencenizdir.

Eğer ile gitmek instantiateViewController#withIdentifier Bir storyboard referansı kullanarak, bir protokol ve bir delege ile etrafa dağılmanız gerekir (delegenin zayıf bir link olacağını hatırlayarak). Ama sonra her yerde esnek bir şekilde "anında" kullanabilirsiniz.

Bunun aksine, bir "sabit", yani konuşmak için, konteyner görünümü son derece basittir ve yukarıda açıklandığı gibi ebeveyn ve çocuk arasında hemen bağlantı kurarsınız.


117
2018-05-01 07:49



Ofise girdiğimde bunu deneyeceğim. Teşekkür ederim. Ben hala AWESOME olduğunu düşünüyorum! :-) - Patricia
O zaman bir seferde bir adım atalım! - Fattie
Komiksin Joe. Bu benim Lanetli sorunumu bir Konteyner Görünümü kullanarak çözer. :-) Ben kodda bunu yapmak istedim çünkü daha önce kodda yaptım (bir kez .... ve bir yıl önce). Hikaye panosunu kullanarak herkes gibi başladım. Eski iş arkadaşlarım, Sr. iOS geliştiricileriydi ve çok fazla penceremiz olduğu için film şeridini kullanmak istemiyorlardı. Öyleyse, hikaye tahtaları ve inançları konusundaki tecrübelerim çok zayıf. Son zamanlarda, AVFoundation ve kamera kontrolleri ve DEĞİL UI şeyler ile çalışıyorum. Çevrenizde dolaştığınızda, temelleri unutmak kolaydır. - Patricia
Masonik sembolü şeyinde küçük "kare kare" ile biraz daha yardıma ihtiyacım var !!! :-) - Patricia
iOS 9’lar Storyboard Referansları konteyner görünümlerini daha da harika hale getirin. Yeniden kullanılabilir görünümünüzü (denetleyici) istediğiniz yerde tanımlayabilir ve çoklu, modüler storyboardlarda herhangi bir kapsayıcı görünümden referans alabilirsiniz. - SimplGy


İki problem görüyorum. Öncelikle, denetleyicileri film şeridinde yaptığınız için bunları örneklerle oluşturmalısınız. instantiateViewControllerWithIdentifier:, değil initWithNibName:bundle:. İkinci olarak, görünümü bir alt görünüm olarak eklediğinizde, ona bir çerçeve vermelisiniz. Yani,

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.aboutVC = [self.storyboard instantiateViewControllerWithIdentifier:@"aboutVC"]; // make sure you give the controller this same identifier in the storyboard
    [self addChildViewController:self.aboutVC];
    [self.aboutVC didMoveToParentViewController:self];
    self.aboutVC.view.frame = self.utilityView.bounds;
    [self.utilityView addSubview:self.aboutVC.aboutView];
}

4
2018-05-01 04:09



Çerçeve gerekli mi? ya da görüntüyü storyboard'a göre varsayılan bir çerçeve verecek? - Brian
@Brian, eklediğiniz görünüm tam ekran ise, muhtemelen gerekli değildir, ancak genellikle emin olmak için herhangi bir şekilde ekleyin. Ayrıca, bu durumda, self.utilityView tam görünüm veya araç çubuğunun altındaki görünümün parçası olup olmadığından emin değildim, bu durumda, muhtemelen çerçeveyi ayarlamak gerekir. - rdelmar
% 100 gerekli değil, bu hikaye tahtası çocuklar için! - Fattie
@rdelmar - Bilgileriniz için teşekkür ederiz. Ben instantiateViewControllerWithIdentifier kullanmalıyım ama biraz karışık mı merak ettim. Ayrıca, evet, self.utilityView tam görünüm değil. 3 yorumun hepsi aynı boyuttadır, bu yüzden çerçeve boyutunu ayarlamam gerektiğini düşünmemiştim. Ofise girdiğimde öneriyi deneyeceğim. - Patricia
@JoeBlow, OP hikaye tahtasında bir kapsayıcı görünümü kullanmasından bahsetmişti, ancak kodda bunu yapmak istediklerini söyledi. - rdelmar