2012-01-05 7 views
19

बनाता है जो आंतरिक छाया को हटाएं IOS जो आईओएस प्रदान करता है उस पॉपओवर का कस्टम लेआउट बना रहा हूं। मैंने UIPopoverBackgroundView को उप-वर्गीकृत किया है और इसे मेरे पॉपओवर के लिए पृष्ठभूमि को सही तरीके से आकर्षित करने के लिए मिला है। मेरी समस्या यह है कि UIPopoverController पॉपओवर की सामग्री व्यू कंट्रोलर को प्रभावित करने वाले पॉपओवर पर एक आंतरिक छाया बनाता है। मैं इस आंतरिक छाया को हटाना चाहता हूं, इसलिए केवल मेरी सामग्री की सामग्री दृश्य नियंत्रक प्रदर्शित होता है।UIPopoverController

इस प्रकार पॉपअप वर्तमान में यूआईएलएबल के साथ सामग्री व्यू कंट्रोलर पर प्रभाव प्रदर्शित करने के लिए दिखता है।

popover

इस भीतरी छाया दूर करने के लिए कोई तरीका है?

+0

आईओएस 6 के लिए कजाम का जवाब देखें, स्वीकार्य उत्तर होना चाहिए। –

उत्तर

25

समर्थन #import <QuartzCore/QuartzCore.h> के लिए याद रखें निम्नलिखित कॉल के साथ ios6.0 में जोड़ा गया:

+ (BOOL)wantsDefaultContentAppearance

प्रलेखन के लिए लिंक: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIPopoverBackgroundView_class/Reference/Reference.html

+0

यह स्वीकार्य उत्तर होना चाहिए। –

+4

यह मेरे लिए काम नहीं करता है .. मेरे पास UIPopoverBackgroundView का सबक्लास है, विधि को ओवरराइड किया गया है, और कुछ भी नहीं। छाया अभी भी वहाँ है .. कोई मदद ?? कृपया – Frade

+0

@ फ़्रेड आपको ओवरराइड करने की आवश्यकता है और 'सुपर' को '- (शून्य) लेआउट में कॉल न करें Subviews विधि (मुझे यह यहां मिला: http://stackoverflow.com/questions/10044227/custom-uipopoverbackgroundview-no-drop -शैडो # टिप्पणी 27674273_12684634) – derpoliuk

1

मुझे विश्वास नहीं है कि ऐप्पल के मानक यूआईपीओवरोवर का उपयोग करने के लिए एक सुरुचिपूर्ण/समर्थित तरीका है। हालांकि, आप अपनी खुद की कस्टम पॉपओवर कक्षा को काफी आसानी से बना सकते हैं। व्यापक वेब पर कुछ और ट्यूटोरियल पर भी ऐसा करने के कुछ उदाहरण हैं (यहां तक ​​कि कुछ तैयार-टू-डाउनलोड समाधान)। बस Google में 'कस्टम यूपोपॉवर' डालें ...

+0

हाँ ठीक है। मैंने सोचा कि यूआईपीओवर की उपस्थिति को वास्तव में अनुकूलित करने में सक्षम होना अच्छा होगा। चूंकि ऐप्पल ने यूआईपीओपॉवरबैकग्राउंड व्यू के साथ कुछ अनुकूलन क्षमताओं की शुरुआत की, मैंने सोचा कि वास्तव में यूआईपीओपॉवर के तरीके को बदलना संभव हो सकता है। – Sorig

+0

यह मामला नहीं है। पूरे स्थान पर पॉपओवर को पुन: कार्यान्वित करना एक बुरा विचार है। –

+1

@ बेन लांचमैन हमें बताएंगे क्यों? प्रश्न "पूरे स्थान पर" के बारे में कुछ भी नहीं कहता है। इसके बजाय, वह वर्णन करता है कि उसे क्या चाहिए, और पूछता है कि क्या UIKit ऑब्जेक्ट की आवश्यकता है। उस समय यह नहीं था। इस मामले में अपना खुद का तत्व रोल करने का कोई कारण नहीं है कि यह एक बुरा विचार है। – isaac

10

चूंकि ऐसा करने का कोई शानदार तरीका नहीं है और चूंकि मैं इसे पूरा करने के लिए पूरे यूआईपीओवर कंट्रोलर को फिर से लिखना नहीं चाहता हूं, इसलिए मैंने एक साधारण हैक बनाया है जो हटा देता है 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: तरीकों कहते हैं। नोट: कोड काम करने के लिए इस बात के लिए

+0

यदि मेरे पास पॉपओवर के अंदर UITableView है, तो स्क्रॉल करते समय कोने मास्क दिखाई देते हैं। अगर कोई इस बारे में काम करने का कोई तरीका है तो कोई विचार? – bromanko

+0

आप पॉपओवर के कोने मास्क और छाया को हटाने के लिए "removeInnerShadow" का उपयोग कर सकते हैं। इसके साथ खेलने का प्रयास करें। स्क्रॉल करते समय आप लगातार "removeInnerShadow" को आजमा सकते हैं और कॉल कर सकते हैं या शायद आप फिर से कोने मास्क जोड़ने से स्क्रॉलिंग को रोकने के लिए एक तरीका ढूंढ सकते हैं। – Sorig

