UIScrollView doesn't update properly, shows empty view randomly - objective-c

I am trying to open a new view on select of a table cell in a previous view. The new view that I am trying to open, consists of different sub-views or modules. Hence, I populate each sub-view one by one inside in [self populate] method which is in triggered inside the viewDidLoad method.
-(void)viewDidLoad{
[super viewDidLoad];
[self populate];
}
-(void) populate{
[self.edgeGallery loadImagesWithURLs: _items];
// Modular view: main info
[self.vwListingMainView setListing: _listing];
[self.vwListingMainView refresh];
// Modular view: listing agents
_vwListingAgentsView.agentsArray = _listing.agents;
// Modular view: listing info
_vwListingInfoView.listing = _listing;
[_vwListingInfoView refresh];
// Modular view: Listing activities
_vwListingActivityView.listing = _listing;
[_vwListingActivityView requestCounts];
}
Every time a new subview is populated, the method viewWillLayoutSubViews is called. This is the method where I compute the subview's height and other constraints and append it to the superview.
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
[self computeAndFixHeight];
}
- (void) computeAndFixHeight {
// Adjusting each module's height
_cstMainInfoHeight.constant = [_vwListingMainView getViewHeight];
_cstListingActionsHeight.constant = [_vwListingActionsView getViewHeight];
_cstListingAgentsHeight.constant = [_vwListingAgentsView getViewHeight];
_cstListingInfoViewHeight.constant = [_vwListingInfoView getViewHeight];
// Adjusting scroll view height
NSInteger computedScrollHeight = _vwListingUpcomingEventView.frame.origin.y + [_vwListingUpcomingEventView getViewHeight];
[self.scrollView setContentSize:CGSizeMake(self.view.frame.size.width, computedScrollHeight)];
_cstContainerBottom.constant = -computedScrollHeight - kDefaultNegativeScrollH;
[self.view layoutIfNeeded];
[self.view updateConstraints];
}
However, once the view is loaded completely, the problem that I am facing is that sometimes, I get the complete view and sometimes, randomly, I get an empty view. I think [self.view layoutIfNeeded] is the problem, but I have also tried using [self.view setNeedsLayout] and [self.view setNeedsUpdateConstraints], but still the problem remains. Any help would be appreciated.
Please excuse me if I am doing anything stupid. I am new to iOS development.

I created this project just for your question to show how to update a scrollView just using AutoLayout (no need to override viewWillLayoutSubviews, update the scrollView's contentSize, call layoutIfNeeded or updateConstraints)
Hope it helps you =)
https://github.com/ghashi/ScrollViewQuestion/tree/master
This is the result:

In our project we had encountered similar issue where we had to add a lot of views to a content view of a scrollview using constraints added programatically. Writing constraints for each view not only made the view controller bloated, it was also static. To add another view we had to write the constraints again.
We end up creating subclass of UIView that now managed this for us. We named this NNVerticalStackView.h,.m.

Related

Preventing user to access a view in a NSView hierarchy

Maybe this is my strange understanding of the NSView hierarchy, but the question is:
I have a window with a SplitViewController which has the classic two child views.
When the user clic a button on the toolbar I add a 'work in progress' view as follows:
NSView* workingView;
// creating the view
...
[self.view addSubView:workingView];
where self is the SplitViewController object. My understanding (also from iOS programming) is that the split view controller has three views: left and right views and the workingView onto them(?)
The problem is that, even if workingView is covering the entire window, the two views are still accessible. In iOS developing we can set the userInteraction to NO so only the desired view is active. What about OSX?
Can I disable interaction with the split view controller views and let only the workingView be active?
Thanks
EDIT:
I followed #Wain hint and I created a new ViewController that contains my work in progress view.
I presented it using the presentViewController:animator technique. In this way I can hav more control about the positioning of the view.
In the custom animator I simply colored the view to see what is happening. Really the way the animator adds the new view controller seems nearly the same as adding a classic view onto the split view (like did before). In fact the result is the same: even if my working view covers two buttons belonging to the left side of the split view, they are clickable!
-(void)animatePresentationOfViewController:(NSViewController *)viewController fromViewController:(NSViewController *)fromViewController {
NSViewController* bottomVC = fromViewController;
NSViewController* topVC = viewController;
topVC.view.wantsLayer = YES;
topVC.view.layerContentsRedrawPolicy = NSViewLayerContentsRedrawOnSetNeedsDisplay;
topVC.view.alphaValue = 0.0f;
[bottomVC.view addSubview:topVC.view];
topVC.view.layer.backgroundColor = [[NSColor blueColor] CGColor];
topVC.view.frame = CGRectMake(10, 10, 100, 100);
[NSAnimationContext runAnimationGroup:^(NSAnimationContext* context){
context.duration = 1.0f;
topVC.view.animator.alphaValue = 1.0f;
} completionHandler:nil];
}
I know something is missing or wrong... May you help me in understanding what is going on here?
You should create a new view controller to manage your new view and then present it as a form sheet. The display style is slightly different on each platform but this is the correct approach.
An alternative is the screenshot the split view and pass the image to the new controller which is presented full size. It then applies an overlay and adds its own content view in front of the background image.

