How to remove an NSView's subview - nsview

I have a problem with an NSView's subview. I'm trying to use an NSArray to retrieve [myView subviews] (in which I have only one view) and I want to remove this subview but I don't know how to do it. I have tried
NSArray *subviews = [self.mainView subviews];
[self.mainView replaceSubview:subviews[0] with:[self.mainViewController view]];
but XCode crashes and I get this log into the console :
-[NSEvent subviews]: unrecognized selector sent to instance 0x102202aa0
I don't know what the problem is....
So if some of you could help me, that would be very kind...

Well, shame on me !
I was actually looking for a problem at the wrong place...
What I ended up doing is this : I have two subviews in my mainView, the one at index 0 is a background NSimageView (which I want to keep) and the second one (at index 1) is the one I want to replace.
So here's the solution :
NSArray *subviews = [self.mainView subviews];
NSView *secondSubView = [subviews objectAtIndex:1];
[self.mainView replaceSubview:secondSubView with:[self.myViewController view]];
Enjoy !

Related

addSubview not working

// Create and add a sub view
CGRect viewRect = CGRectMake(0, 0, 200, 200);
UIView *a_sub_view = [[UIView alloc] initWithFrame : viewRect];
[window addSubview : a_sub_view];
After adding the above 3 lines of code, xcode produces no errors or warnings. But the sub-view is not showing at all. The sample program seems to be running exactly as before. Hope that somebody knowledgable could help.
I find it useful to set the background color so I know where the view is and the boundaries.
a_sub_view.backgroundColor = [UIColor redColor];
In your example, you're create an empty view so you won't 'see' anything.
window expects a viewcontrollers view to be added.
you can then add subviews to the current view.
so in your example use:
[self.view addSubview:a_sub_view];
I am using this in order to "find" the window:
UIWindow *window = [[[UIApplication sharedApplication] delegate] window];
[window addSubview:myView];
This also worked for me, but it is a bit uglier:
[self.navigationController.tabBarController.view addSubview:myView];
To explain the second one, I had to "follow" the controllers back up to the "top" view. (My application has a tab bar with a navigation controller inside the current tab.)
If you are working with iOS 5 & above , you have to do as below:
[self.window.rootViewController.view addSubView:viewObject];
[self.view addSubView: a_sub_view];

iphone: uiscrollview doesn't scroll? but contentsize is set..?

