Ce qui fonctionne pour passer des touches grâce à (et l'affichage de toutes) les sous-vues?
J'ai le texte suivant de la chaîne de sous-vue:
UIViewController.view -+
|-> UIView (subclass) -+
| +-> UIToolbar
|
+------------------------> UIWebView
Dans la sous-classe, je remplace son -touchesEnded:forEvent:
méthode afin de masquer et d'afficher le UIToolbar
sur un seul robinet toucher, par le biais d'un CAAnimation
, ainsi que d'émettre un NSNotification
que provoque la vue-contrôleur de cacher sa barre de navigation.
Si je ne suis pas d'ajouter le UIWebView
comme une sous-vue à la vue du contrôleur de vue, cela fonctionne correctement.
Si je puis ajouter le UIWebView
comme une sous-vue de la vue du contrôleur de la vue, puis l' UIToolbar
n'apparaît pas, et je ne reçois pas l'effet d'animation. Le UIWebView
répond au toucher, mais le sous-classé UIView
ne le fait pas. La notification de me faire virer, même si, et la barre de navigation ne seront cachés.
Quelle est la meilleure façon de disposer de ces sous-vues, de sorte que:
- La
UIToolbar
peut être faite à glisser sur et en dehors de l'écran - La
UIWebView
est visible peut encore recevoir son typique touch-événements: zoom avant/arrière et appuyez deux fois sur pour réinitialiser le niveau de zoom
Une réponse correcte sera répondent à ces deux critères.
MODIFIER
J'ai fait quelques progrès, mais je ne peux pas distinguer les événements tactiles et donc j'ai le feu d'une barre d'outils afficher/masquer méthode, elle ne doit pas être tiré.
J'ai la vue du contrôleur de la propriété en vue de la UIView
sous-classe, et j'ai inséré le web dans la partie supérieure de la -subviews
tableau via [self.view insertSubview:self.webView atIndex:0]
.
J'ai ajouté la méthode suivante à la UIView
sous-classe:
- (UIView *) hitTest:(CGPoint) point withEvent:(UIEvent *)event {
UIView *subview = [super hitTest:point withEvent:event];
if (event.type == UIEventTypeTouches) {
[self toggleToolbarView:self];
//get touches
NSSet *touches = [event allTouches];
NSLog(@"subview: %@", subview);
NSLog(@"touches: %@", touches);
//individual touches
for (UITouch *touch in touches) {
switch (touch.phase) {
case UITouchPhaseBegan:
NSLog(@"UITouchPhaseBegan");
break;
case UITouchPhaseMoved:
NSLog(@"UITouchPhaseMoved");
break;
case UITouchPhaseCancelled:
NSLog(@"UITouchPhaseCancelled");
break;
case UITouchPhaseStationary:
NSLog(@"UITouchPhaseStationary");
break;
default:
NSLog(@"other phase...");
break;
}
}
}
return subview;
}
La méthode -toggleToolbarView:
déclenche une NSTimer
-chronométré CAAnimation
qui cache/montre un UIToolbar*
.
Le problème est qu'un toucher-glisser combinaison de causes -toggleToolbarView:
à feu (ainsi que de l'utilisation du zoom de l'affichage sur le web). Ce que je voudrais faire est de provoquer -toggleToolbarView:
d'être licencié que lorsqu'il n'y est un toucher événement.
Lorsque j'appelle la méthode ci-dessus -hitTest:withEvent:
, il semble que la UIWebView
aspire la touche. Les deux NSLog
déclarations montrent que le UIView*
qui est renvoyé par le parent UIView*
's -hitTest:withEvent:
est le UIWebView
ou la UIToolbar
(quand il est à l'écran et touché). Le touches
tableau est vide et donc le toucher types d'événements ne peuvent pas être distingués.
Il y a encore une chose que je vais essayer, mais j'ai voulu enregistrer cette tentative ici au cas où d'autres ont rapidement suggestions. Merci pour votre aide permanente.
EDITION II
J'ai fait quelques progrès avec l'obtention de la UIWebView
de pincement/zoom et de répondre à une double-tap. Je peux aussi masquer/afficher la barre d'outils avec un seul robinet.
Au lieu de vous embêter avec la UIWebView
instance privée UIScroller
, j'ai accès à son intérieur, privé,UIWebDocumentView
. Mais la vue web dans son ensemble n'a pas mis à jour correctement après un zoom avant.
Ce que cela signifie: Si mon document contient un PDF ou SVG vector illustration, par exemple, le zoom en cause le contenu d'être floues, comme si l'image tuiles qui composent le rendu PDF ou illustration vectorielle contenu ne sont pas re-rendus, un nouveau facteur de zoom.
Pour les fins de cette documentation, je vais:
-
Appeler le
UIView (subclass)
au lieuViewerOverlayView
-
La
UIWebView
est appeléViewerWebView
Les deux sont des sous-classes de UIView
et UIWebView
, respectivement.
Mon ViewerWebView
contient une nouvelle ivar (avec @property
+ @synthesized
):
UIView *privateWebDocumentView;
(Ce UIView
est en fait un pointeur vers un UIWebDocumentView
exemple, mais pour éviter de Pomme de repérage de l'application de refus, j'ai choisi ce à un UIView
pour le simple but de transmettre les événements tactiles.)
La mise en œuvre de ViewerWebView
remplace -hitTest:withEvent:
- (UIView *) hitTest:(CGPoint)point withEvent:(UIEvent *)event {
UIView *_subview = [super hitTest:point withEvent:event];
self.privateWebDocumentView = _subview;
return _subview;
}
Mon ViewerOverlayView
contient de nouvelles ivars (avec @property
+ @synthesized
):
ViewerWebView *webView;
UIView *webDocumentView;
Dans la mise en œuvre de la superposition de vue, je remplace -touchesBegan:withEvent:
, -touchesMoved:withEvent:
et -touchesEnded:withEvent:
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
self.touchHasMoved = NO;
if (self.webView) {
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:self];
self.webDocumentView = [self.webView hitTest:touchPoint withEvent:event];
}
[super touchesBegan:touches withEvent:event];
[self.webDocumentView touchesBegan:touches withEvent:event];
}
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
self.touchHasMoved = YES;
if (self.webView) {
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:self];
self.webDocumentView = [self.webView hitTest:touchPoint withEvent:event];
}
[super touchesMoved:touches withEvent:event];
[self.webDocumentView touchesMoved:touches withEvent:event];
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
if(!self.touchHasMoved)
[self toggleToolbarView:self];
if (self.webView) {
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:self];
self.webDocumentView = [self.webView hitTest:touchPoint withEvent:event];
}
[super touchesEnded:touches withEvent:event];
[self.webDocumentView touchesEnded:touches withEvent:event];
}
Dans la vue du contrôleur, je ne les suivants:
-
Instancier la
ViewerOverlayView
et ajoutez-la à la sous-vue de la vue du contrôleur deview
propriété -
Instancier la vue du contrôleur de
ViewerWebView
instance et l'insérer à la partie inférieure de la sous-vues tableau -
Définir la
ViewerOverlayView
web de propriété en vue de l'affichage de contrôleur de la vue web
Alors maintenant, mon transparente ViewerOverlayView
correctement passes zoom/stretch/double-tap touch événements de la ViewerWebView
instance privée UIWebDocumentView
instance. Le UIWebDocumentView
puis redimensionne.
Toutefois, le contenu ne se redessiner avec la nouvelle échelle. Alors vecteur basé sur le contenu (par exemple, PDF, SVG) paraît floue lors du zoom avant.
Voici ce que le point de vue ressemble sans mise à l'échelle, agréable et forte:
Voici ce que l'affichage apparaît comme lorsque vous utilisez le zoom, ce qui n'est pas aussi forte qu'elle serait autrement sans cet événement personnalisé munging:
Il est intéressant de noter, je ne peux redimensionner entre les deux niveaux de zoom. Une fois que j'ai arrêter de double-tap-étirement de zoom à n'importe quel niveau, il "revient" à l'image que vous voyez dans l'image ci-dessus.
J'ai essayé -setNeedsDisplay
sur le ViewerWebView
et son intérieur UIWebDocumentView
instance. Ni l'appel de la méthode a fonctionné.
En dépit de vouloir éviter les méthodes privées, parce que je veux à terme, obtenir cette application approuvée, j'ai aussi essayé cette suggestion de l'accès au privé UIWebDocumentView
méthode -_webCoreNeedsDisplay
:
[(UIWebDocumentView *)self.webDocumentView _webCoreNeedsDisplay];
Cette méthode causé à l'application de crash d'un unrecognized selector
exception. Peut-être que Apple a changé le nom de cette méthode de SDK 3.0 pour 3.1.2.
Sauf s'il existe un moyen pour que le web pour redessiner son contenu, je suppose que je vais avoir à la ferraille de la superposition transparente afficher et il suffit de dessiner une vue web, afin d'obtenir l'affichage web pour fonctionner correctement. Qui suce!
Si quelqu'un a des pensées de redessiner après mise à l'échelle, n'hésitez pas à ajouter une réponse.
Merci encore à vous tous pour vos commentaires. En aparté, je n'ai pas d'annuler le bounty sur cette question -- je ne sais pas pourquoi il n'était pas attribuée automatiquement à la première réponse à ce fil de discussion, comme je l'ai été autrement s'attendait à arriver à partir de l'expérience précédente.
MODIFIER III
J'ai trouvé cette page web qui affiche comment la sous-classe de la fenêtre de l'application afin de pouvoir observer les robinets et avant que ces coups à la vue du contrôleur.
Il n'est pas nécessaire de mettre en œuvre son délégué partout dans l'application, seulement lorsque je veux observer les robinets sur UIWebView
, donc cela peut très bien fonctionner pour une visionneuse de documents.
Jusqu'à présent, je peux observer les robinets, masquer et afficher la barre d'outils, et la UIWebView
se comporte comme un affichage web. Je peux faire un zoom dans et hors de la vue web et le document est re-rendus correctement.
Alors qu'il serait bien d'apprendre à gérer les robinets dans un plus générique de la mode, cela ressemble à une excellente solution.
Les vues sont de la taille de l'écran. Ils sont parfaitement superposées. La coutume UIView est la taille de l'écran de sorte à accepter touche n'importe où sur l'écran.
Avez-vous essayé de l'annulation de la bascule lorsqu'un simple toucher progresse dans le glisser/zoom phase? Je suppose que l'annulation d'une horloge qui retarde le début de l'animation, juste assez longtemps pour détecter le changement de toucher-glisser/zoom?
Je ne sais pas d'un moyen de faire la distinction entre les touchez, puis faites glisser les événements, comme
[event allTouches]
tableau est vide. En raison de la tableau vide, je n'ai aucun moyen de l'émission d'une notification pour annuler la minuterie, par exemple.Intéressant que vous avez annulé le bounty, même quand vous avez eu une réponse à votre question initiale. Je suis nouveau ici, mais il ne semble pas juste que la prime disparaît, même si vous avez changé votre question.
OriginalL'auteur Alex Reynolds | 2009-12-06
Vous devez vous connecter pour publier un commentaire.
La façon dont je suis en train de lire votre question, vous voulez intercepter les événements pour déclencher une action (animer la barre d'outils, poste de notification), tout en permettant à l'événement pour atteindre sa destination naturelle.
Si je devais essayer de faire ça, je mettrais le
UIToolbar
directement comme une sous-vue de laUIViewController.view
. LeUIWebView
reste une sous-vue directe aussi.La
UIViewController.view
devrait être une sous-classe deUIView
, et il doit remplacerLa vue de côté-étape faisant partie de l'événement traitement par le renvoi de la vue que vous souhaitez recevoir de l'événement (UIToolbar ou UIWebView), alors que vous avez encore une chance de déclencher les actions que vous voulez.
Un exemple pourrait être:
Dans ce cas, pouvez-vous mettre la
UIWebView
à l'intérieur de laUIView (subclass)
dans votre schéma ci-dessus? Qui vous permettent également de remplacer-hitTest:
et d'utiliser la même approche.Est-il un moyen de séparer les
event.type
de savoir quel type de contact a lieu? Par exemple, une touche et faites-le glisser ne devrait déplacer la vue web, mais c'est aussi traitée comme une touche, ce qui déclenche la sous-vue contenant la barre d'outils. Est-il un moyen de distinguer entre les "toucher-glisser" et claire "touch"? Il estif (event.type == UIEventTypeTouches)
mais je ne vois pas d'autre type d'événement ou de sous-type qui casse cette.Je ne suis pas compétent avec l'événement tactile à déchiffrer, mais cette SORTE de réponse semble approprié: stackoverflow.com/questions/990870/...
OriginalL'auteur ohhorob
Si vous commencez par adjonction de la sous-classe UIView à la vue du contrôleur de la vue, puis ajouter la UIWebView comme vous le décrivez, la UIWebView va couvrir complètement le sous-classe UIView (en supposant que les deux points de vue sont complètement se chevauchent comme vous l'avez mentionné dans la question des commentaires).
Il semble que vous ne voulez pas que - vous souhaitez la sous-classe ci-dessus la vue web. Vous devez soit ajouter à la vue du contrôleur de vue dans l'ordre inverse (web ajouter, puis ajoutez les UIView) ou appelez le:
Avec que de la route, nous allons parler de la façon d'intercepter les événements tactiles. Je vais proposer une approche différente qui m'a permis de faire quelque chose de gentil similaire. Voici la question et la réponse que j'ai créé pour elle - n'hésitez pas à aller voir là pour plus de détails sur cette technique.
L'idée est que vous sous-classe UIApplication et remplacer l'-sendEvent: la méthode. Le vôtre ressemble à quelque chose comme ceci, je suppose:
Je n'attends pas cela vous aidera à 100%, mais j'espère que c'est un début. En particulier, vous pouvez jouer avec la condition if qui vérifie les propriétés de la UITouches vous avez affaire. Je ne suis pas sûr si je suis, y compris le droit de chèques ou si ils vont attraper la condition exacte que vous cherchez.
Bonne chance!
-subviews
tableau à l'indice 0 à obtenir pour devenir visible et sensible au toucher. Toutefois, cela provoque la sous-vue contenant la barre d'outils pour devenir instable.Vous avez besoin d'utiliser addSubview: ou l'un des insertSubview: méthodes. Ne pas ajouter de la vue pour les sous-vues tableau directement.
J'ai utilisé les deux méthodes. Je ne pense pas que je veux à la sous-classe le délégué d'application, puisque ce composant qui nécessite de sous-classement est seulement une petite (si important) une partie de l'ensemble de la demande.
OriginalL'auteur Mike McMaster
D'accord, qu'à ce sujet:
-Dans votre personnalisé
UIView
sous-classe, ajouter un pointeur vers votreUIWebView
-Ajouter un ivar à la
UIView
sous-classe,BOOL hasMoved;
-Dans le
UIView
sous-classe, remplacer le contact des méthodes comme ceci:Et puis de les mettre à la vue personnalisée sur le dessus de la vue web. Semble trop simple, et c'est probablement -- un peu de magie peut être amené à gérer de multiples touches correctement, et vous pouvez avoir besoin d'utiliser un
NSTimer
dans letouchesBegan:
méthode de retard à poignée double tap situations, mais je pense que l'idée générale est bonne...peut-être?-touchesBegan:withEvent:
une fois le premier contact se produit, ce qui l'incite à en forcer l'arrêt. Je suis surprise de voir que c'est si difficile!C'est très étrange. Je ne peux pas imaginer pourquoi. J'ai mis en place un projet de démonstration pour vérifier et je n'ai pas de rencontrer une boucle infinie -- toutefois, cela n'a pas fonctionné comme prévu. J'ai trouvé l'autre moitié solution que je vais poster à des fins historiques.
OriginalL'auteur Ian Henry
Prendre 2: les mêmes que ci-dessus, mais remplacer les méthodes comme suit:
Cela fonctionne...en quelque sorte. Cela vous permet de déplacer la vue web autour. Mais il n'est pas de la manipulation d'autres événements tactiles correctement (en suivant les liens, les pincements, n'importe quoi). . Probablement pas très utile, mais c'était un progrès pour moi!
OriginalL'auteur Ian Henry