Une des questions les plus fréquentes concernant la programmation je obtenir l'iPhone est sur la façon de tourner ou de l'échelle ou faire diverses autres modifications à une vue. Je ne parle pas au sujet Hardcore type Core Animation de trucs, juste simple, "Comment puis-je placer une étiquette à 45 ^ 0" genre de questions. L'attente est qu'il devrait y avoir une propriété appelée "angle" ou "échelle" qui peut être réglé, ou que vous devriez être capable de tenir la touche option enfoncée dans Interface Builder pour le faire tourner là-bas.
Avec Leopard, Apple nous a donné Core Animation, et il est très cool, mais afin de réaliser tout ce que la fraîcheur, ils ont dû ajouter quelques concepts qui font qu'il n'est pas toujours intuitive. (BTW: Si vous ne voulez en savoir plus sur Core Animation, j'ai lu le projet de loi Dudney Core Animation pour Mac OS X et l'iPhone et c'est très bon).
Tout changement à la position d'un point de vue, l'échelle ou la rotation peuvent désormais être stockés dans une propriété de la vue appelée transform. Il s'agit d'une struct CGAffineTransform, et c'est un peu cryptique, si vous n'avez jamais travaillé avec des matrices de transformation avant.
Un rien matrice plus la transformation d'un tableau à deux dimensions de nombres. Ok, peut-être je ne devrais pas dire «juste», comme des matrices de transformation sont très puissantes. Ils peuvent stocker des changements complexes de la position et la forme d'un objet, y compris en rotation, redimensionnement, déplacement, et l'inclinaison (ou cisaillement) le point de vue que c'est tiré. Cela ajoute un peu de complexité programmeur si vous voulez faire quelque chose de plus que les bases absolues, mais il ouvre un monde de possibilités.
Alors, qu'est-ce que cette structure de données ressembler? Ceci:
ouais, il ne ressemble pas à une matrice, n'est ce pas? Il est; it'sit est une matrice 3x3, c'est juste que certaines valeurs dans la matrice sont constants, ils ne peuvent pas changer, alors qu'ils ne sont pas représentés par une variable. Voici ce que la matrice devrait ressembler à tirer en homme respectueux forme:
Ces neuf numéros sont utilisés pour stocker la rotation, l'échelle et la position d'un objet en utilisant quelque chose qui s'appelle la multiplication matricielle.
Ainsi, si un point de vue a une transformation, comment ne Core Graphics comprendre où et comment le dessiner?
Fondamentalement, il figure où il serait de dessiner chaque point (x, y) sans la transformation, puis fait le calcul suivant pour déterminer le nouveau point transformé:
Et cela fonctionne? Yep, c'est le cas, assez étonnamment. Si vous êtes intéressé par les mathématiques derrière tout cela, il ya beaucoup de bonnes sources. Juste google "matrice de transformation" d'en trouver. Si vous allez faire des transformations complexes, c'est une bonne idée d'avoir une compréhension de base des mathématiques sous-jacentes, mais pour un usage de base, vous pouvez vous en sortir sans elle.
La raison pour laquelle vous pouvez vous en sortir sans comprendre les subtilités de la mathématique est parce qu'Apple nous a fourni un certain nombre de fonctions pour récupérer les matrices standard et à des transformations standard. Afin de pouvoir utiliser n'importe lequel de ces transformations, vous devrez inclure le cadre CoreGraphics dans votre projet, et inclure le fichier d'entête CoreGraphics:
Tous les points de vue (et les couches, mais nous ne parlons pas de couches aujourd'hui) commencer avec leur propriété de transformer l'ensemble Matrice identité. Cette matrice représente l'objet, sans aucune modification. Il n'a pas été tourné, à l'échelle, cisaillé, ou traduit (déplacé). Pour une vue qui a la matrice identité de la propriété transform sera établi uniquement sur la taille et l'origine de la propriété bounds.
Chaque fois que vous souhaitez réinitialiser une vue ou d'une couche à son état d'origine, non transformées, il suffit de définir sa transformée de la transformation d'identité en utilisant les CGAffineTransformIdentity valeur constante comme ceci:
Translation est juste une façon élégante de dire «en mouvement». Vous pouvez, bien sûr, d'accomplir un mouvement en changeant la valeur d'origine de la propriété frame de la vue (qui se déplace le point de vue par rapport à son SuperView), mais puisque nous ne pouvons pas utiliser la propriété frame avec d'autres transformations, la transformation est de traduire une question importante. Si vous voulez traduire un point de vue, vous utilisez une fonction appelée Core Graphics CGAffineTransformTranslate (). Cette méthode prend trois paramétrée. La première est une valeur CGAffineTransform existants que la traduction sera appliqué. Pour traduire une vue de sa position actuelle, vous devriez passer la propriété de la vue de transformer ici. Pour traduire le point de vue de sa position initiale, vous passeriez à CGAffineTransformIdentity. Voici un exemple qui serait déplacer la vue de cinq points à la droite et dix points de retard.
La multiplication de matrices est cumulatif, donc si vous traduisez par cinq pixels, puis de traduire à nouveau par cinq pixels dans la même direction, vous obtenez une traduction de dix pixels, en supposant qu'il n'y avait pas d'autres transformations entre les deux appels.
La traduction la plus courante, et le premier dont nous parlons qui ne peuvent pas se faire sans des transformations, est une rotation, qui est gérée par la fonction appelée CGAffineTransormRotate (). Cette fonction prend deux paramètres, le premier étant la matrice de transformation existantes, et la seconde étant l'angle de rotation exprimé en radians.
Radians? Qui diable pense en radians? Il ya une macro de conversion de commodité dans Core Graphics pour Mac OS X appelée degreesToRadian (), mais maintenant, il est inexplicablement absent de Core Graphics pour l'iPhone. C'est une conversion assez facile, même si - il suffit d'ajouter cette ligne de code à votre fichier d'entête:
alors vous pouvez faire pivoter une vue comme celle-ci:
La finale de la transformation de base est la transformation d'échelle, ce qui vous permet de redimensionner votre point de vue, sans toucher sa propriété de limites. Pour l'échelle en vue de doubler sa taille d'origine, nous utilisons CGAffineTransformScale (), comme ceci:
Voici quelques choses que vous devriez prendre note de que vous commencez à travailler avec les transformations.
Lorsque vous êtes mise à l'échelle ou de rotation, l'objet recevra échelle ou tourné à partir du centre de l'objet. En Core Animation, vous pouvez définir un point d'ancrage qui va changer ce comportement, mais si vous n'utilisez pas Core Animation et ne veulent pas faire face à des couches, puis dans l'ordre à l'échelle ou faire pivoter à partir, par exemple, vous auriez à doivent également le faire manuellement les transformations de traduction pour repositionner la vue après l'échelle ou de rotation. Qui apporte autre chose à l'esprit:
Lorsque vous appliquez des transformations de succès, la question commande. Rotation et puis de traduire vous donnera un résultat différent, puis de traduire puis de la tourner. Cela peut vous mordre si vous ne faites pas attention.
Comme je le disais précédemment, vous pouvez toujours revenir au point de départ en fixant le point de vue de transformer à la matrice identité. Mais, si vous voulez juste de revenir en arrière une transformation. Dites, vous avez fait pivoter, puis à l'échelle, puis traduits, et vous voulez juste "traduire" il. Cela peut être utile si, par exemple, vous voulez faire des animations complexes, comme d'avoir une vue déplacer un chemin, et puis revenir à sa position initiale. Il ya une autre transformation de regarder appelé la transformation inverse. L'inverse d'une transformation est la traduction qui nient que la traduction lorsqu'il est appliqué après. Vous pouvez obtenir la transformation inverse pour tout CGAffineTransform en utilisant le CGAffineTransformInvert function (), comme ceci:
La valeur de l'inverse dans le code est le même que ci-dessus la création d'une traduction de (-5,0, -5,0), mais vous n'avez pas à savoir ce que la transformation est d'obtenir l'inverse en utilisant cette méthode.
Bon, nous avons seulement gratté la surface de ce qui est une partie très complexe de l'iPhone, mais j'espère que cela contribue à rendre le concept de «transforme» et «transformations» plus accessible et aideront certaines personnes font plus de sens de la documentation. Comme toujours, si vous avez des questions, n'hésitez pas à me ping via e-mail ou messagerie instantanée, ou envoyer un tweet à ma façon. J'utilise le même nom partout, ce qui est jeff soulignent Lamarche, sauf pour gmail, où je suis jeff points Lamarche.
Voici un l'échantillon de projets Xcode qui montre comment utiliser certaines transformations sur les vues créées dans Interface Builder.
Avec Leopard, Apple nous a donné Core Animation, et il est très cool, mais afin de réaliser tout ce que la fraîcheur, ils ont dû ajouter quelques concepts qui font qu'il n'est pas toujours intuitive. (BTW: Si vous ne voulez en savoir plus sur Core Animation, j'ai lu le projet de loi Dudney Core Animation pour Mac OS X et l'iPhone et c'est très bon).
Tout changement à la position d'un point de vue, l'échelle ou la rotation peuvent désormais être stockés dans une propriété de la vue appelée transform. Il s'agit d'une struct CGAffineTransform, et c'est un peu cryptique, si vous n'avez jamais travaillé avec des matrices de transformation avant.
Un rien matrice plus la transformation d'un tableau à deux dimensions de nombres. Ok, peut-être je ne devrais pas dire «juste», comme des matrices de transformation sont très puissantes. Ils peuvent stocker des changements complexes de la position et la forme d'un objet, y compris en rotation, redimensionnement, déplacement, et l'inclinaison (ou cisaillement) le point de vue que c'est tiré. Cela ajoute un peu de complexité programmeur si vous voulez faire quelque chose de plus que les bases absolues, mais il ouvre un monde de possibilités.
La structure de données CGAffineTransform
Alors, qu'est-ce que cette structure de données ressembler? Ceci:
struct CGAffineTransform {
CGFloat a;
CGFloat b;
CGFloat c;
CGFloat d;
CGFloat tx;
CGFloat ty;
};
ouais, il ne ressemble pas à une matrice, n'est ce pas? Il est; it'sit est une matrice 3x3, c'est juste que certaines valeurs dans la matrice sont constants, ils ne peuvent pas changer, alors qu'ils ne sont pas représentés par une variable. Voici ce que la matrice devrait ressembler à tirer en homme respectueux forme:
| a b 0 |
| c d 0 |
| tx ty 1 |
Ces neuf numéros sont utilisés pour stocker la rotation, l'échelle et la position d'un objet en utilisant quelque chose qui s'appelle la multiplication matricielle.
Remarque: Par ailleurs, ce même processus est utilisé pour transformer les formes de graphiques en trois dimensions. Les matrices utilisées pour la 3D sont 4X4 au lieu de 3x3 pour capturer les complémentaires z dimension.
Ainsi, si un point de vue a une transformation, comment ne Core Graphics comprendre où et comment le dessiner?
Fondamentalement, il figure où il serait de dessiner chaque point (x, y) sans la transformation, puis fait le calcul suivant pour déterminer le nouveau point transformé:
new x position = old x position * a + old y position * c + tx
new y position = old x position*b + old y position * d + ty
Et cela fonctionne? Yep, c'est le cas, assez étonnamment. Si vous êtes intéressé par les mathématiques derrière tout cela, il ya beaucoup de bonnes sources. Juste google "matrice de transformation" d'en trouver. Si vous allez faire des transformations complexes, c'est une bonne idée d'avoir une compréhension de base des mathématiques sous-jacentes, mais pour un usage de base, vous pouvez vous en sortir sans elle.
Les transformations de base
La raison pour laquelle vous pouvez vous en sortir sans comprendre les subtilités de la mathématique est parce qu'Apple nous a fourni un certain nombre de fonctions pour récupérer les matrices standard et à des transformations standard. Afin de pouvoir utiliser n'importe lequel de ces transformations, vous devrez inclure le cadre CoreGraphics dans votre projet, et inclure le fichier d'entête CoreGraphics:
#import
La transformation des identités
Tous les points de vue (et les couches, mais nous ne parlons pas de couches aujourd'hui) commencer avec leur propriété de transformer l'ensemble Matrice identité. Cette matrice représente l'objet, sans aucune modification. Il n'a pas été tourné, à l'échelle, cisaillé, ou traduit (déplacé). Pour une vue qui a la matrice identité de la propriété transform sera établi uniquement sur la taille et l'origine de la propriété bounds.
Note: Vues avoir à la fois un cadre (coordonnées dans le système de coordonnées superview) et des limites (coordonnées dans le système de coordonnées propres) propriété, mais si vous transformez une vue, vous ne devez pas utiliser ou s'appuyer sur la propriété frame plus. Si vous utilisez des transformations, de travailler avec la propriété bounds, et non la propriété frame, que les transformations sont appliquées à la limite, mais ne sont pas nécessairement reflété correctement dans le châssis
Chaque fois que vous souhaitez réinitialiser une vue ou d'une couche à son état d'origine, non transformées, il suffit de définir sa transformée de la transformation d'identité en utilisant les CGAffineTransformIdentity valeur constante comme ceci:
theView.transform = CGAffineTransformIdentity;
La transformation Traduire
Translation est juste une façon élégante de dire «en mouvement». Vous pouvez, bien sûr, d'accomplir un mouvement en changeant la valeur d'origine de la propriété frame de la vue (qui se déplace le point de vue par rapport à son SuperView), mais puisque nous ne pouvons pas utiliser la propriété frame avec d'autres transformations, la transformation est de traduire une question importante. Si vous voulez traduire un point de vue, vous utilisez une fonction appelée Core Graphics CGAffineTransformTranslate (). Cette méthode prend trois paramétrée. La première est une valeur CGAffineTransform existants que la traduction sera appliqué. Pour traduire une vue de sa position actuelle, vous devriez passer la propriété de la vue de transformer ici. Pour traduire le point de vue de sa position initiale, vous passeriez à CGAffineTransformIdentity. Voici un exemple qui serait déplacer la vue de cinq points à la droite et dix points de retard.
theView.transform = CGAffineTransformTranslate(theView.transform, 5.0, 10.0);
Remarque: des «points» ou «unités» signifie généralement pixels, mais que nous allons à l'indépendance de résolution et de départ pour soutenir la troisième dimension, il n'est plus correct de dire que c'est encore et toujours vrai que un point est un pixel. Mais, il est généralement
La multiplication de matrices est cumulatif, donc si vous traduisez par cinq pixels, puis de traduire à nouveau par cinq pixels dans la même direction, vous obtenez une traduction de dix pixels, en supposant qu'il n'y avait pas d'autres transformations entre les deux appels.
La transformation de rotation
La traduction la plus courante, et le premier dont nous parlons qui ne peuvent pas se faire sans des transformations, est une rotation, qui est gérée par la fonction appelée CGAffineTransormRotate (). Cette fonction prend deux paramètres, le premier étant la matrice de transformation existantes, et la seconde étant l'angle de rotation exprimé en radians.
Radians? Qui diable pense en radians? Il ya une macro de conversion de commodité dans Core Graphics pour Mac OS X appelée degreesToRadian (), mais maintenant, il est inexplicablement absent de Core Graphics pour l'iPhone. C'est une conversion assez facile, même si - il suffit d'ajouter cette ligne de code à votre fichier d'entête:
#define degreesToRadians(x) (M_PI * x / 180.0)
alors vous pouvez faire pivoter une vue comme celle-ci:
theView.transform = CGAffineTransformRotate(theView.transform, degreesToRadians(45));
La transformation d'échelle
La finale de la transformation de base est la transformation d'échelle, ce qui vous permet de redimensionner votre point de vue, sans toucher sa propriété de limites. Pour l'échelle en vue de doubler sa taille d'origine, nous utilisons CGAffineTransformScale (), comme ceci:
theView.transform = CGAffineTransformScale(theView.transform, 2.0, 2.0);
Remarque: Si vous désirez transformer la matrice d'identité, vous pouvez utiliser la fonction "Make" version de ces fonctions qui ne prennent pas une CGAffineTransform comme paramètre, et simplement supposer la matrice identité. Ainsi, par exemple, en appelant:theView.transform = CGAffineTransformTranslate(CGAffineTransformIdentity, 2.0, 2.0);
Vous pourriez appelertheView.transform = CGAffineTransformMakeTranslation(2.0, 2.0);
Ces deux lignes de code sont fonctionnellement identiques.
Quelques choses à savoir de
Voici quelques choses que vous devriez prendre note de que vous commencez à travailler avec les transformations.
Le Centre du Monde
Lorsque vous êtes mise à l'échelle ou de rotation, l'objet recevra échelle ou tourné à partir du centre de l'objet. En Core Animation, vous pouvez définir un point d'ancrage qui va changer ce comportement, mais si vous n'utilisez pas Core Animation et ne veulent pas faire face à des couches, puis dans l'ordre à l'échelle ou faire pivoter à partir, par exemple, vous auriez à doivent également le faire manuellement les transformations de traduction pour repositionner la vue après l'échelle ou de rotation. Qui apporte autre chose à l'esprit:
Questions Commander
Lorsque vous appliquez des transformations de succès, la question commande. Rotation et puis de traduire vous donnera un résultat différent, puis de traduire puis de la tourner. Cela peut vous mordre si vous ne faites pas attention.
Prendre du recul
Comme je le disais précédemment, vous pouvez toujours revenir au point de départ en fixant le point de vue de transformer à la matrice identité. Mais, si vous voulez juste de revenir en arrière une transformation. Dites, vous avez fait pivoter, puis à l'échelle, puis traduits, et vous voulez juste "traduire" il. Cela peut être utile si, par exemple, vous voulez faire des animations complexes, comme d'avoir une vue déplacer un chemin, et puis revenir à sa position initiale. Il ya une autre transformation de regarder appelé la transformation inverse. L'inverse d'une transformation est la traduction qui nient que la traduction lorsqu'il est appliqué après. Vous pouvez obtenir la transformation inverse pour tout CGAffineTransform en utilisant le CGAffineTransformInvert function (), comme ceci:
CGAffineTransform inverse = CGAffineTransformInvert(CGAffineTransformMakeTranslation(5.0, 5.0));
La valeur de l'inverse dans le code est le même que ci-dessus la création d'une traduction de (-5,0, -5,0), mais vous n'avez pas à savoir ce que la transformation est d'obtenir l'inverse en utilisant cette méthode.
Conclusion
Bon, nous avons seulement gratté la surface de ce qui est une partie très complexe de l'iPhone, mais j'espère que cela contribue à rendre le concept de «transforme» et «transformations» plus accessible et aideront certaines personnes font plus de sens de la documentation. Comme toujours, si vous avez des questions, n'hésitez pas à me ping via e-mail ou messagerie instantanée, ou envoyer un tweet à ma façon. J'utilise le même nom partout, ce qui est jeff soulignent Lamarche, sauf pour gmail, où je suis jeff points Lamarche.
Voici un l'échantillon de projets Xcode qui montre comment utiliser certaines transformations sur les vues créées dans Interface Builder.
Aucun commentaire:
Enregistrer un commentaire