I am working on an application that supports multiple languages. In order to support languages that start from right to left, I am transforming the view so that views on the right side get shifted to left side as shown in the images below:
I am using the following code to transform the view
self.view.transform = CGAffineTransformMakeScale(-1, 1);
What I now want to do is transform the views in its new position in the left to remove the mirrored text. For example, I want to flip the "FLIP LABEL" about its center so that the text is displayed properly. How do I do this?
You could try running the same transform again on the individual subviews - for example:
for (UIView *view in self.view.subviews) {
view.transform = CGAffineTransformMakeScale(-1, 1);
}
(Or maybe it would be CGAffineTransformMakeScale(1, 1)? I'm not totally sure.)
Related
I'm trying to get a UIButton to scale but remain at its original center point, and I'm getting perplexing results with CGAffineTransformScale.
Here's the function in my UIButton subclass:
-(void)shrink {
self.transform = CGAffineTransformMakeScale(0.9,0.9);
}
With this code, the button scales to the top-left corner, but when I add code to try to set the anchor point (either of the following lines), the button gets relocated off screen somewhere:
[self.layer setAnchorPoint:CGPointMake(self.frame.size.width/2, self.frame.size.height/2)];
//same result if I use bounds instead of frame
[self.layer setAnchorPoint:self.center];
Interestingly, this line causes the view to move down and to the right some distance:
[self.layer setAnchorPoint:CGPointMake(0, 0)];
Sorry, I know there are many posts on this topic already but I honestly read and tried at least a dozen and still couldn't get this to work. I'm probably just missing something incredibly simple.
The default anchor point is 0.5, 0.5. That is why setting it to 0, 0 moves the view down and to the right. Also, if you don't want the center to move, you need to re-adjust the center after scaling it.
Just readjust its position after shrinking it.
-(void)shrink {
CGPoint centerPoint = self.center;
self.transform = CGAffineTransformMakeScale(0.9,0.9);
self.center = centerPoint;
}
I've created a .xib with a landscape orientation UIView.
The problem I'm trying to solve is that I want a UILabel running vertically along the side with text reading from bottom of the view to the top, but I can't figure out how to do that. Is that possible?
Image to show what I mean
You need to rotate and then translate it to put it where you want it. Rotation happens around the center of the label which is why you then need to translate it.
If you laid out the text label with the upper left corner where you wanted it to end up (i.e. the displayed label looks like it rotates around the upper left corner point of the label), you'd use code something like:
- (void)viewDidLayoutSubviews {
CGAffineTransform transform = CGAffineTransformMakeRotation(3 * M_PI_2);
CGAffineTransform transform2 = CGAffineTransformConcat(transform, CGAffineTransformMakeTranslation(floor(-self.label.bounds.size.width / 2), floor(-self.label.bounds.size.width / 2)));
self.label.transform = transform2;
}
You might need to adjust the translation values slightly to get what you want, but you definitely want them to be integers (which I've done with floor) so the label is crisp.
Of course you can. You need to do a transform.
yourlabel.transform = CGAffineTransformMakeRotation(-M_PI/2);
what I am having is
UIView
1.Image1
2.Image2
3.UILabel
like an image below
Then I apply rotation on UILabel by doing
- (void)viewDidLoad
{
testLabel.transform = CGAffineTransformMakeRotation(M_PI*0.25);
[super viewDidLoad];
}
and when I am running the application, the uilabe is disppearing after all. Look at the second image for your reference
Please point out what I am doing wrong here....and how to get the work done
Thanks
Watch out because Autolayout cause a lot of problems.
Try to deselect 'Use Autolayout'
It solves to me all the problems trying to translate objects.
Try multiplying by a smaller value against PI to see if it is rotating or just disappearing. If I remember correctly, rotations are not based on the center, but on the top-left corner, so you have to translate afterwards!
For instance, to rotate a video clip this is what I had to do:
CGAffineTransform rotation = CGAffineTransformMakeRotation(M_PI);
CGAffineTransform translateToCenter = CGAffineTransformMakeTranslation(640, 480);
CGAffineTransform mixedTransform = CGAffineTransformConcat(rotation, translateToCenter);
[firstTrackInstruction setTransform:mixedTransform atTime:kCMTimeZero];
I rotated by PI first (180 degrees), but because the center of rotation is the top left corner, my video clip was now in the opposite quadrant, and needed to be transformed back! This may be what is happening with your label.
So try this, assuming your label is 42x21 dimensions..
CGAffineTransform rotation = CGAffineTransformMakeRotation(M_PI);
CGAffineTransform translateToCenter = CGAffineTransformMakeTranslation(42, 21);
CGAffineTransform mixedTransform = CGAffineTransformConcat(rotation, translateToCenter);
label.transform = mixedTransform;
try putting the [super viewDidLoad] first :
- (void)viewDidLoad
{
[super viewDidLoad];
testLabel.transform = CGAffineTransformMakeRotation(M_PI*0.25);
}
AutoLayout and AutoResizing often cause difficulties when you apply transforms as these seem to alter the frame rather than the bounds and center of a view. Hence the automatic adjustments wreck havoc on your layout. Try to wrap the transformed label in a view that does not change dimensions and layout that view within its superview however you want.
I want to simultaneously scale and translate a CALayer from one CGrect (a small one, from a button) to a another (a bigger, centered one, for a view). Basically, the idea is that the user touches a button and from the button, a CALayer reveals and translates and scales up to end up centered on the screen. Then the CALayer (through another button) shrinks back to the position and size of the button.
I'm animating this through CATransform3D matrices. But the CALayer is actually the backing layer for a UIView (because I also need Responder functionality). And while applying my scale or translation transforms separately works fine. The concatenation of both (translation, followed by scaling) offsets the layer's position so that it doesn't align with the button when it shrinks.
My guess is that this is because the CALayer anchor point is in its center by default. The transform applies translation first, moving the 'big' CALayer to align with the button at the upper left corner of their frames. Then, when scaling takes place, since the CALayer anchor point is in the center, all directions scale down towards it. At this point, my layer is the button's size (what I want), but the position is offset (cause all points shrank towards the layer center).
Makes sense?
So I'm trying to figure out whether instead of concatenating translation + scale, I need to:
translate
change anchor point to upper-left.
scale.
Or, if I should be able to come up with some factor or constant to incorporate to the values of the translation matrix, so that it translates to a position offset by what the subsequent scaling will in turn offset, and then the final position would be right.
Any thoughts?
You should post your code. It is generally much easier for us to help you when we can look at your code.
Anyway, this works for me:
- (IBAction)showZoomView:(id)sender {
[UIView animateWithDuration:.5 animations:^{
self.zoomView.layer.transform = CATransform3DIdentity;
}];
}
- (IBAction)hideZoomView:(id)sender {
CGPoint buttonCenter = self.hideButton.center;
CGPoint zoomViewCenter = self.zoomView.center;
CATransform3D transform = CATransform3DIdentity;
transform = CATransform3DTranslate(transform, buttonCenter.x - zoomViewCenter.x, buttonCenter.y - zoomViewCenter.y, 0);
transform = CATransform3DScale(transform, .001, .001, 1);
[UIView animateWithDuration:.5 animations:^{
self.zoomView.layer.transform = transform;
}];
}
In my test case, self.hideButton and self.zoomView have the same superview.
I'm working on a drawing app.
I want the user to be able to "drop" a shape on the screen and then move, resize or rotate it as desired.
The problem is with the rotation. I have the moving and resizing working fine.
I did this before with a rather complex and memory/processor-intensive process, which I am now trying to improve.
I've searched and searched but haven't found an answer similar to what I'm trying to do.
Basically, let's say the user drops a square on the "surface". Then, they tap it and get some handles. They can touch anywhere and pan to move the square around (working already), touch and drag on a resize handle to resize the square (working already), or grab the rotation handle to have the square rotate around its center.
I've looked into drawing the square using UIBezierPath or just having it be a subclass of UIView that I fill.
In either case, I'm trying to rotate the UIView itself, not some contents inside. Every time I try to rotate the view, either nothing happens, the view vacates the screen or it rotates just a little bit and stops.
Here's some of the code I've tried (this doesn't work, and I've tried a lot of different approaches to this):
- (void) rotateByAngle:(CGFloat)angle
{
CGPoint cntr = [self center];
CGAffineTransform move = CGAffineTransformMakeTranslation(-1 * cntr.x, -1 * cntr.y);
[[self path] applyTransform:move];
CGAffineTransform rotate = CGAffineTransformMakeRotation(angle * M_PI / 180.0);
[[self path] applyTransform:rotate];
[self setNeedsDisplay];
CGAffineTransform moveback = CGAffineTransformMakeTranslation(cntr.x, cntr.y);
[[self path] applyTransform:moveback];
}
In case it isn't obvious, the thinking here it to move the view to the origin (0,0), rotate around that point and then move it back.
In case you're wondering, "angle" is calculated correctly. I've also wrapped the code above in a [UIView beginAnimations:nil context:NULL]/[UIView commitAnimations] block.
Is it possible to rotate a UIView a "custom" amount? I've seen/done it before where I animate a control to spin, but in those examples, the control always ended up "square" (i.e., it rotated 1 or more full circles and came back to its starting orientation).
Is it possible to perform this rotation "real-time" in response to UITouches? Do I need to draw the square as an item in the layer of the UIView and rotate the layer instead?
Just so you know, what I had working before was a shape drawn by a set of lines or UIBezierPaths. I would apply a CGAffineTransform to the data and then call the drawRect: method, which would re-draw the object inside of a custom UIView. This UIView would host quite a number of these items, all of which would need to be re-drawn anytime one of them needed it.
So, I'm trying to make the app more performant by creating a bunch of UIView subclasses, which will only get a command to re-draw when the user does something with them. Apple's Keynote for the iPad seems to accomplish this using UIGestureRecognizers, since you have to use two fingers to rotate an added shape. Is this the way to go?
Thoughts?
Thanks!
-(void)rotate{
CGAffineTransform transform;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1.0];
[UIView setAnimationCurve:UIViewAnimationOptionBeginFromCurrentState];
myView.alpha = 1;
transform = CGAffineTransformRotate(myView.transform,0.5*M_PI);
[myView setUserInteractionEnabled:YES];
myView.transform = transform;
[UIView commitAnimations];
}
This might help.
for just simple rotation you might leave out the Animation:
-(void)rotate:(CGFloat)angle
{
CGAffineTransform transform = CGAffineTransformRotate( myView.transform, angle * M_PI / 180.0 );
myView.transform = transform;
}
I use a simple NSTimer to control a animation.