ScrollView Objective C

I am trying to add a scrollview on my view controller.
First I changed the Simulated size of View Controller to Freeform.
Add new scrollview and change the height to 1000
Added couple of tags.
select all these tags and embedded in a view.
I name this view as contentView.
then,
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
[self.scrollView layoutIfNeeded];
self.scrollView.contentSize = self.contentView.bounds.size;
}
didn't work, for sure i miss something.
Any advise?
you can check out my answer on this other post and get an idea how to use UIScrollView.

Change UIView of storyboard dynamically and keep the rest of the subviews in place

I have a storyboard and I am trying to change the UIView to set a custom gradient view that I have created.
I have tried self.view = myNewViewWithGradient; and the gradient is displayed, but no other element can be seen since I am replacing the current view.
How can I set a new view dynamically and keep the elements that have been added in the storyboard?
I have tried re-adding the subviews (that have a referencing outlet) to this new view, but nothing is displayed.
[self.view addSubview:self.txtPassword];
Thanks for your help.
UPDATE: here is a screenshot of the outlets set in the storyboard:
You can add all your subviews to your new view, something like:
[myNewViewWithGradient setFrame:self.view.frame];
for (UIView* v in [self.view subviews]) {
[myNewViewWithGradient addSubview:v];
}
self.view = myNewViewWithGradient;
but I can not see what are you trying to achieve, did you just want a new background? You can do somehting like:
[self.view addSubview:myNewViewWithGradient];
[self.view sendSubviewToBack:myNewViewWithGradient];
Your sendSubviewToBack:myNewViewWithGradient is an UIView? If it did not work please provide more information so we can better help you :)

UIButton inside UIView doesn't respond to touch events