hey people,
I have some data and want to show this in a new view inside a navigation-stack.
I created some new viewcontroller class with XIB file. Then I edited the XIB file and placed the following hierachy:
1 files owner
2 first responder
3 scrollview
3.1 view
3.1.1 label1
3.1.2 label2
3.1.3 label3
3.1.4 image4
I arranged the labels and the image. the content of the labels may differ and they should size dynamically. I also did the IBOutlets in the viewcontroller class and connected everything correctly. the files owner's view delegate is set to view..
then I load the viewcontroller and I do in the "viewDidLoad" - method the following:
- (void)viewDidLoad {
[super viewDidLoad];
self.currentPageURL.text = [self.offerItem objectForKey: #"page-url"];
self.currentPrice.text = [self.offerItem objectForKey: #"price"];
self.currentRank.text = [self.offerItem objectForKey: #"rank"];
self.currentName.text = [self.offerItem objectForKey: #"name"];
self.currentProducerName.text = [self.offerItem objectForKey: #"producer-name"];
self.currentDescription.text = [self.offerItem objectForKey: #"description"];
self.imageViewForImage.image = [helperClass resizeImage:[self.offerItem objectForKey: #"picture"] forSize:CGSizeMake(280.0, 280.0) ];
[theScrollview setScrollEnabled:YES];
[theScrollview setContentSize:CGSizeMake(320, 1200)];
[theScrollview flashScrollIndicators];
[theScrollview addSubview:theView];
}
when I start the app in my simulator, everything is shown, but if I try to scroll, nothing happens..
what do I do wrong?
Autolayout set some constraints after the view loads, so, pick your code that sets the content size in viewDidLoad and put in viewDidAppear, and your code won't be rewritten.
This worked for me.
-(void)viewDidAppear:(BOOL)animated{
[self.scrollView setContentSize:CGSizeMake(320, 1000)];
}
and sorry for my poor english.
Ensure that "Use Autolayout" is unchecked in the IB Document attributes. I had the exact same issue, setting the correct contentSize and all, but with this feature enabled, scrolling was always disabled.
UPDATE To use Autolayout, explicitly set the width and height of the scrollView's content in the viewDidAppear method, like this:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
// set the scrollview to the specified size
CGRect screenRect = [[UIScreen mainScreen] bounds];
[scrollView setContentSize:CGSizeMake(screenRect.size.width, 1100)];
[scrollView setBounds:CGRectMake(0, 0, screenRect.size.width, screenRect.size.height)];
[scrollView setScrollIndicatorInsets:UIEdgeInsetsFromString(#"{0,0,0,-1.0}")];
}
Immediately change the frame of theScrollView to 320x480 and you should see scrolling.

Programmatically getting the "Z" position of a UIView compared to it's siblings

My class has logic for inserting views in certain levels in the hierarchy.
containerView = [[UIView alloc] init];
shadowView = [[UIView alloc] init];
contentView = [[UIView alloc init];
[containerView addSubview:shadowView];
[containerView insertSubview:contentView belowSubview:shadowView];
Later down the line, it flips them so the shadow view is below the content view instead of above it.
// "Flipping" their positions.
[containerView insertSubview:contentView aboveSubview:shadowView];
UIView has a subviews property returning an NSArray, unfortunately the array does not reflect the view stack ordering.
I want to unit test the placement of the view compared to it's siblings. How can I do that?
Here's an example of a test.
- (void)testViewHierarchyFlipping {
STAssertEquals(containerView, shadowView.superview, nil);
STAssertEquals(containerView, contentView.superview, nil);
// Test that shadowView is ABOVE contentView.
}
You can inspect the containerView.subviews property to determine the Z position of each subview.
Items at the beginning of the array are deeper than items at the end of the array.
I believe this should work for your test, although I don't have access to Xcode to verify that it's correct at the moment.
- (void)testViewHierarchyFlipping {
STAssertEquals(containerView, shadowView.superview, nil);
STAssertEquals(containerView, contentView.superview, nil);
// Test that shadowView is ABOVE contentView.
UIView *topView = (UIView *)[[containerView subviews] lastObject];
UIView *bottomView = (UIView *)[[containerView subviews] objectAtIndex:0];
STAssertEquals(shadowView, topView, nil);
STAssertEquals(contentView, bottomView, nil);
}

How to reset UIWebView's zoom? I'm already using scalesPagesToFit = YES;

I've been looking for the past week for the answer to this question.
I have a UIWebView, inside of a UIScrollView. Everything works great, but I want the content of the UIWebView to reset its zoom, when the orientation changes.
In the HTML inside the UIWebView, I set the width of the viewport (w/ a meta tag) to "device-width" and then on the Obj-C side, I set the scalesPagesToFit = YES;
I've tried resetting the zoom with javascript; by replacing the meta tags in runtime; reloading; accessing the UIScrollView inside of the UIWebView; etc...
but with no success.
Any of you gods know a workaround?
The only one I can think off is to recreate the UIWebViews every time we change the orientation, but that makes them flash to white whilst rendering content, which looks terrible :(
Any thoughts?
Many thanks,
Andre
I'm just guessing here and haven't tried, but AFAIK a UIWebView has a UIScrollView child. So one should be able to do:
for (UIScrollView *scroll in [myWebView subviews]) {
// Make sure it really is a scroll view and reset the zoom scale.
if ([scroll respondsToSelector:#selector(setZoomScale:)])
[scroll setZoomScale:1.0];
}
On iOS 5+ you have access to scrollView.
Just do:
[webView.scrollView setZoomScale:1.0];
If you want to do it programmatically this is the only way I could find to accomplish it: (specify your own sizes if you wish, i was attempting to zoom out after typing into a form field)
UIScrollView *sv = [[webViewView subviews] objectAtIndex:0];
[sv zoomToRect:CGRectMake(0, 0, sv.contentSize.width, sv.contentSize.height) animated:YES];
Update:
Downscaling wasn't working properly when using
[[[webView subviews] lastObject] setZoomScale:0.25];
The quality of the images being downscaled on the page was awful. Doing:
[[[webView subviews] lastObject] setZoomScale:0.25 animated:YES];
Fixed it. So that last line is the one you could use.
webView was subclassed of a UIWebView which lies on some IB file. I didn't use the Viewport at all. I find that one should pick by either doing this from the Cocoa Touch side or use JS.
I used:
webView.scalesPageToFit = YES;
I wonder if there's a way of resetting the scalesPageToFit.
Adapting from Captnwalker1's answer, I came up with this:
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
if(toInterfaceOrientation ==UIInterfaceOrientationPortrait||toInterfaceOrientation==UIInterfaceOrientationMaskPortraitUpsideDown)
{
currentScrollView = [[webView subviews] objectAtIndex:0];
[currentScrollView zoomToRect:CGRectMake(0, 0, currentScrollView.contentSize.width, currentScrollView.contentSize.height) animated:NO];
}
else
{
currentScrollView = [[webView subviews] objectAtIndex:0];
[currentScrollView zoomToRect:CGRectMake(0, 0, currentScrollView.contentSize.width, currentScrollView.contentSize.height) animated:NO];
}
}
So load your webview image, and the image will reset it's size when rotated.

UIScrollView + UIWebView = NO scrollsToTop

It looks like a problem which could have simple solution, but I haven't found anything what could lead the way to it. I'm using UIWebView inside of UIScrollView and tapping on statusBar (to scroll content to top) is not working.
I've made simple test application to see if it's really UIWebViews fault. And it really is.
// scrolls to top on status bar tap
UIScrollView *sv = [[UIScrollView alloc] init];
sv.frame = CGRectMake(0, 0, 320, 480);
sv.contentSize = CGSizeMake(320, 1200);
[self.view addSubview:sv];
// doesn't scroll
UIScrollView *sv = [[UIScrollView alloc] init];
sv.frame = CGRectMake(0, 0, 320, 480);
sv.contentSize = CGSizeMake(320, 1200);
UIWebView *wv = [[UIWebView alloc] init];
wv.frame = CGRectMake(0, 0, 320, 100);
[sv addSubview:wv];
[self.view addSubview:sv];
So, I think maybe there's something I could disable to make UIWebView not to mess with scrollToTop? Or some kind of workaround also would be nice.
Any ideas?
I ran into this last night until I finally found the answer buried in a comment to a comment. The idea of that original post is that when you add the UIWebView to your UIScrollingView, you use the following:
- (void) ensureScrollsToTop: (UIView*) ensureView {
((UIScrollView *)[[webView subviews] objectAtIndex:0]).scrollsToTop = NO;
}
This seemed fishy to me since the first sub-view of a UIWebView claims to be a UIScroller which is not a subclass of UIScrollView. However, since UIScroller supports the scrollsToTop property, the cast just gives us a way past the compiler warning:
Class List:
Class = UIScroller
Class = UIView
Class = UIResponder
Class = NSObject
Supported Methods:
...
Method _scrollToTop
Method setScrollsToTop:
Method scrollsToTop
...
Supported Properties:
Property scrollsToTop
EDIT:
Just another quick note about where this actually needs to occur: in the webViewDidFinishLoad callback. Calling it on UIWebView construction isn't good enough because at that time the UIWebView hasn't created it's child views yet, which are the ones causing the problem:
- (void)webViewDidFinishLoad:(UIWebView *) wv {
[self ensureScrollsToTop: wv];
}
EDIT #2:
now, in iOS 5, as noted in iPhone OS: Tap status bar to scroll to top doesn't work after remove/add back use UIWebView's new #property scrollView, making ensureScrollsToTop implementation unnecessary for projects that aren't using deployment targets lower than iOS 5.0 .
In iPhone OS, if there is more than one UIScrollView (or its subclass, for example UITableView, UIWebView) in the current viewController, the system doesn't know which UIScrollView should be scrolled to the top.
Quick fix: for all the UIScrollViews that you don't want to support scrollsToTop, just set the scrollsToTop as NO, then every thing works perfect.
self.scrollView1.scrollsToTop = NO;
self.scrollView2.scrollsToTop = NO;
self.scrollView1.scrollsToTop = YES; // by default scrollsToTop is set as YES, this line is not necessary
Webviews by default will have YES for scrollsToTop-value. I've written a simple class for this specific issue. In my app we're having multiple webviews and scrollviews. This makes it all much easier.
https://gist.github.com/hfossli/6776203
It basically sets scrollsToTop to NO on all other scrollViews than the one you are specifying.
I want to add my case, I add an UIWebView on an UIScrollView, as h4xxr said:
If there is more than one scrolling view a scrollViewDidScrollToTop message is ignored
So, I get a simply way to make it work on webView: just set the scrollView·s scrollsToTop property false.
And when tap the status bar, it won`t got intercepted by the scrollView, and the webView scrolls to the top!
UIScrollView *scrollView = [[UIScrollView alloc] init];
scrollView.frame = self.view.bounds;
scrollView.scrollsToTop = false; //igore scrollView`s scrollsToTop
[self.view addSubview:scrollView];
UIWebView *webView = [[UIWebView alloc] init];
webView.frame = scrollView.bounds;
[scrollView addSubview:webView];