I am easily rotating my UIView using CATransform3DMakeRotation but the problem is occurring when em adding a SubView after the rotation. It is adding it as rotated..
This is my view before the rotation
This is how i am rotating my UIView
aCustomView.layer.transform = CATransform3DMakeRotation(M_PI,0.0,1.0,0.0);
and after that em adding a custom Badge on it by this
JSCustomBadge *onlineUsersCountBadge = [JSCustomBadge customBadgeWithString:#"1"];
CGSize size = onlineUsersCountBadge.frame.size;
onlineUsersCountBadge.frame = CGRectMake(imageViewRect.origin.x+20, imageViewRect.size.height*0.3, size.width, size.height);
[aCustomView addSubview:onlineUsersCountBadge];
This is my view after rotation and added Subview
If I understood it well, you want the view to rotate but the badge to stay normal.
In my opinion, the best approach to this problem is to create an invisible subview containing all the elements (UIViews) you want to rotate (such as the background image). You then shouldn't apply the rotation to the full view, but only to that subview. Doing so, if you want to add an element which shouldn't be rotated, such as your badge, you add it to the main non-rotated view and not to the rotated subview.
Related
I have a UIView that I move with a pan gesture to the side of the screen and now the UIView is only partially displayed on the screen. How do I get the CGRect that contains ONLY the visible portion of the UIView, AND, in the coordinates of the original view?
I've tried combinations of CGRectIntersect() for the UIView.frame rect and the [UIScreen mainscreen].bounds rect, like this:
CGRect rect = CGRectIntersection([UIScreen mainScreen].bounds,
view.frame);
I haven't been able to correctly resolve matching the coordinate systems.
You first need to translate the CGRect of your displaced view, to the coordinate system of the main screen.
You can try something like
if let mainVC = UIApplication.shared.keyWindow?.rootViewController {
let translatedRect = mainVC.view.convert(myTestView.frame, from: view)
let intersection = translatedRect.intersection(mainVC.view.frame)
}
This first finds the main rootViewController, and translates your view's frame to rootViewController's coordinate system, and then finds the intersection. This would work even if your displaced view is nested in multiple layers of views.
After some (hours of) experimentation I came up with this solution:
// return the part of the passed view that is visible
- (CGRect)getVisibleRect:(UIView *)view {
// get the root view controller (and it's view is vc.view)
UIViewController *vc = UIApplication.sharedApplication.keyWindow.rootViewController;
// get the view's frame in the root view's coordinate system
CGRect frame = [vc.view convertRect:view.frame fromView:view.superview];
// get the intersection of the root view bounds and the passed view frame
CGRect intersection = CGRectIntersection(vc.view.bounds, frame);
// adjust the intersection coordinates thru any nested views
UIView *loopView = view;
do {
intersection = [loopView convertRect:intersection fromView:loopView.superview];
loopView = loopView.superview;
} while (loopView != vc.view);
return intersection; // may be same as the original view frame
}
I first tried to convert the root view to the destination view's coordinates and then do the CGRectIntersect on the view frame, but it did not work. But I got it working the reverse way for UIViews with the root view as their superview. Then after some spelunking I figured out that I had to navigate thru the view hierarchy for subviews.
It works for UIViews where the superview is the root view and also for UIViews that are subviews of other views.
I tested it by drawing borders around these visible rects on the initial views, and it works perfectly.
BUT ... it does NOT work correctly if a UIView is scaled (!=1) AND a subview of another UIView other than the root view. The origin of the resultant visible rect is offset by a bit. I tried a few different ways to adjust the origin if the view is in a subview but I couldn't figure out a clean way to do it.
I've added this method to my utility UIView category, along with all the other "missing" UIView methods I've been developing or acquiring. (Erica Sadun's transform methods ...I'm not worthy...)
This does solve the problem I was working on though. So I will post another question regarding the scaling problem.
EDIT:
While working on the question and answer for the scaling issue, I came up with a better answer for this question too:
// return the part of the passed view that is visible
- (CGRect)getVisibleRect:(UIView *)view {
// get the root view controller (and it's view is vc.view)
UIViewController *vc = UIApplication.sharedApplication.keyWindow.rootViewController;
// get the view's frame in the root view's coordinate system
CGRect rootRect = [vc.view convertRect:view.frame fromView:view.superview];
// get the intersection of the root view bounds and the passed view frame
CGRect rootVisible = CGRectIntersection(vc.view.bounds, rootRect);
// convert the rect back to the initial view's coordinate system
CGRect visible = [view convertRect:rootVisible fromView:vc.view];
return visible; // may be same as the original view frame
}
Hi Im making a simple game with the basic UIKit stuff where there is an object that pops up on the screen.
I'm trying to make it so that every time the object pops up the screen will scroll to the object and center it on screen. Basically I have a UIView that has the objects that popup within it and that UIView is a subview of a UIScrollView. All of this is a subview of self.view of my ViewController. I'm using the UIScrollview to scroll through the contents of its subview with the objects in it. I'm not sure if a UIScrollView is the ideal option for what I want to do but I was looking for a way to scroll the position of the object and center it in the middle of the device. Ideally with animation.
If anyone knows of a method or maybe a formula that could help me out that would be awesome. Thanks in advance :D
Update:
I don't really have much code in regards to this except for adding the views within each other :
self.world = [[UIView alloc]initWithFrame:CGRectMake(0, 0, currentDeviceWidth*4, currentDeviceHeight*2.2)];
self.world.backgroundColor = [UIColor blueColor];
_scrollView = [[UIScrollView alloc] initWithFrame:[[self view] bounds]];
[_scrollView setContentSize:self.world.frame.size];
[_scrollView addSubview:self.world];
[[self view] addSubview:_scrollView];
but below is a simple image of what I want to accomplish. The arrows are just a representation of the possible scrolling direction.
Apple object is off the side of the screen Note: apple object is a subview of self.world and self.world is a subview of scrollview
The finish look is where now the scrollview has scroll self.world to where the apple object is in the center of the screen
Just looking to basically accomplish how a user could manually scroll the object to the center but instead do it automatically without the use of a user's touch.
I think you may need contentOffset which is a property of UIScrollView. This property controls the position of the contentView.
Now let's say, your apple is in the center of the self.world, then animated put it in the middle is like this:
[UIView animateWithDuration: 0.5//you can put any float as you want
animations:^{self.world.contentOffset = CGPointMake((_scrollview.frame.size.width - self.world.frame.size.width) / 2, (_scrollview.frame.size.height - self.world.frame.size.height) / 2);
}];
If you put your apple in any other position, you should calculate the position yourself, and set the contentOffset to the right one. I think any position other than center is much complicated, you calculation should involve the position of the apple in the self.world view.
Did you try
[_scrollView scrollRectToVisible:newView.frame animated:(BOOL)animated]
What might be tricky about what you are trying to do is positioning views such that they are always within the coordinate system of the _scroll view, e.g. x >= middle of the view & y >= middle of the view.
I have a very strange problem. I trying to rotate and move a UIView's superview manually in viewDidAppear like so:
- (void)viewWillAppear:(BOOL)animated
{
// ...
[self.view.superview setTransform:CGAffineTransformMakeRotation(M_PI/2)];
[self.view.superview setCenter:CGPointMake(100, 200)]; // (100, 200) is toy value
// ...
}
For some reason, the rotation is applied correctly but the superview's center (i.e. position) is not moved at all. I've also tried setting the transform to a CGAffineTransform that's a combination of a rotation + translation (or just a translation alone), and that won't move the superview either.
If it makes a difference, self.view.superview is the top-most view (i.e. self.view.superview.superview is nil).
Am I missing something very simple here?
Edit: nielsbot's comment was correct in that putting it in viewDidLoad worked, but by then, the view has already appeared so there's a flicker where it snaps to the new location. Is there a way around this?
Try setting the bounds of the view so:
[self.view.superview setBounds:CGRectMake(x,y,self.view.superview.width,self.view.superview.height)];
This should move your view to the x,y position you give him
But of course this is not the center
The center just represents a special point that is for example used for rotations
I have a view that is slightly translucent, I set the alpha to about .75 and it contains a button as a sub element.
I want the button to be completely opaque and I set the opaque property in IB but still the button appears as translucent.
Any pointers?
Thanks!
A subview of a superview is allways minimum as transparent as its subview.
Subview alpha = 0.5 and superview alpha = 0.1 would result in an alpha of the subview of 0.05.
The only way of achieving that is changing the view hierarchy. Your subview must not be a subview any more. It may still be at the same position. (May require different position value).
An example.
Your background view is backgroundView
Your superview is firstView
Your subview is overlayView
Your current hierarchy is
backgroundView -> firstView -> overlayView
You should change that to:
backgroundView -> first View
\-> overlay View.
If your firstView's position is (10, 10) and your overlayView's position was (20,20) then change your overlayView's position to (30,30) because it now is within the coordinate system of background view.
For your code:
At some point you used to have
[backgroundView addSubView:firstView];
[fisrtView addSubView:overlayView];
change that to
[backgroundView addSubView:firstView];
[backgroundView addSubView:overlayView];
If you did not code that but defined it within IB then just move overlayView within the views tree accordingly so that it is on the same level as firstView.
Regardless whether you code it or draw it in IB, make sure that firstView comes first and overlayView comes next. Otherwise firstView could hide overlayView when its alpa is greater than 0.
I have a scroll view with 2 different subviews for two different orientation.
In portait mode, it shows a table view and in portait it shows the UIImageView.
I want to know the ideal way to handle the orientation.
I am having glitches with my current way of handling
1.Load a view,and add scrollview as a subview to the root view.
2.Change orientation,
3.Change the frame and contents of the scrollview.
4.Add this modified scrollview as subview again.
But, every time I change orientation,the new view gets added on top of the previous one.
If you want to have two different views for different orientations, you need to switch them while orientation is changing.
When you go from portrait to landscape, you have to remove UIImageView and add scrollview (and vice versa)
[myImageView removeFromSuperview];
[self.view addSubview:scrollView];
You can also check if view doesn't have a superview to be sure that you have to add it:
if(scrollView.superview == nil)
[self.view addSubview:scrollView];
As you have already added scrollView as subView so you do not need to add it as subView again.
Just change the frame and contentSize of scrollView.
for Views do as
[scrollView.subView removeFromSuperView]
[scrollView addSubView:view1]; // or add view2