I've put a UIButton inside a custom UIView and the button is not receiving any touch events (it doesn't get into the highlighted state, so my problem is not about being unable to wire up a touch inside up handler). I've tried both putting it into the XIB in Interface Builder, and also tried programatically adding the UIButton into the UIView seperately, both ended with no luck. All my views are inside a UIScrollView, so I first though UIScrollView may be blocking them, so I've also added a button programatically exactly the same way I add my custom view into UIScrollView, and the button worked, elimination the possibility of UIScrollView could be the cause. My View's hiearchy is like this:
The button is over the image view, and the front layer isn't occupying my button completely, so there's no reason for me not be physically interacting with the button. At my custom view's code side, I'm creating my view as such:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
UIView *sub = [[[NSBundle mainBundle] loadNibNamed:#"ProfileView" owner:self options:nil] objectAtIndex:0];
[self addSubview:sub];
[sub setUserInteractionEnabled:YES];
[self setUserInteractionEnabled:YES];
CALayer *layer = sub.layer;
layer.masksToBounds = YES;
layer.borderWidth = 5.0;
layer.borderColor = [UIColor whiteColor].CGColor;
layer.cornerRadius = 30.0;
/*layer.shadowOffset = CGSizeZero;
layer.shadowRadius = 20.0;
layer.shadowColor = [[UIColor blackColor] CGColor];
layer.shadowOpacity = 0.8;
*/
}
return self;
}
I've tried all combinations of setUserInteractionsEnabled, and had no luck. (Yes, also set them to checked in Interface Builder too). I've also read in another question with a similar problem that I should try overriding 'canBecomeFirstResponder' to return 'YES' and I've also done that too. But the problem persists, I can't click the button. I've not given any special properties, settings to the button, it's just a regular one. My other objects in the view (labels below, image view behind the button etc.) are working properly without problems. What could be possibly wrong here?
Thanks,
Can.
UPDATE: Here is a quick reproduction of the problem: https://dl.dropbox.com/u/79632924/Test.zip
Try to run and click the button.
Looking at the test project, I believe your problem in the way you create TestView, you do not specify the frame for it, so basically the parent view is 0 size, and the subviews you see from XIB extending out of the parent view and thus do not get anything in responder chain.
You should either specify the frame when creating TestView, or adjust the frame after loading XIB file.
I have had this problem as well. The cause for me was that the UIButton superview frame was of height 0, so I believe that even though a touch was happening, it was not being passed down to the button.
After making sure that the button's superview took a larger rectangle as a frame the button actions worked.
The root cause for this problem on my side was a faulty auto layout implementation (I forgot to set the height constraint for the button's superview).
I've found the solution. I was initializing my custom view as:
MyView *view = [[MyView alloc] init];
I've initialized it instead with a frame of my view's size, and it started responding to events:
CGRect rect = CGRectMake(0,0,width,height);
MyView *view = [[MyView alloc] initWithFrame:rect];
Storyboard Solution
Just for anyone wanting a solution to this when using storyboards and constraints.
Add a constraint between the superview (containing the button) and the UIButton with an equal heights constraint.
In my case, I had selected embed UIButton in a UIView with no inset on the storyboard. Adding the additional height constraint between the UIButton and the superview allowed the UIButton to respond to touches.
You can confirm the issue by starting the View Debugger and visually confirm that the superview of the UIButton is not selectable.
(Xcode 11, *- Should also work in earlier versions)

zooming in scrollview ios6

I am trying to implement a simple ImageView in a scrollview to display an image. I want to particularly implement the pinch to zoom feature. I implemented the following code (which is taken from one of the Objective C sample codes on the apple websites). I tested the zooming thoroughly on ios 5 and there seems to be no problem. However when I ported my code to ios 6 and I test my zoom feature, after a while I get the following error message and my app crashes with skewed zoom results.
Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
NSAutoresizingMaskLayoutConstraint:0x8808360 h=--- v=--- V:[UIWindow:0x744db00(480)],
NSLayoutConstraint:0x71286d0 UIView:0x71222c0.bottom == UIWindow:0x744db00.bottom,
NSLayoutConstraint:0x7128650 V:|-(20)-[UIView:0x71222c0] (Names: '|':UIWindow:0x744db00 ),
NSLayoutConstraint:0x7120c50 UIImageView:0x7451630.bottom == UIScrollView:0x71206f0.bottom,
NSLayoutConstraint:0x7120c90 V:|-(0)-[UIImageView:0x7451630] (Names: '|':UIScrollView:0x71206f0 ),
NSLayoutConstraint:0x7120bd0 UIImageView:0x7451630.centerY == UIScrollView:0x71206f0.centerY,
NSLayoutConstraint:0x7122a50 V:|-(10)-[UIScrollView:0x71206f0] (Names: '|':UIView:0x71222c0 ),
NSLayoutConstraint:0x7122940 V:[UIScrollView:0x71206f0]-(38)-| (Names: '|':UIView:0x71222c0 )
Will attempt to recover by breaking constraint
Break on objc_exception_throw to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in may also be helpful.
I tried doing a google search for this problem but I am not getting good results. The code I am using is as follows. Help is greatly Appreciated
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// set the tag for the image view
[self.imageView setTag:ZOOM_VIEW_TAG];
// calculate minimum scale to perfectly fit image width, and begin at that scale
NSLog(#"[imageScrollView frame].size.width : %f",[self.scrollVIew frame].size.width);
NSLog(#"[imageView frame].size.width : %f",[self.imageView frame].size.width);
NSLog(#"[imageScrollView frame].size.height : %f",[self.scrollVIew frame].size.height);
NSLog(#"[imageView frame].size.height : %f",[self.imageView frame].size.height);
float minimumScale = [self.scrollVIew frame].size.width / [self.imageView frame].size.width;
minimumScale = 300.0/1200.0;
NSLog(#"minimumScale : %f",minimumScale);
[self.scrollVIew setMinimumZoomScale:minimumScale];
[self.scrollVIew setZoomScale:minimumScale];
NSLog(#"imageScrollView.zoomScale : %f",self.scrollVIew.zoomScale);
NSLog(#"imageScrollView.minimumZoomScale = minimumScale : %f",self.scrollVIew.minimumZoomScale = minimumScale);
self.scrollVIew.contentSize = CGSizeMake(1200.0, 800.0);
self.scrollVIew.delegate = self;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return [self.scrollVIew viewWithTag:ZOOM_VIEW_TAG];
}
Vivek
You need to create your UIImageView Programatically, and add in a subview of your UIScrollView. But you must make this inside of the viewDidAppear.
Just your UIScrollView can be made in StoryBoard!
And you will set the scrollView.contentSize inside of "viewDidAppear:(BOOL)animated" and not inside of the viewDidLoad.
Disable auto layout in your XIB file. It will be under the left most tab in the properties section on the right. You are probably using it without knowing it. If you are using it intentionally, then try to sort out your constraints so they don't conflict with each other.