получение ссылок на самый верхний вид/окно в приложении ios

<p>я создаю многоразовую платформу для отображения уведомлений в приложении ios. мне бы хотелось, чтобы представления уведомлений добавлялись поверх всего остального в приложении, что-то вроде uialertview. когда я запускаю менеджер, который прослушивает события nsnotification и добавляет представления в ответ, мне нужно получить ссылку на самый верхний вид в приложении. вот что у меня на данный момент:</p><pre><code>\_topview = [[[[uiapplication sharedapplication] keywindow] subviews] lastobject]; </code></pre><p>будет ли это работать для любого приложения ios или это более безопасный/лучший способ получить вид сверху?</p>

<p>обычно это дает вам вид сверху, но нет никакой гарантии, что он виден пользователю. он может быть вне экрана, иметь альфа 0.0 или иметь размер 0x0, например.</p><p>может также случиться так, что у keywindow нет подпредставлений, поэтому вам, вероятно, следует сначала проверить это. это было бы необычно, но это не невозможно.</p><p>uiwindow является подклассом uiview, поэтому, если вы хотите убедиться, что ваше уведомление является видимым для пользователя, вы можете добавить его непосредственно в keywindow с помощью <code>addsubview:</code>, и оно сразу станет самым верхним видом. я не уверен, что это то, что вы хотите сделать, хотя. (исходя из вашего вопроса, похоже, вы уже знаете это.)</p>

<p>всякий раз, когда я хочу отобразить какое-либо наложение поверх всего остального, я просто добавляю его поверх окна приложения напрямую:</p><pre><code>[[[uiapplication sharedapplication] keywindow] addsubview:someview] </code></pre>

<p>есть две части проблемы: верхнее окно, вид сверху на верхнее окно.</p><p>все существующие ответы не попали в верхнюю часть окна. но <code>[[uiapplication sharedapplication] keywindow]</code> не обязательно будет верхним окном.</p><ol> <li><p>верхнее окно. маловероятно, что для приложения будут сосуществовать два окна с одинаковым <code>windowlevel</code>, поэтому мы можем отсортировать все окна по <code>windowlevel</code> и получить самое верхнее.</p> <pre><code>uiwindow *topwindow = [[[uiapplication sharedapplication].windows sortedarrayusingcomparator:^nscomparisonresult(uiwindow *win1, uiwindow *win2) { return win1.windowlevel - win2.windowlevel; }] lastobject]; </code></pre></li> <li><p>вид сверху в верхнем окне. просто чтобы быть полным. как уже указывалось в вопросе:</p> <pre><code>uiview *topview = [[topwindow subviews] lastobject]; </code></pre></li> </ol>

<p>на самом деле в вашем приложении может быть более одного uiwindow. например, если на экране есть клавиатура, то <code>[[uiapplication sharedapplication] windows]</code> будет содержать как минимум два окна (ваше окно клавиш и окно клавиатуры).</p><p>так что, если вы хотите, чтобы ваш вид отображался поверх них обоих, вам нужно сделать что-то вроде:</p><pre><code>[[[[uiapplication sharedapplication] windows] lastobject] addsubview:view]; </code></pre><p>(предполагая, что lastobject содержит окно с наивысшим приоритетом windowlevel).</p>

<p>я придерживаюсь вопроса, как говорится в названии, а не в обсуждении. какой вид виден сверху в любой заданной точке? </p><pre><code>@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 </code></pre><p>может использоваться напрямую с любым uiwindow в качестве получателя или любым uiview в качестве получателя.</p>

<p>если ваше приложение работает только в портретной ориентации, этого достаточно:</p><pre><code>[[[uiapplication sharedapplication] keywindow] addsubview:yourview] </code></pre><p>и ваш вид не будет отображаться над клавиатурой и строкой состояния.</p><p>если вы хотите получить самый верхний вид, который через клавиатуру или строку состояния, или вы хотите, чтобы самый верхний вид мог корректно вращаться на устройствах, попробуйте следующую структуру:</p><p> <a href="https://github.com/harrisonxi/topmostview">https://github.com/harrisonxi/topmostview</a> </p><p>поддерживает ios7/8/9.</p>

<p>если вы добавляете представление загрузки (например, представление индикатора активности), убедитесь, что у вас есть объект класса uiwindow. если вы покажете лист действий непосредственно перед тем, как отобразить представление загрузки, <code>keywindow</code> будет <code>uiactionsheet</code>, а не <code>uiwindow</code>. и поскольку лист действий исчезнет, представление загрузки исчезнет вместе с ним. или это то, что вызывало у меня проблемы.</p><pre><code>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; } } } </code></pre>

<p>попробуй это</p><pre><code>uiwindow *window = [[[uiapplication sharedapplication] windows] lastobject]; </code></pre>

<p>просто используйте этот код, если вы хотите добавить вид выше всего на экране.</p><pre><code>[[uiapplication sharedapplication].keywindow addsubview: yourview]; </code></pre>