I have an array of views that are also subviews of a base view. I want to efficiently remove all views that are not inside the frame of the base view (i.e. not visible).
I'm looking for suggestions to find the most efficient method besides of computing the intersection of all frames with the base view frame.
If you want to remove your subviews when they are not inside the base view's frame, you will need to calculate their frames intersections with the base view. Alternatively, you could use bool CGRectContainsRect ( CGRect rect1, CGRect rect2 ); instead of fully calculating the intersection.
If you are trying to do this to optimize subview drawing, you can think of using the UIView'scliptobounds property, instead of removing the subviews:
clipsToBounds
A Boolean value that determines whether subviews are confined to the bounds of the receiver.
#property(nonatomic) BOOL clipsToBounds
Discussion
Setting this value to YES causes subviews to be clipped to the bounds of the receiver. If set to NO, subviews whose frames extend beyond the visible bounds of the receiver are not clipped. The default value is NO.
Related
I have a simple test app that has one view, one view controller, and all of this is instantiated via a standard storyboard. When I run my app and pause on a breakpoint in my view controller I can see that the following values are set on the view:
self.view.layer.position = (CGPoint) (x=160, y=294)
self.view.layer.frame = (CGRect) (origin=(x=0, y=20) size=(width=320, height=548))
self.view.layer.visibleRect = (CGRect) (origin=(x=0, y=0) size=(width=320, height=548))
I understand the initial origin value for the frame (assuming the value of 20 is an offset for the status bar), but where is the 160/294 value coming from for the layer's position? I'm baffled by this one.
This is because a CALayer's position property is relative to its anchorPoint. By default, the anchorPoint is set to (0.5, 0.5), which represents the center of the layer's bounds.
If you're trying to perform very basic positioning changes programmatically, I'd stay away from your view's layer property, since UIView has positioning properties of its own.
I have a problem I've run into with the UIView method convertRect: fromView: method. Here is the situation:
I have an overwritten the UIView class to create a view that rotates with the user's movement(very similar to the TaskRabbit spinner). To create the rotation, over I added an additional view to my subclassed view, and I rotated that view. The rotated view contains additional subviews that obviously rotate with the rotated subview. The problem is, after the subview has been rotated, I need to find where those additional subviews are, with respect to the original overritten view - not the rotated view. To do this, in my UIView class, I have the following:
[self convertRect:currentView.frame fromView:rotationView];
However, when I print out the frame of the converted rect, the coordinates are not accurate. Has anyone run into this issue where the convertRect: fromView: isn't accurate after the view is rotated?
Edit
Specifically, about the points being not accurate, I can't even see the relationship between what is should be and what it is-ie off by an specific angle, x/y flipped etc. For example, the point that should be (25, 195) is returned at (325.25, 273.16)
I'm assuming that you are rotating your views by applying a transform to them (either a CGAffineTransform to the view or a CATransform3D to the layer). This is what is causing the problem with your frame. The documentation for UIView frame says:
Warning If the transform property is not the identity transform, the value of this property is undefined and therefore should be ignored.
As you've already seen, the value of the frame is undefined. You can still use the center and bounds properties though.
I have a view in which I am doing some specific drawings in drawRect. These drawings are dynamic and are based on the view's width and height. Then, the view which contains it applies a rotation transformation to it. However this transformation seems to adjust the values for my view's frame which impacts my drawing in drawRect.
NSLog(#"before:%f,%f,%f,%f",button.frame.origin.x,button.frame.origin.y,button.frame.size.width,button.frame.size.height);
CGAffineTransform currentTransform = button.transform;
CGAffineTransform transformRotate = CGAffineTransformMakeRotation(degreesToRadians);
button.transform = transformRotate;
NSLog(#"after:%f,%f,%f,%f",button.frame.origin.x,button.frame.origin.y,button.frame.size.width,button.frame.size.height);
Here is the output:
before:50.000000,100.000000,150.000000,50.000000
after:65.849365,47.548096,118.301262,154.903809
Is this correct behaviour or am I applying the transformation incorrectly?
See the reference documentation on UIView's frame property;
frame
The frame rectangle, which describes the view’s location and size in
its superview’s coordinate system.
#property(nonatomic) CGRect frame
Warning
If the transform property is not the identity transform, the value of
this property is undefined and therefore should be ignored.
Despite that warning, things work as intended. Once a transformation (other that identity) is applied, the frame usually results into the projection rectangle of the original view.
But then again, you should not ignore that warning if you really want to find out about the frame with the applied transformation and use CGRectApplyAffineTransform for properly getting it.
I have an instance of UIScrollview containing an instance of UIView. The UIView is just a container for a horizonal array of UIImageView instances. - Zooming is provided by UIScrollView and UIScrollViewDelegate. I would like to constrain zooming to occur only along the horizontal axis with no vertical scalling at all. How to I do this?
Is there a way, for example, to subclass UIView and override the appropriate method to prevent vertical scaling? I like this approach but I am unclear on which method to override and what that overridden method should actually do.
Cheers,
Doug
Similar to what I describe in this answer, you can create a UIView subclass and override the -setTransform: accessor method to adjust the transform that the UIScrollView will try to apply to your UIView. Set this UIView to host your content subviews and make it the subview of the UIScrollView.
Within your overridden -setTransform:, you'll need to take in the transform that the UIScrollView would like to apply and adjust it so that the scaling only takes effect in one direction. From the documentation on how CGAffineTransform matrices are constructed, I believe the following implementation should constrain your scaling to be just along the horizontal direction:
- (void)setTransform:(CGAffineTransform)newValue;
{
CGAffineTransform constrainedTransform = CGAffineTransformIdentity;
constrainedTransform.a = newValue.a;
[super setTransform:constrainedTransform];
}
Using OS 3.0, you can tell the zoom to zoom to a rect in the scrollview. I have this in my logic that detects taps.
CGRect zoomRect = [self zoomRectForScale:newScale withCenter:CGPointMake(tapPoint.x, tapPoint.y) inScrollView:scrollView];
[scrollView zoomToRect:zoomRect animated:YES];
The for the other part, you will have to stretch your image views by the ratio that the new frame has against the original, and center it in the same center point. You can do this in an animation timed the same as the zoom animation so that it looks right, but I think this will be the only way to do it.
In scrollViewDidZoom:, adjust your content view's variables based on zoomScale, reset zoomScale to 1.0, then do setNeedsDisplay on the content view. Handle the actual zoom (in whatever direction you want) in your content view's drawRect:.
The Ugly Details:
While the zoom is in progress, the UIScollView changes contentOffset and contentScale, so save those prior values in scrollViewWillBeginZooming: and in scrollViewDidZoom: so you can compute a new contentOffset yourself according to the zoom.
Since changing zoomScale will immediately fire another scrollViewDidZoom:, you must set a BOOL before (and clear after) resetting the zoomScale. Test the BOOL at the start of scrollViewDidZoom: and return if true.
You may need to inhibit scrollViewDidScroll: while the zoom is in progress (test a BOOL; set it in scrollViewWillBeginZooming: and clear it in scrollViewDidEndZooming:) so your own contentOffsets are used while the zoom is in progress.
I have a UIImageView that can be resized by pinching in and out (Example: view.frame.size.width+10). The image of the Image View can also be rotated (CGAffineTransformMakeRotate). Okay, here is the problem: When I resize the UIImageView AFTER having had applied a Rotate Transform the view resizes abnormally (inversly (shrink when it should grow, vice-versa) or at enormous resize unit increments). How can I resize my UIImageView in a consistent manner whether or not a CGAffineTransform is applied?
There's a warning in the documentation for UIView that says, for the frame property:
Warning: If the `transform` property is not the identity transform, the value of this property is undefined and therefore should be ignored.
Use the bounds and center properties instead; they remain viable after a transform is applied.