I want to count total no of subview in a view and also release that subviews in my iphone application how i can do it? provide me suggestion.Thanks.
//count subviews
NSUInteger count = [[view subViews] count];
for (UIView *v in [view subViews])
{
[v removeFromSuperView];
//if 'v' was not autoreleased add next line as well
[v release];
}
NSArray * subviews = [view subviews];
int count = [subviews count];
for(UIView * v in subviews)
{
[v removeFromSuperview];
}
I want to count total no of subview in a view
NSUInteger count = view.subviews.count;
and also release that subviews in my iphone application
Don't. The view retains its subviews for you. Just add and remove views as needed, and let the view system handle reference counting correctly. If you need to retain a reference, hold that reference elsewhere (in your own variables).
Related
I am having a little problem. I want to make all my scrollview scroll to the top when I press a UITableViewCell. Following is the code in didSelectRowAtIndexPath:
[self.tableView setContentOffset:CGPointZero];
[verbTableView setContentOffset:CGPointZero];
[seinhabenScrollView setContentOffset:CGPointZero];
[mdhPresensScroll setContentOffset:CGPointZero];
[mdhPreteritumScroll setContentOffset:CGPointZero];
[mhdScroll setContentOffset:CGPointZero];
....
There are more of those scrollview, and I want to put the all in one single object or something... I have tried following code:
for (UIScrollView *scrolls in topLayer.subviews)
{
[scrolls setContentOffset:CGPointZero];
}
Thanks!
The basic idea is right. It just depends upon how you identify the scroll views. You could do something like the following, which explicitly tests whether the subview is a kind of UIScrollView:
for (UIScrollView *scrollView in self.view.subviews)
{
if ([scrollView isKindOfClass:[UIScrollView class]])
scrollView.contentOffset = CGPointZero;
}
Or you can explicitly reference the specific scrollviews in question (in which case the class membership test isn't strictly needed):
for (UIScrollView *scrollView in #[seinhabenScrollView, mdhPresensScroll, mdhPreteritumScroll])
{
scrollView.contentOffset = CGPointZero;
}
Or, if you create an IBOutletCollection in IB, you can use that, too:
for (UIScrollView *scrollView in self.scrollViews)
{
[scrollView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES];
}
(Note, in that final example, I'm scrolling to the location in question with animation, providing the user some visual cue as to what just happened; that's completely up to you.)
In a comment above, you say that topView has subviews which, themselves, have subviews that are scrollviews, you'd have to do something like the following to handle this subview-of-subview situation:
for (UIView *subview in topLayer.subviews)
{
for (UIScrollView *scrollView in subview)
{
if ([scrollView isKindOfClass:[UIScrollView class]])
scrollView.contentOffset = CGPointZero;
}
}
Avoiding the dynamic type check, just place the views that can scroll into an array. Then, a little fancier, add an extension to scroll view so they can scroll to zero using no params, that let's us do the scrolling with an NSArray one-liner (makeObjectsPerform...)...
#interface UIScrollView (ScrollToZero)
- (void)scrollToZero; // a no-param method for scrolling to zero offset
#end
#implementation UIScrollView (ScrollToZero)
- (void)scrollToZero {
[self setContentOffset:CGPointZero animated:YES];
}
#end
NSArray *allMyScrolls = #[verbTableView, seinhabenScrollView, // and so on. put ONLY scrollViews in here
// you can make this array a property, initialized when the views are created
[allMyScrolls makeObjectsPerformSelector:#selector(scrollToZero)];
I have three different views in my iPhone app, and when the user presses a button, I need the view to change to either of the three views randomly. I've found this code, but i don't know how to load images..sorry but i'm newbie....!!
- (IBAction) yourBtnPressed : (id) sender
{
int i = arc4random() % 3;
if(i == 1)
{
//load first view
}
else if(i == 2)
{
//load second view
}
else
{
//load third view
}
}
if view are all in the same viewcontroller you can simply write
self.view = firstView;
or for more cool transition you can use these method
+ transitionWithView:duration:options:animations:completion:
+ transitionFromView:toView:duration:options:completion:
see apple documentation:
http://developer.apple.com/library/IOs/#documentation/UIKit/Reference/UIView_Class/UIView/UIView.html
If your views are in a .xib file you can use this code:
[self.view addSubview:aView];
If you think to create your views programmatically, then:
UIView *aView = [[UIView alloc] initWithFrame:aFrame];
// add contents to your aView here
[self.view addSubview:aView];
[aView release]; // if you don't need it anymore
I have one class in which i have two method _addView() and _removeView().
And these method i am using in another class for adding view and removing view but its not working.If i am using in the same then its working.
For Remove-
- (id)deleteBoxAtIndex:(int)boxIndex{
for (int i = 0; i < [[self subviews] count]; i++ ) {
[[[self subviews] objectAtIndex:boxIndex] removeFromSuperview];
}
return self;
}
Then how i count the subviews in that class or remove from that class.
You correct in trying to use [self.subviews count] to count the number of subviews, but there is an elegant way to remove all subviews from a view in Objective-C. Try this:
[self.subviews makeObjectsPerformSelector:#selector(removeFromSuperView)];
You should pass a pointer to the UIView instance (the one that has got the subviews) to the other object so that you can call:
myView.subviews
I don't know if this could work for you:
- (id)deleteBoxAtIndex:(int)boxIndex fromView:(UIView*)view {
for (int i = 0; i < [[view subviews] count]; i++ ) {
[[[view subviews] objectAtIndex:boxIndex] removeFromSuperview];
}
return self;
}
If you give more detail about the relationship between the two classes you mention (basically, the names and how one interact with the other), I could give you more hints.
Your problem not in retrieving the count but in fact that your relay on a count that changes dynamically inside of your for loop logic execution. Do cleanup of subviews in the following way:
while([[self subviews] count] > 0) {
UIView *view = [[self subviews] objectAtIndex:0];
[view removeFromSuperview];
}
You can use the superview property:
[[self superview] subviews]
to do the similar loop you are doing right row. However I'd strongly encourage you to use
[[self superview] viewWithTag:boxIndex]
instead of objectAtIndex: method
Just do a loop of all subViews u want to remove:
for (UIView *subs in [self.view subviews]){
[subs removeFromSuperview];
}
I am not able to Hide the iphone Camera shutter opening animation for my app.
I am using UIImagePickerController to access iphone camera and using my own overlay controllers.
Is there a way to remove the initial shutter(also known as Iris) animation as the camera starts.
Thank You
[EDIT]
For those who wants to know the way to change the camera iris animation.
The below function is called before the camera iris animation starts.
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
// Here is were I make the camera preview fit the entire screen.
// This might violate the "don't change the view hierarchy"-rule.
// So I am not sure if it is valid for App Store commitment.
// However, the NSLogs are used to
// figure out which subview is the actual Camera Preview which turns out
// to be the PLPreviewView. (uncomment to se the printouts).
// Change it's size to fit the entire screen (and scale it accordingly
// to avoid distorted image
NSLog(#"WillShowViewController called...");
NSLog(#"VC:view:subviews\n %#\n\n", [[viewController view] subviews]);
NSLog(#"VC:view:PLCameraView:subviews\n %#\n\n", [[[[viewController view] subviews] objectAtIndex: 0] subviews]);
NSLog(#"VC:view:PLCameraView:PLPreviewView:subviews\n %#\n\n", [[[[[[viewController view] subviews] objectAtIndex: 0] subviews] objectAtIndex: 0] subviews]);
NSLog(#"VC:view:PLCameraView:PLCropOverLay:subviews\n %#\n\n", [[[[[[viewController view] subviews] objectAtIndex: 0] subviews] objectAtIndex: 1] subviews]);
NSLog(#"VC:view:PLCameraView:UIImageView:subviews\n %#\n\n", [[[[[[viewController view] subviews] objectAtIndex: 0] subviews] objectAtIndex: 2] subviews]);
}
In the above function you can go through each layer by using the normal NSMuatableArray syntax like objectAtIndex
hope this might help you.
Regards,
Ankur
Using this answer as a starting point, I've finally solved this problem:
NOTE: This is obviously not 3.3.1-compliant.
Listen for the UINavigationControllerDidShowViewControllerNotification on your UIImagePickerController, and the PLCameraViewIrisAnimationDidEndNotification globally.
Traverse the view hierarchy (starting at the main UIWindow) looking for the PLCameraView. Save the index of the view against the main UIWindow, as you'll need it later.
Remove the PLCameraView from its superView. If desired, insert your own view at global index 0.
When the iris animation is finished, remove your view and re-add the PLCameraView at its original index.
Came across a similar: I wanted to have the shutter appear when I take the picture triggered by a button in a self.cameraOverlayView of a UIImagePickerController. Arrived to this page, did some extra research and came to this solution.
Synopsis:
#interface MyController : UIImagePickerController
...
- (id) init {
...
self.cameraOverlayView = _my_overlay_;
self.showsCameraControls = NO;
...
}
...
- (void) onMyShutterButton {
[self takePicture];
// You want the shutter animation to happen now.
// .. but it does not.
}
Solution:
// Some constants for the iris view and selector
NSString* kIrisViewClassName = #"PLCameraIrisAnimationView";
SEL kIrisSelector = NSSelectorFromString(#"animateIrisOpen");
#implementation MyController {
...
UIView* iris_;
}
- (void) viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
// Find the iris view in the siblings of your overlay view
for (UIView* view in self.cameraOverlayView.superview.subviews) {
if ([kIrisViewClassName isEqualToString:[[view class] description]]) {
// It will be hidden by 'self.showsCameraControls = NO'.
view.hidden = false;
// Extra precautions - as this is undocumented.
if ([view respondsToSelector:kIrisSelector]) {
iris_ = view;
}
break;
}
}
}
- (void) animateIrisOpen {
if (iris_) {
[iris_ performSelector:kIrisSelector];
}
}
...
- (void) onMyShutterButton {
[self takePicture];
[self animateIrisOpen]; // Voila - the shutter happens
}
I've messed around with this a bit, but sending various combinations of the view lifecycle methods to the image picker. (viewWillAppear, viewDidAppear, etc.) But I don't remember which ones ended up working.
Sorry for replying getting back so late. I found out the solution for that well I played around with the view hierarchy of the cameraView and added my own layer at the top of everything. The animation took place there and once the shutter was open the top most layer was removed. If someone need any further help with the code please let me know, I will provide with the exact steps and syntax.
-Ankur
joshwa's answer completely hides the entire camera view for the duration of the iris animation. For my purposes, I needed the camera view visible, just without the iris animation. I was able to accomplish this with a little tweaking of his method. As others have noted, this may or may not be allowed on the app store since we're messing with the view hierarchy as well as listening for undocumented notifications.
3 ivars are needed:
UIImagePickerController *imagePickerController;
UIView *plCameraIrisAnimationView; // view that animates the opening/closing of the iris
UIImageView *cameraIrisImageView; // static image of the closed iris
Hide the closed iris image and remove the animation view. I tried simply hiding the animation view as well, but the animation was still visible:
- (void)receivedNavigationControllerDidShowViewControllerNotification:(NSNotification *)notification {
UIView *view = imagePickerController.view;
[plCameraIrisAnimationView release];
plCameraIrisAnimationView = nil;
cameraIrisImageView = nil;
while (view.subviews.count && (view = [view.subviews objectAtIndex:0])) {
if ([[[view class] description] isEqualToString:#"PLCameraView"]) {
for (UIView *subview in view.subviews) {
if ([subview isKindOfClass:[UIImageView class]]) {
cameraIrisImageView = (UIImageView *)subview;
}
else if ([[[subview class] description] isEqualToString:#"PLCropOverlay"]) {
for (UIView *subsubview in subview.subviews) {
if ([[[subsubview class] description] isEqualToString:#"PLCameraIrisAnimationView"]) {
plCameraIrisAnimationView = [subsubview retain];
}
}
}
}
}
}
cameraIrisImageView.hidden = YES;
[plCameraIrisAnimationView removeFromSuperview];
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"UINavigationControllerDidShowViewControllerNotification" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receivedPLCameraViewIrisAnimationDidEndNotification:) name:#"PLCameraViewIrisAnimationDidEndNotification" object:nil];
}
When the animation is over, unhide the iris image and re-add the animation view:
- (void)receivedPLCameraViewIrisAnimationDidEndNotification:(NSNotification *)notification {
cameraIrisImageView.hidden = NO;
UIView *view = imagePickerController.view;
while (view.subviews.count && (view = [view.subviews objectAtIndex:0])) {
if ([[[view class] description] isEqualToString:#"PLCameraView"]) {
for (UIView *subview in view.subviews) {
if ([[[subview class] description] isEqualToString:#"PLCropOverlay"]) {
[subview insertSubview:plCameraIrisAnimationView atIndex:1];
[plCameraIrisAnimationView release];
plCameraIrisAnimationView = nil;
break;
}
}
}
}
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"PLCameraViewIrisAnimationDidEndNotification" object:nil];
}
The below function is called before the camera iris animation starts.
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
// Here is were I make the camera preview fit the entire screen.
// This might violate the "don't change the view hierarchy"-rule.
// So I am not sure if it is valid for App Store commitment.
// However, the NSLogs are used to
// figure out which subview is the actual Camera Preview which turns out
// to be the PLPreviewView. (uncomment to se the printouts).
// Change it's size to fit the entire screen (and scale it accordingly
// to avoid distorted image
NSLog(#"WillShowViewController called...");
NSLog(#"VC:view:subviews\n %#\n\n", [[viewController view] subviews]);
NSLog(#"VC:view:PLCameraView:subviews\n %#\n\n", [[[[viewController view] subviews] objectAtIndex: 0] subviews]);
NSLog(#"VC:view:PLCameraView:PLPreviewView:subviews\n %#\n\n", [[[[[[viewController view] subviews] objectAtIndex: 0] subviews] objectAtIndex: 0] subviews]);
NSLog(#"VC:view:PLCameraView:PLCropOverLay:subviews\n %#\n\n", [[[[[[viewController view] subviews] objectAtIndex: 0] subviews] objectAtIndex: 1] subviews]);
NSLog(#"VC:view:PLCameraView:UIImageView:subviews\n %#\n\n", [[[[[[viewController view] subviews] objectAtIndex: 0] subviews] objectAtIndex: 2] subviews]);
}
In the above function you can go through each layer by using the normal NSMuatableArray syntax like objectAtIndex
hope this might help you.
Regards,
Ankur
To expound on Catalin's answer, (which was great btw), I found if you change the method "animateIrisOpen" slightly, the presentation is a fraction better... but noticeable.
- (void) animateIrisOpen {
if (iris_) {
iris_.hidden = NO;
[iris_ performSelector:kIrisSelector];
}
}
How should I be handling, or rather NOT handling (ignoring), touches to my background view? It happens to be the view of my View Controller which has subviews (objects) that I DO want to respond to touch events. Setting userInteractionEnabled = NO for the view seems to turn off ALL interaction for the subviews as well.
I'm currently testing for
if ([[touch view] superview] == self.view)
in touchesBegan/Moved/Ended. But I'm trying to eliminate some conditional testing so looking for a better way...
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event; recursively calls -pointInside:withEvent:. point is in frame coordinates
If you override that in your background view, you can specify which subview gets hit - you can be lazy and just ask each of your subviews if they would return yes to it, and never return yourself (return nil if they all return nil). Something like:
UIView *hitView = nil;
NSArray *subviews = [self subviews];
int subviewIndex, subviewCount = [subviews count];
for (int subviewIndex = 0; !hitView && subviewIndex < subviewCount; subviewIndex++) {
hitView = [[subviews objectAtIndex:subviewIndex] hitTest:point withEvent:event];
}
return hitView;
Thanks for the answer Dan, great question too.
However the accepted answer has an error: hitTesting subviews should be done with the point converted to the subview.
Also, subviewIndex is already defined before 'for'.
Since subviews are ordered according to their z index, iterating should go from the last to the first one (see Event handling for iOS - how hitTest:withEvent: and pointInside:withEvent: are related? and How to get UIView hierarchy index ??? (i.e. the depth in between the other subviews)).
Here's the updated code:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
UIView *hitView = nil;
NSArray *subviews = [self subviews];
int subviewIndex, subviewCount = [subviews count];
for (subviewIndex = subviewCount-1; !hitView && subviewIndex >= 0; subviewIndex--) {
UIView *subview = [subviews objectAtIndex:subviewIndex];
hitView = [subview hitTest:[self convertPoint:point toView:subview] withEvent:event];
}
return hitView;
}