View loaded from xib file and added to scrollView draws over it - ios

I have scrollView set for horizontal scrolling (paging enabled, ...).
If i create UiViews in code and add them to scrollView everything works ok.
Example:
//second page
CGRect frame2;
frame2.origin.x = myScrollView.frame.size.width;
frame2.origin.y = 0;
frame2.size = myScrollView.frame.size;
UIImage *tutImage2=[UIImage imageNamed:#"tutorialScreen2.png"];
UIImageView *tutorialImage2=[[UIImageView alloc] initWithImage:tutImage2];
tutorialImage2.frame=tutImageFrame;
UIView *subview2 = [[UIView alloc] initWithFrame:frame2];
subview2.backgroundColor = [UIColor clearColor];
[subview2 addSubview:tutorialImage2];
[myScrollView addSubview:subview2];
The problem is with views loaded from xib, because they draw over scrollView (eventhough their frame is set to height smaller than full screen).
Example:
//third page
CGRect frame3;
frame3.origin.x = myScrollView.frame.size.width*2;
frame3.origin.y = 0;
frame3.size = myScrollView.frame.size;
dashView = [[[NSBundle mainBundle]loadNibNamed:#"DashboardView"owner:self options:nil] lastObject];
dashView.frame=frame3;
[myScrollView addSubview:dashView];
I tried setting my view's simulated metrics size to freeform and retina 4inch and it didnt help. I also turned off autolayout (i dont use it in my xib) but it also didnt help.
Any idea?

Related

Unwanted bounce of subviews on scrollview

I have a scrollview that acts as a banner with 15 image views as subviews (scrolled horizontally). I add the subviews this way:
for (int i = 0; i < featuredImages.count; i++) {
CGRect frame;
frame.origin.x = self.scrollViewFeaturedImages.frame.size.width * i;
frame.origin.y = 0;
frame.size = self.scrollViewFeaturedImages.frame.size;
UIImageView *subview = [[UIImageView alloc] init];
subview.frame = frame;
[self.scrollViewFeaturedImages addSubview:subview];
}
And set the contentSize accordingly:
self.scrollViewFeaturedImages.contentSize = CGSizeMake(self.scrollViewFeaturedImages.frame.size.width * featuredImages.count, self.scrollViewFeaturedImages.frame.size.height);
self.scrollViewFeaturedImages.contentInset = UIEdgeInsetsZero;
However, when the view appears, the first image seems to be a little off.
When I scroll (horizontally) to the next image, the gap disappears, and when I scroll back to the first image, the frame is corrected already.
I've also disabled BOUNCE but I can drag the image vertically.
I've also tried this:
self.automaticallyAdjustsScrollViewInsets = NO;
with no success.
What's going on?
After being puzzled for 2 weeks I finally got this fixed by adding these lines in viewDidAppear.
self.scrollViewFeaturedImages.contentInset = UIEdgeInsetsZero;
self.scrollViewFeaturedImages.scrollIndicatorInsets = UIEdgeInsetsZero;
Did you try to change the UIImageView's property contentMode to UIViewContentModeScaleToFill?

Trying to create multiple views from one XIB file programmatically

I have a page enabled scroll view which I would like to fill with UIViews. I have tried creating a "XIB" file and loading from it in a for loop, but this only gives me one UIView in my scroll view.
int amount = garments.count;
[self.pageControl setNumberOfPages:amount];
for (int i = 0; i < amount; i++) {
DOVGarment *garment = garments[i];
CGRect frame;
frame.origin.x = self.scrollView.frame.size.width * i;
frame.size = self.scrollView.frame.size;
DOVGarmentDetailView *view = [DOVGarmentDetailView new];
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"detailView" owner:view options:nil];
view = [topLevelObjects objectAtIndex:0];
view.image.image = [UIImage imageNamed:garment.fileName];
view.labelID.text = garment.ID;
[self.scrollView addSubview:view];
}
self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width * amount, self.scrollView.frame.size.height);
Anyone have an idea why this doesn't work? Or if this is even possible?
You are creating multiple views but you are not changing the frame so they will all be placed directly on top of each other.
Update your code to offset each view relative to the one created before
Every view object you place in your xib file has only one instance of it. So every run cycle of your for loop you are accessing the same UIView instance.
Incase you need to fill your scrollView with view's you need to alloc and initialise again in every run cycle of the for loop thereby creating many instances of UIView.
This is how I did it which places UIViews horizontally in my scrollView -
for (int i = 0; i<numberOfViews; i++)
{
UIView*smallView = [[UIView alloc]initWithFrame:CGRectMake((i*scrollview.frame.size.width+heightOfYourView), 0, scrollview.frame.size.width, scrollview.bounds.size.height)];
[scrollview addSubview: smallView];
}
scrollview.contentSize = CGSizeMake(numberOfViews*scrollview.frame.size.width, scrollview.frame.size.height);

UIImageView and autolayout

I have a view that is set up nicely using autolayout. The view contains a series of labels stacked from top to bottom. I am allowing the intrinsic size of these labels to determine the size of the view.
The final step is to add a background from an image. I started by trying the colorWithPatternImage method on UIColor but this isn't quite what I am looking for. I do not want to tile the image, and I can not guarantee it will always be larger than the intrinsic size of the view.
Similarly, adding a uiImageView to the view itself doesn't quite work. The view will expand to accommodate the image when I want to keep the intrinsic size based on the labels.
I guess what I am looking for is the following.
1) The background should have no effect on the size of the view.
2) The image should be scaled to fill the view but in it's original aspect ration (so cropping edges if necessary).
Any ideas appreciated.
In my case, I needed it for a UIImageView inside a dynamically-sized view in a UITableViewCell, but the image refused to shrink below its instristic size and instead worked as a minimum-size constraint for the superview. The only way I could get it ignore the intristic size is by lowering the priority at which it is enforced, right after creating the cell:
[imageView setContentCompressionResistancePriority:UILayoutPriorityDefaultLow
forAxis:UILayoutConstraintAxisHorizontal];
[imageView setContentCompressionResistancePriority:UILayoutPriorityDefaultLow
forAxis:UILayoutConstraintAxisVertical];
After this, all my constraints magically started working. In the OP's case, setting UIViewContentModeScaleAspectFill is also required, as per Mundi's answer.
In Interface Builder, add a UIImageView as the first subview to the view. Make sure its size always matches the view.
Then, in Interface Builder or code, set the contentMode:
backgroundImageView.contentMode = UIViewContentModeScaleAspectFill;
Here's how I would approach this. Hopefully it helps. :)
CGRect contentFrame = CGRectMake(0, 0, self.view.frame.size.width, 0); // This will be the frame used to create the background image view.
UIEdgeInsets contentInsets = UIEdgeInsetsMake(20, 20, 20, 20); // The margins by which the labels will be inset from the edge of their parent view.
CGFloat labelHeight = 21;
CGFloat verticalGap = 8; // The vertical space between labels
CGFloat y = contentInsets.top;
int numberOfLabels = 10;
for (int i = 0; i < numberOfLabels; i++) {
CGRect frame = CGRectMake(contentInsets.left, y, self.view.frame.size.width - (contentInsets.left + contentInsets.right), labelHeight);
UILabel *label = [[[UILabel alloc] initWithFrame: frame] autorelease];
// customize the label here
[self.view addSubview: label];
contentFrame = CGRectUnion(contentFrame, label.frame);
y += labelHeight + verticalGap;
}
contentFrame.size.height += contentInsets.bottom;
UIImageView *backgroundImageView = [[[UIImageView alloc] initWithFrame: contentFrame] autorelease];
[backgroundImageView setClipsToBounds: YES];
[backgroundImageView setContentMode: UIViewContentModeScaleAspectFill];
[backgroundImageView setImage: [UIImage imageNamed: #"background_image.png"]];
[self.view insertSubview: backgroundImageView atIndex: 0];

Graphical glitch in UIScrollView when autorotating device

I have an application which has a fullscreen UIScrollView, and within it there are seven images. The images are also meant to be full screen, and the scroll view is set to enable pagination.
I have a method which either creates or moves the image views:
-(void)rebuildImageView{
// set up images
float screenW = self.view.bounds.size.width;
float screenH = self.view.bounds.size.height;
int numImgs = self.soundNames.count;
self.mainScrollView.contentSize = CGSizeMake(screenW * numImgs, screenH);
for(int i=0; i<numImgs; i++){
UIImageView* imageView = (UIImageView*)[self.mainScrollView viewWithTag:i+100];
if(imageView == nil){
imageView = [[UIImageView alloc] init];
imageView.tag = i+100;
[self.mainScrollView addSubview:imageView];
imageView.image = [UIImage imageNamed:[NSString stringWithFormat:#"image%d.jpg",i]];
imageView.contentMode = UIViewContentModeScaleAspectFill;
imageView.clipsToBounds = YES;
[imageView release];
}
imageView.frame = CGRectMake(i * screenW, 0, screenW, screenH);
}
// scroll to the current one
[self.mainScrollView scrollRectToVisible:CGRectMake(self.currentSound*screenW, 0, screenW, screenH) animated:YES];
}
I also have this on the view controller:
-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
[UIView animateWithDuration:duration animations:^{
[self rebuildImageView];
}];
}
This code works fine when I autorotate while image 0 is being shown, but when I'm on image 7, you can briefly see most of image 6 when rotating. This video shows what's happening:
http://www.youtube.com/watch?v=1O3jOcTgVP8
Is there a better method I should use to reconfigure the scroll view and images when rotating the device?
Any frame changes put in the willAnimateRotationToInterfaceOrientation:duration method should automatically animate. So you could try removing it from the block?
Personally, I've had a lot more luck with this type of thing subclassing UIScrollView and putting the equivalent layout subview frame code in an override of the layoutSubviews method (don't forget to call super or you might end up with misplaced scroll bars).

IOS: UIScrollView with an infinite paging view

I have this code for a scrollview to showe 3 images:
const CGFloat kScrollObjHeight = 150.0;
const CGFloat kScrollObjWidth = 320.0;
const NSUInteger kNumImages = 3;
- (void)layoutScrollImages
{
UIImageView *view = nil;
NSArray *subviews = [scrollView1 subviews];
// reposition all image subviews in a horizontal serial fashion
CGFloat curXLoc = 0;
for (view in subviews)
{
if ([view isKindOfClass:[UIImageView class]] && view.tag > 0)
{
CGRect frame = view.frame;
frame.origin = CGPointMake(curXLoc, 0);
view.frame = frame;
curXLoc += (kScrollObjWidth);
}
}
// set the content size so it can be scrollable
[scrollView1 setContentSize:CGSizeMake((kNumImages * kScrollObjWidth), [scrollView1 bounds].size.height)];
}
- (void)viewDidLoad
{
self.view.backgroundColor = [UIColor viewFlipsideBackgroundColor];
// 1. setup the scrollview for multiple images and add it to the view controller
//
// note: the following can be done in Interface Builder, but we show this in code for clarity
[scrollView1 setBackgroundColor:[UIColor blackColor]];
[scrollView1 setCanCancelContentTouches:NO];
scrollView1.indicatorStyle = UIScrollViewIndicatorStyleWhite;
scrollView1.clipsToBounds = YES; // default is NO, we want to restrict drawing within our scrollview
scrollView1.scrollEnabled = YES;
// pagingEnabled property default is NO, if set the scroller will stop or snap at each photo
// if you want free-flowing scroll, don't set this property.
scrollView1.pagingEnabled = YES;
scrollView2.pagingEnabled = YES;
scrollView3.pagingEnabled = YES;
// load all the images from our bundle and add them to the scroll view
NSUInteger i;
for (i = 1; i <= kNumImages; i++)
{
NSString *imageName = [NSString stringWithFormat:#"image%d.jpg", i];
UIImage *image = [UIImage imageNamed:imageName];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
// setup each frame to a default height and width, it will be properly placed when we call "updateScrollList"
CGRect rect = imageView.frame;
rect.size.height = kScrollObjHeight;
rect.size.width = kScrollObjWidth;
imageView.frame = rect;
imageView.tag = i; // tag our images for later use when we place them in serial fashion
[scrollView1 addSubview:imageView];
//[scrollView2 addSubview:imageView];
//[scrollView3 addSubview:imageView];
[imageView release];
}
[self layoutScrollImages]; // now place the photos in serial layout within the scrollview
}
But now I want to do a scrollview that when is in last image show me after the first image of scroll view and the same thing when I have the first image if I go back, it must show the last image; so I want create a paging loop.
The basic idea is to set yourself as a UIScrollViewDelegate and apply some modulo arithmetic to the scroll position in order to wrap it around.
There are two basic variations on the idea. Suppose your images are A, B, C, so you currently have them within the scrollview ordered as ABC.
In the more logically pleasing solution — especially if you had lots and lots of images — you watch the scroll position and as soon as it gets to a position where the view is being pushed rightward and C has left the screen, you reorder the images as CAB and shift the current scroll position one spot to the right so that the move is invisible to the user. To put that another way, the scroll position is restrained to an area of two screens, centred on the middle of B (so, you get all of B and half a screen either side). Whenever you wrap it from somewhere on the left to somewhere on the right you shift all your image views one place to the right. And vice versa.
In the slightly easier to implement variation, instead of creating a scroll view with images arranged ABC, arrange then as CABCA. Then apply the same wrap around logic but to a central area of four screens and don't do any view reshuffling.
Make sure you use just setContentOffset: (or the dot notation, as in scrollView.contentOffset =) as a setter. setContentOffset:animated: will negate velocity.

Resources