+0

पृष्ठभूमि रंग को भी सेट करने में मदद करता है: 'subviewA.layer.backgroundcolor = [UIColor clearcolor] .CGColor;' – bromanko

10

मैं 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; 
                   } 
               } 
           } 
       } 
   } 
} 

आईओएस अद्यतन के लिए काफी बुलेटप्रूफ होना चाहिए।

+1

यह पॉपओवर के साथ विचारों के लिए ठीक काम करता है, जो नेविगेशन नियंत्रकों में एम्बेडेड नहीं हैं। जैसे ही व्यू कंट्रोलर (जो नेविगेशन कंट्रोलर में एम्बेडेड है) पॉपओवर के लिए छाया का फिर से उपयोग किया जाता है। इस के लिए कोई भी समाधान है? – FrankZp

+0

# फ्रैंकजेपी नीचे संशोधन के लिए देखो। –

+0

+1 अच्छा कामकाज! एक प्रश्न: क्या आप थोड़ा सा समझा सकते हैं कि '[स्वयं वर्ग]' (जो 'objc_class' है) पर संदेश भेज रहा है? – matm

0
FrankZp

यह विचारों के लिए R आर, जो NavigationControllers में एम्बेडेड नहीं कर रहे हैं के साथ ठीक काम करता है के लिए

। जैसे ही ViewController (जो नेविगेशन नियंत्रक में एम्बेडेड है) पॉपओवर के लिए छाया फिर से वापस आ गया है। इस के लिए कोई भी समाधान है?

यहाँ 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

हालांकि मैं प्रिंसिपल कि अपनी खुद की पॉपओवर रोल करने के लिए है इस संभाल करने के लिए उचित तरीके से सहमति व्यक्त करते हैं, इस मामले में यह एक गैर मुद्दा है ओएस के नए संस्करण। क्या मैं वास्तव में एक ओएस का समर्थन करने के लिए अपने स्वयं के पॉपओवर कार्यान्वयन को बनाना और बनाए रखना चाहता हूं जो अंततः अप्रासंगिक होगा? यदि आप वास्तव में चाहते हैं, तो वेब पर कुछ मुक्त मुक्त स्रोत कार्यान्वयन पर विचार करें।

व्यक्तिगत रूप से मैंने यहां सुझाए गए तरीकों की जांच की और शुरुआती बिंदु (धन्यवाद!) के रूप में इस पृष्ठ का उपयोग करके स्वयं के साथ आया। यह दोनों परिदृश्यों के लिए काम करता है (नेविगेशन बार के साथ या बिना) और मेरी राय में थोड़ा सा सुरक्षित है।

UIPopoverController में कोई विधि जोड़ने के बजाय, मैंने ABSOLUTE के बजाय एक विश्वसनीय मार्ग का उपयोग करके अपमानजनक विचारों को देखने के लिए अपने UIPopoverBackgroundView में एक दिनचर्या जोड़ा। संक्षेप में, चूंकि कोड UIPopoverBackgroundView (स्वयं) का सीधा संदर्भ है, इसलिए यह नेविगेट (पर्यवेक्षण) और फिर नीचे (सबव्यू) को नेविगेट कर सकता है।

दृश्य पेड़ दोनों स्थितियों में इस तरह दिखेगा:

UINavigationBar साथ : enter image description here

UINavigationBar के बिना: enter image description here

दो बार देखा गया है कि हम में रुचि रखते हैं कर रहे हैं UILayoutView और UIImage विचार जो प्रत्येक ग्राफ में बोल्ड और रेखांकित हैं। हम नीचे दिए गए कोड का उपयोग करके UIPopoverBackgroundView से शुरू होने वाले इनका संदर्भ प्राप्त कर सकते हैं (एआरसी मानते हैं)। मैं इसे अपने UIPopoverBackgroundView कार्यान्वयन में layoutSubviews से निष्पादित करता हूं।

// 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

आपको आईओएस 6+ में इनमें से कोई भी करने से बचने के लिए एक शर्त जोड़नी चाहिए और 'चाहें डीफॉल्टकंटेंटएपियरेंस' से 'NO' वापस लौटना चाहिए। विस्तृत चित्रण स्पष्टीकरण के लिए –

+0

+1। क्या आप यह भी बता सकते हैं कि यूआईपीओपीओवर के सीमा आकार को कैसे समायोजित किया जाए? – HDdeveloper

+0

क्या आपका बाहरी सीमा है? मैंने popover के रूप को निर्दिष्ट करने के लिए छवियों का उपयोग करने के लिए एक UIPopoverBackgroundView का उपयोग किया। यदि आप आंतरिक सीमा का मतलब है, तो मैंने इसे हटा दिया है। डिफ़ॉल्ट कार्यान्वयन UIImageView का उपयोग करता है, इसलिए यदि आप सीमा को बदलना चाहते हैं तो आपको छवि को प्रतिस्थापित करना होगा। –