İOS uygulamasında en üstteki görünüme / pencereye referans alma


97

Bir iOS uygulamasında bildirimleri görüntülemek için yeniden kullanılabilir bir çerçeve oluşturuyorum. Bildirim görünümlerinin uygulamadaki diğer her şeyin üstüne, bir tür UIAlertView gibi eklenmesini istiyorum. NSNotification olaylarını dinleyen ve yanıt olarak görünümler ekleyen yöneticiyi başlattığımda, uygulamadaki en üst görünüme bir referans almam gerekiyor. Şu anda sahip olduğum şey bu:

_topView = [[[[UIApplication sharedApplication] keyWindow] subviews] lastObject];

Bu, herhangi bir iOS uygulaması için işe yarar mı yoksa üstten görünümü elde etmenin daha güvenli / daha iyi bir yolu mu?

Yanıtlar:


36

Genellikle bu size en iyi görünümü verir, ancak kullanıcı tarafından görülebileceğinin garantisi yoktur. Ekranın dışında olabilir, alfa değeri 0,0 olabilir veya örneğin 0x0 boyutunda olabilir.

Ayrıca keyWindow'da alt görünümler olmayabilir, bu nedenle muhtemelen önce bunu test etmelisiniz. Bu alışılmadık olurdu, ama imkansız değil.

UIWindow, UIView'ın bir alt sınıfıdır, bu nedenle, bildiriminizin kullanıcıya görünür olduğundan emin olmak istiyorsanız, bunu kullanarak doğrudan keyWindow'a ekleyebilir addSubview:ve anında en üstteki görünüm olacaktır. Yine de yapmak istediğin bu mu emin değilim. (Sorunuza göre, bunu zaten biliyormuşsunuz gibi görünüyor.)


111

Her şeyin üzerinde bir kaplama görüntülemek istediğimde, bunu doğrudan Uygulama Penceresinin üstüne eklerim:

[[[UIApplication sharedApplication] keyWindow] addSubview:someView]

9
Yalnızca dikey yönde çalışır .. Döndürmeleri vb.
Önemsemelisiniz

