2013-08-08 11 views
5

Ich baue eine benutzerdefinierte Ansicht, die mehrere andere Teilansichten enthält (NSTextField, WebView, ...). Ich möchte, dass in meiner benutzerdefinierten Ansicht ein anderer Rahmen gezeichnet wird, wenn eine der Unteransichten der erste Responder ist, und als ein einzelnes Element fungiert, auf das mit Menüelementen und Tastenkombinationen reagiert werden kann. Es sieht etwa so aus:Gibt es eine zuverlässige Möglichkeit, Erstanwenderänderungen in Unteranfragen zu erkennen?

+-------------+ 
| NSTextField | 
+-------------+ 
| WebView  | 
+-------------+ 

Bisher habe ich Erfolg Subklassifizieren NSTextField und andere hatten einen Delegierten zu benachrichtigen, wenn - (BOOL)becomeFirstResponder und - (BOOL)resignFirstResponder genannt werden. Dieser Ansatz funktioniert jedoch nicht mit WebView, da er selbst viele Unteransichten enthält - ich kann sie nicht alle untergliedern!

Gibt es eine bessere Möglichkeit festzustellen, wenn Subviews ihren First Responder-Status ändern? Oder eine bessere Möglichkeit, eine benutzerdefinierte Ansicht zu erstellen?

+0

Genau die gleichen Probleme hier, haben Sie jemals eine Lösung gefunden? – Kappe

Antwort

1

Beide WebViewEditingDelegate Methode aufrufen wird,

Ersthelfer Resign:

-(void)webViewDidEndEditing:(NSNotification *)notification 
{ 

} 

und wenn Ersthelfer werden:

-(BOOL)webView:(WebView *)webView shouldBeginEditingInDOMRange:(DOMRange *)range 
{ 
    return YES; 
} 
+0

Sicher wäre schön, wenn diese API für UIWebKit verfügbar wäre :) – BadPirate

2

Ein anderer Ansatz wäre es, die -makeFirstResponder: Methode auf NSWindow zu überschreiben, um eine Benachrichtigung zu senden.

- (BOOL)makeFirstResponder:(NSResponder *)responder { 
    id previous = self.firstResponder ?: [NSNull null]; 
    id next = responder ?: [NSNull null]; 

    NSDictionary *userInfo = @{ 
    BrFirstResponderPreviousKey: previous, 
    BrFirstResponderNextKey: next, 
    }; 

    [[NSNotificationCenter defaultCenter] postNotificationName:BrFirstResponderWillChangeNotification object:self userInfo:userInfo]; 

    return [super makeFirstResponder:responder]; 
} 

Sie können dann für die Benachrichtigung in Ihrer benutzerdefinierten Ansicht oder einen View-Controller hören und überprüfen, ob die vorherigen oder nächsten Responder Subviews sind mit -isDescendantOf: und setzen needsDisplay nach Bedarf.

Dies ist jedoch keine ideale Lösung, da die benutzerdefinierte Ansicht nicht länger eigenständig ist. Es funktioniert für jetzt, aber hoffentlich wird ein besserer Ansatz geteilt.

1

ich mit iOS/UIWebView dieses Problem hatte, die makeFirstResponder in UIWindow nochnicht implementiertoder shouldBeginEditingInDOMRange. Mit der Verwendung von Swizzling konnte ich jedoch eine Hilfskategorie erstellen, die es ermöglicht, den aktuellen Ersthelfer abzurufen und bei jedem Wechsel des Erstantragstellers eine Benachrichtigung zu senden. Wirklich frustrierend, wie all dies öffentliche API sein sollte, ist es aber nicht, da Swizzle normalerweise kein erster Goto ist, aber das hat gut genug funktioniert.

Zuerst Einrichtung Ihrer Kategorie-Header:

@interface UIResponder (Swizzle) 
+ (UIResponder *)currentFirstResponder; 
- (BOOL)customBecomeFirstResponder; 
@end 

Dann Kategorie Implementierung

@implementation UIResponder (Swizzle) 
// It's insanity that there is no better way to get a notification when the first responder changes, but there it is. 
static UIResponder *sCurrentFirstResponder; 
+ (UIResponder *)currentFirstResponder { 
    return sCurrentFirstResponder; 
} 

- (BOOL)customBecomeFirstResponder { 
    NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithCapacity:2]; 
    if(sCurrentFirstResponder) { 
     [userInfo setObject:sCurrentFirstResponder forKey:NSKeyValueChangeOldKey]; 
    } 
    sCurrentFirstResponder = self; 
    if(sCurrentFirstResponder) { 
     [userInfo setObject:sCurrentFirstResponder forKey:NSKeyValueChangeNewKey]; 
    } 
    [[NSNotificationCenter defaultCenter] postNotificationName:kFirstResponderDidChangeNotification 
                 object:nil 
                 userInfo:userInfo]; 
    return [self customBecomeFirstResponder]; 
} 
@end 

schließlich einen Helfer wie JR Swizzle verwenden, tauschen Sie die Klassen.

#import "JRSwizzle.h" 

- (void)applicationLoaded { 
    if(![UIResponder jr_swizzleMethod:@selector(becomeFirstResponder) withMethod:@selector(customBecomeFirstResponder) error:&error]) { 
     NSLog(@"Error swizzling - %@",error); 
    } 
} 

Ich dachte, ich würde teilen. Gültig im App-Store, da keine private API verwendet wird. Während Apple davor warnt, die Basisklassen zu vertauschen, gibt es keinen Erlass dagegen.

Verwandte Themen