2012-01-05 2 views
19

Я создаю пользовательский макет popover, который предоставляет iOS. Я подклассифицировал UIPopoverBackgroundView и получил его, чтобы правильно рисовать фон для моего popover. Моя проблема в том, что UIPopoverController создает внутреннюю тень на popover, влияющую на contentViewController popover. Я хочу удалить эту внутреннюю тень, поэтому отображается только контент моего ContentViewController.Удалить внутреннюю тень, создаваемую UIPopoverController

Вот как выглядит popover в настоящее время, с UILabel, чтобы продемонстрировать влияние на ContentViewController.

popover

Есть ли способ, чтобы удалить эту внутреннюю тень?

+0

Посмотрите ответ kajham, поскольку iOS 6 должен быть принятым ответом. –

ответ

25

поддержки этого было добавлено в ios6.0 со следующим вызовом:

+ (BOOL)wantsDefaultContentAppearance

Ссылка на документацию: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIPopoverBackgroundView_class/Reference/Reference.html

+0

Это должен быть принятый ответ. –

+4

это не работает для меня .. У меня есть подкласс UIPopoverBackgroundView, переопределенный метод и ничего. там тени там .. любая помощь ?? – Frade

+0

@Frade вам нужно переопределить и не называть 'super' в методе' - (void) layoutSubviews' (я нашел его здесь: http://stackoverflow.com/questions/10044227/custom-uipopoverbackgroundview-no-drop -shadow # comment27674273_12684634) – derpoliuk

1

Я не считаю, что есть элегантный/поддерживаемый способ достижения этого с помощью стандартного UIPopover от Apple. Однако вы можете легко создать свой собственный класс popover. Существует немало примеров того, как сделать это как здесь, так и в учебниках по более широкой сети (даже несколько готовых к загрузке решений). Просто поместите «пользовательский uipopover» в Google ...

+0

Да, хорошо. Я просто подумал, что было бы неплохо по-настоящему настроить внешний вид UIPopover. Поскольку Apple представила некоторые возможности настройки с помощью UIPopoverBackgroundView, я просто подумал, что можно реально изменить способ просмотра UIPopover. – Sorig

+0

Это не тот случай. Повторное внедрение popovers по всему месту - плохая идея. –

+1

@BenLachman Помогите рассказать нам, почему? В вопросе ничего не говорится о «повсюду». Скорее, он описывает, что ему нужно, и спрашивает, подходит ли объект UIKit. В то время это не так. Нет абсолютно никакой причины, почему катит ваш собственный элемент в этом случае - плохая идея внутри себя и сама. – isaac

10

Поскольку нет такого элегантного способа сделать это, и так как я не хочу переписывать весь UIPopoverController только для этого, я создал простой хак, который удаляет внутренняя тень на popover путем перемещения структуры UIView. Хак является категорией в UIPopoverController, и я просто помещаю его в файлы для моего подкласса UIPopoverBackgroundView. Так вот код:

@interface UIPopoverController(removeInnerShadow) 

- (void)removeInnerShadow; 
- (void)presentPopoverWithoutInnerShadowFromRect:(CGRect)rect 
              inView:(UIView *)view 
         permittedArrowDirections:(UIPopoverArrowDirection)direction 
             animated:(BOOL)animated; 

- (void)presentPopoverWithoutInnerShadowFromBarButtonItem:(UIBarButtonItem *)item 
           permittedArrowDirections:(UIPopoverArrowDirection)arrowDirections 
               animated:(BOOL)animated; 

@end 

@implementation UIPopoverController(removeInnerShadow) 

- (void)presentPopoverWithoutInnerShadowFromRect:(CGRect)rect inView:(UIView *)view permittedArrowDirections:(UIPopoverArrowDirection)direction animated:(BOOL)animated 
{ 
    [self presentPopoverFromRect:rect inView:view permittedArrowDirections:direction animated:animated]; 
    [self removeInnerShadow]; 
} 

- (void)presentPopoverWithoutInnerShadowFromBarButtonItem:(UIBarButtonItem *)item 
           permittedArrowDirections:(UIPopoverArrowDirection)arrowDirections 
               animated:(BOOL)animated 
{ 
    [self presentPopoverFromBarButtonItem:item permittedArrowDirections:arrowDirections animated:animated]; 
    [self removeInnerShadow]; 
} 

- (void)removeInnerShadow 
{ 
    UIWindow *window = [[[UIApplication sharedApplication] delegate] window]; 

    for (UIView *windowSubView in window.subviews) 
    { 
     if ([NSStringFromClass([windowSubView class]) isEqualToString:@"UIDimmingView"]) 
     { 
      for (UIView *dimmingViewSubviews in windowSubView.subviews) 
      { 
       for (UIView *popoverSubview in dimmingViewSubviews.subviews) 
       { 
        if([NSStringFromClass([popoverSubview class]) isEqualToString:@"UIView"]) 
        { 
         for (UIView *subviewA in popoverSubview.subviews) 
         { 
          if ([NSStringFromClass([subviewA class]) isEqualToString:@"UILayoutContainerView"]) 
          { 
           subviewA.layer.cornerRadius = 0; 
          } 

          for (UIView *subviewB in subviewA.subviews) 
          { 
           if ([NSStringFromClass([subviewB class]) isEqualToString:@"UIImageView"]) 
           { 
            [subviewB removeFromSuperview]; 
           } 
          } 
         } 
        } 
       } 
      } 
     } 
    } 
} 

@end 

Когда я хочу показать мой поповер я просто называю presentPopoverWithoutInnerShadowFromRect: и presentPopoverWithoutInnerShadowFromBarButtonItem: методы вместо стандартных. ПРИМЕЧАНИЯ: Не забудьте #import <QuartzCore/QuartzCore.h> для кода для работы

+0

Если у меня есть UITableView внутри popover, угловые маски появляются при прокрутке. Любая идея, если есть способ обойти это? – bromanko

+0

Вы можете использовать «removeInnerShadow», чтобы удалить угловые маски и тень от popover. Попробуйте поиграть с ним. Вы можете постоянно нажимать «removeInnerShadow» во время прокрутки или, возможно, вы можете искать способ остановить прокрутку от добавления угловых масок снова. – Sorig

+0

Выключает также настройку цвета фона: 'subviewA.layer.backgroundColor = [UIColor clearColor] .CGColor;' – bromanko

10

I juest создал мою собственную версию для проекта, над которым я работаю.

В основном вы должны использовать свой собственный backgroundClass для пирог и в этом классе вы должны определить:

- (void)willMoveToWindow:(UIWindow *)newWindow { 
   [super willMoveToWindow:newWindow]; 
   if ([UIPopoverBackgroundView respondsToSelector:@selector(wantsDefaultContentAppearance)]) 
       return; 

   if (![[self class] wantsDefaultContentAppearance]) { 
       for (UIView *view in self.superview.subviews) { 
           for (UIView *subview in view.subviews) { 
               if (subview.layer.cornerRadius != 0.0) { 
                  subview.layer.cornerRadius = 0.0; 
                   for (UIView *subsubview in subview.subviews) { 
                       if (subsubview.class == [UIImageView class]) 
                           subsubview.hidden = YES; 
                   } 
               } 
           } 
       } 
   } 
} 

Должен быть в значительной степени пуленепробиваемым для обновления IOS.

+1

Это прекрасно работает с popOvers для представлений, которые не встроены в NavigationControllers. Как только ViewController (который встроен в NavigationController) используется для popover, тень возвращается снова. Есть ли какие-либо решения? – FrankZp

+0

#FrankZP Ищите модификацию ниже. –

+0

+1 хороший обходной путь! Один вопрос: не могли бы вы немного объяснить, почему нужно отправлять сообщение в '[self class]' (которое является «objc_class')? – matm

0

Для FrankZp

Это прекрасно работает с Popovers для представлений, которые не встроены в NavigationControllers. Как только ViewController (то есть , встроенный в NavigationController), используется для popover. тень снова возвращается. Есть ли какие-либо решения?

Вот модификация для UINavigationController:

- (void)removeInnerShadow 
{ 
    UIWindow *window = [[[UIApplication sharedApplication] delegate] window]; 

    for (UIView *windowSubView in window.subviews) { 
     if ([NSStringFromClass([windowSubView class]) isEqualToString:@"UIDimmingView"] { 
      for (UIView *dimmingViewSubviews in windowSubView.subviews) { 
       for (UIView *popoverSubview in dimmingViewSubviews.subviews) { 
        if([NSStringFromClass([popoverSubview class]) isEqualToString:@"UIView"]) { 
         for (UIView *subviewA in popoverSubview.subviews) { 
          if ([NSStringFromClass([subviewA class]) isEqualToString:@"UILayoutContainerView"]) { 
           subviewA.layer.cornerRadius = 0; 
          } 

          for (UIView *subviewB in subviewA.subviews) { 
           if ([NSStringFromClass([subviewB class]) isEqualToString:@"UILayoutContainerView"]) { 
            for (UIView * subviewC in subviewB.subviews) { 
             if ([NSStringFromClass([subviewC class]) isEqualToString:@"UIImageView"]) { 
              [subviewC removeFromSuperview]; 
             } 
            } 
           } 

           if ([NSStringFromClass([subviewB class]) isEqualToString:@"UIImageView"]) { 
            [subviewB removeFromSuperview]; 
           } 
          } 
         } 
        } 
       } 
      } 
     } 
    } 
} 
3

Хотя я согласен в принципе, что правильный способ справиться с этим свернуть свой собственный поповер, в данном случае это не проблема для более новые версии ОС. Действительно ли я хочу создавать и поддерживать собственную реализацию popover только для поддержки ОС, которая в конечном итоге будет неактуальной? Если вы действительно хотите, рассмотрите некоторые из бесплатных версий с открытым исходным кодом в Интернете.

Лично я исследовал предложенные здесь методы и придумал свои собственные, используя эту страницу в качестве отправной точки (спасибо!). Он работает для обоих сценариев (с навигационной панелью или без нее) и, на мой взгляд, немного безопаснее.

Вместо добавления метода в UIPopoverController я добавил подпрограмму в свой UIPopoverBackgroundView, чтобы искать нарушающие представления, используя маршрут RELATIVE, а не ABSOLUTE. Короче говоря, поскольку код имеет прямую ссылку на UIPopoverBackgroundView (self), он может перемещаться вверх (супервизор), а затем вниз (subviews).

точка зрения деревьев выглядеть в обоих сценариях:

С UINavigationBar: enter image description here

Без UINavigationBar: enter image description here

Эти две точки зрения, что мы заинтересованы в являются Представления UILayoutView и UIImage, выделенные жирным шрифтом и подчеркнутые в каждом графике. Мы можем получить ссылку на них, начиная с UIPopoverBackgroundView, используя следующий код (предполагает ARC). Я выполняю это с layoutSubviews в моей реализации UIPopoverBackgroundView.

// Helper method for traversing child views based solely on class types 
UIView* (^__unsafe_unretained __block traverseSubviews)(UIView*, NSArray*) = ^(UIView *root, NSArray* nodeTypes) { 
    NSString *typeName = [nodeTypes objectAtIndex:0]; 
    for (UIView *subView in root.subviews) { 
     if ([NSStringFromClass([subView class]) isEqualToString: typeName]) { 
      if (nodeTypes.count == 1) 
       return subView; 
      else 
       return traverseSubviews(subView, [nodeTypes subarrayWithRange:NSMakeRange(1, nodeTypes.count - 1)]); 
     } 
    } 
    return (UIView*)nil; 
}; 

// Find the subviews of interest, taking into account there could be a navigation bar 
UIView *layoutView = traverseSubviews([self superview], @[@"UIView", @"UILayoutContainerView"]); 
if (traverseSubviews(layoutView, @[@"UINavigationBar"])) { 
    layoutView = traverseSubviews(layoutView, @[@"UILayoutContainerView"]); 
} 
UIView *imageView = traverseSubviews(layoutView, @[@"UIImageView"]); 

// Remove the default content appearance 
layoutView.layer.cornerRadius = 0; 
[imageView removeFromSuperview]; 

Здесь я использую блок для прохождения обходных объектов, чтобы код был кратким. Он принимает представление как отправную точку и массив имен классов. Массив классных имен - это последовательность классов классов, которые я ожидаю, когда индекс 0 является родительским индексом 1, а индекс 1 является родительским элементом индекса 2 и т. Д. Он возвращает представление, представленное последним элементом массива.

+0

Вы должны добавить условие, чтобы не делать этого в iOS 6+ и просто возвращать 'NO' из' хочетDefaultContentAppearance'. –

+0

+1 для детального схематического объяснения. Можете ли вы также рассказать, как настроить размер границы UIPopover? – HDdeveloper

+0

Вы имеете в виду внешнюю границу? Я использовал UIPopoverBackgroundView для использования изображений, чтобы указать внешний вид popover. Если вы имеете в виду внутреннюю границу, я просто удалил ее. Реализация по умолчанию использует UIImageView, поэтому вам придется заменить изображение, если вы просто хотите изменить границу. –

 Смежные вопросы

  • Нет связанных вопросов^_^