1
(null)İOS-8 uygulamama giriyorum (film şeridi sorunu mu var?) Herhangi bir ipucu var mı? Teşekkürler! (Not: (null)her iki döndü viewDidLoadve viewWillAppear:saati. viewDidAppear:Çok geç.
Olie

Bu bir görünüm denetleyicisi sunduğumuzda çalışır mı? Eklenen alt görünüm sunulan görünüm denetleyicisinde gösterilecek mi?
Pratyusha Terli

Bu klavyenin üstüne çıkmaz, yine de lastObject yapar.
Ser Pounce

Bu çerçeve tüm yönelimlerde çalışabilir. Ve klavyenin üstüne çıkacak. github.com/HarrisonXi/TopmostView
Harrison Xi

47

Sorunun iki bölümü vardır: Üst pencere, üst pencerede üstten görünüm.

Mevcut tüm cevaplar üst pencere bölümünü kaçırdı. Ancak [[UIApplication sharedApplication] keyWindow]en üst pencere olacağı garanti edilmez.

  1. Üst pencere. windowLevelBir uygulama için aynı anda bir arada bulunan iki pencere olması pek olası değildir , bu nedenle tüm pencereleri sıralayabilir windowLevelve en üstteki pencereyi alabiliriz.

    UIWindow *topWindow = [[[UIApplication sharedApplication].windows sortedArrayUsingComparator:^NSComparisonResult(UIWindow *win1, UIWindow *win2) {
        return win1.windowLevel - win2.windowLevel;
    }] lastObject];
  2. Üst pencerede üstten görünüm. Sadece tamamlanmak için. Soruda daha önce belirtildiği gibi:

    UIView *topView = [[topWindow subviews] lastObject];

5
Bu çözüm, UIAlertViews devreye girdiğinde benim için çalışmayı bıraktı - arkalarında boş bir UIWindow bırakıyor gibi görünüyorlar, bu yüzden geri döndümtopView = [[[[UIApplication sharedApplication] keyWindow] subviews] lastObject];
Gereon

4
Klavye yukarıdaysa bu çalışmaz. En üstteki pencere bu olacak gibi
entropy

@Gereon, herhangi bir UIAlertView için güçlü bir referansa sahip olmadığınızdan emin olun. Zayıf bir referans değilse, UIAlertOverlayWindow hala hiyerarşide olacak ve anahtar pencere olarak tanınacaktır, ancak buna eklenen alt görünümler görüntülenmeyecektir.
beebcon

topWindow değeri iOS 8 için uygun değil
Mehul Thakkar

11

Aslında uygulamanızda birden fazla UIWindow olabilir. Örneğin, ekranda bir klavye varsa [[UIApplication sharedApplication] windows], en az iki pencere (anahtar pencereniz ve klavye penceresi) içerecektir.

Dolayısıyla, görüşünüzün her ikisinin üzerinde görünmesini istiyorsanız, o zaman şöyle bir şey yapmalısınız:

[[[[UIApplication sharedApplication] windows] lastObject] addSubview:view];

(LastObject öğesinin en yüksek windowLevel önceliğine sahip pencereyi içerdiğini varsayarsak).


[[[UIApplication sharedApplication] windows] lastObject] değeri, ios 8
Mehul Thakkar

Bunu kullanmaya başladım, ancak bazen klavye penceresi var ama görünmüyor ve sonra görünümüm hiç görüntülenmiyor!
teradyl

3

Tartışma yerine başlıkta belirtildiği gibi soruya bağlı kalıyorum. Herhangi bir noktada hangi görünüm en üstte görünür?

@implementation UIView (Extra)

- (UIView *)findTopMostViewForPoint:(CGPoint)point
{
    for(int i = self.subviews.count - 1; i >= 0; i--)
    {
        UIView *subview = [self.subviews objectAtIndex:i];
        if(!subview.hidden && CGRectContainsPoint(subview.frame, point))
        {
            CGPoint pointConverted = [self convertPoint:point toView:subview];
            return [subview findTopMostViewForPoint:pointConverted];
        }
    }

    return self;
}

- (UIWindow *)topmostWindow
{
    UIWindow *topWindow = [[[UIApplication sharedApplication].windows sortedArrayUsingComparator:^NSComparisonResult(UIWindow *win1, UIWindow *win2) {
        return win1.windowLevel - win2.windowLevel;
    }] lastObject];
    return topWindow;
}

@end

Alıcı olarak herhangi bir UIWindow ile veya alıcı olarak herhangi bir UIView ile doğrudan kullanılabilir.


topWindow, iOS 8 durumunda yanlış değer veriyor, iOS 8 için cevabınızı günceller misiniz?
Mehul Thakkar

1
Bulacak vaktim yok. Eğer yaparsanız, bu yazıyı güncellemekte özgürsünüz.
hfossli

1

Bir yükleme görünümü ekliyorsanız (örneğin bir etkinlik göstergesi görünümü), UIWindow sınıfının bir nesnesine sahip olduğunuzdan emin olun. Yükleme görünümünüzü göstermeden hemen önce bir eylem sayfası gösterirseniz, keyWindowolacaktır UIActionSheetve olmayacaktır UIWindow. Ve işlem sayfası kaybolacağından, yükleme görünümü de onunla birlikte kaybolacaktır. Ya da bana sorun yaratan buydu.

UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
if (![NSStringFromClass([keyWindow class]) isEqualToString:@"UIWindow"]) {
    // find uiwindow in windows
    NSArray *windows = [UIApplication sharedApplication].windows;
    for (UIWindow *window in windows) {
        if ([NSStringFromClass([window class]) isEqualToString:@"UIWindow"]) {
            keyWindow = window;
            break;
        }
    }
}

1

Uygulamanız yalnızca dikey yönde çalışıyorsa, bu yeterlidir:

[[[UIApplication sharedApplication] keyWindow] addSubview:yourView]

Ve görünümünüz klavye ve durum çubuğu üzerinde gösterilmeyecektir.

Klavye veya durum çubuğu üzerinden en üst düzeyde bir görünüm elde etmek istiyorsanız veya en üstteki görünümün cihazlarla doğru şekilde dönebilmesini istiyorsanız, lütfen şu çerçeveyi deneyin:

https://github.com/HarrisonXi/TopmostView

İOS7 / 8 / 9'u destekler.


0

Ekrandaki her şeyin üstüne bir görünüm eklemek istiyorsanız bu kodu kullanın.

[[UIApplication sharedApplication].keyWindow addSubView: yourView];

0

bunu dene

UIWindow *window = [[[UIApplication sharedApplication] windows] lastObject];

Windows özelliği hakkında: "Bu özellik, uygulama için mevcut tüm mevcut pencerelere karşılık gelen bir dizi NSWindow nesnesi içerir. Dizi, herhangi bir alanda görünür olsun veya olmasın, tüm ekran üstü ve ekran dışı pencereleri içerir. Siparişin garantisi yoktur. dizideki pencerelerin "
Steven Fisher

0
UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
if (![NSStringFromClass([keyWindow class]) isEqualToString:@"UIWindow"]) {

    NSArray *windows = [UIApplication sharedApplication].windows;
    for (UIWindow *window in windows) {
        if ([NSStringFromClass([window class]) isEqualToString:@"UIWindow"]) {
            keyWindow = window;
            break;
        }
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.