I'm fairly new to programming, and I have looked for an answer for a very long time. There are some posts about it, but nothing has solved my problem. I have a UIScrollView view that I get from the nib, everything is ok with this, the content length is good and scrolling works, but it just scrolls on the left side, if I try to scroll on the right side it doesn't scroll..
Here is the code,
- (void)viewDidLoad {
[super viewDidLoad];
NSString *descriptionString = _currentBook.description;
CGSize stringSize = [descriptionString sizeWithFont:[UIFont boldSystemFontOfSize:16] constrainedToSize:CGSizeMake(387, 9999) lineBreakMode:UILineBreakModeWordWrap];
_authorLabel.text = _currentBook.author;
_titleLabel.text = _currentBook.title;
_descriptionLabel.text = [NSString stringWithFormat:#"Description: %#",_currentBook.description];
[(UIScrollView *)self.view setContentSize:CGSizeMake(387, stringSize.height +50)];
}
Thanks in advance!
Its hard to understand the problem since we cant see your nib file, but its better practice to put the scrollView on top the view of the view controller, and connect it to an IBOutlet in your view controller.
In order to find the problem I would get rid of the textfields for testing purposes (I think the constrained 9999 might be a problem but I am not sure) and then print and post the frame of the scrollView and the Content size in runtime.I am betting that you will see some issue with the frame of the uiscrollview.
Thanks,
Ok, after copy-pasting and running some tests, I found out the problem.
The problem is in the wording of the question, your problem is not that the "scroll doesn't work on the right side" (As in: you move your finger up and down on the right side of the screen without triggering a scroll), the problem is that the contents, the label itself is going out of bounds, outside of the visible area of the scrollView, and the right-handed side is not visible.
First of all, you should note that the iphone resolution is 320x480 (640x960 for Retina), so you actually have to work with a smaller width (using 387 width will make it go out of bounds).
Second, take in account the x position of the label itself is also affecting the amount of visible text. With this in mind, a more generic code would be:
- (void)viewDidLoad
{
[super viewDidLoad];
// This number represents the total width of the label that will fit centered in
// the scrollView area.
CGFloat visibleWidth = self.view.frame.width - descriptionLabel.frame.origin.x*2;
// Use the number above to get a more accurate size for the string.
NSString *descriptionString = _currentBook.description;
CGSize stringSize = [descriptionString sizeWithFont:[UIFont boldSystemFontOfSize:16] constrainedToSize:CGSizeMake(visibleWidth, 9999) lineBreakMode:UILineBreakModeWordWrap];
// Fill data (why so many underscores?)
_authorLabel.text = _currentBook.author;
_titleLabel.text = _currentBook.title;
_descriptionLabel.text = [NSString stringWithFormat:#"Description: %#", _currentBook.description];
// Also, why didn't you resize the description label? I'm assuming that you forgot this.
// (Make sure that the descriptionLabel number of lines is 0)
CGRect frame = descriptionLabel.frame;
descriptionLabel.frame.size = stringSize;
// Now set the content size, since you're using the scrollView as the main view of the viewController,
// I'll asume that it's using the whole screen, so I'm gonna use the whole width
// of the screen (that's what UIScreen is for).
[(UIScrollView *)self.view setContentSize:CGSizeMake([UIScreen mainScreen].bounds.size.width, stringSize.height +50)];
}
Finally i've found my problem, I've added a uiview programmatically as a subview to some view and then to this View i've added my scroll view as a subview.. And then it would only scroll in the area of my UIView. It was nonsense to do it like this, still a lack of knowledge..
Thank you all for trying to help!
Related
I am currently testing in xcode a UICollectionView with just one horizontal row like a kinda cover flow. Basically I have my own Custom Cell class and xib file for the cell and then on each cell I am adding another UIView with a xib. In case you are wondering why, it is so I can add different UIViews to the cell. Right now I am only adding one.
Edit I have followed the WWDC 2012 video on creating a linelayout of a UICollectionViewCell with one difference. Instead of the cell in the middle getting bigger all the other cells get smaller.
Everything below is new to my question.
-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
NSArray *array = [super layoutAttributesForElementsInRect:rect];
CGRect visibleRect;
visibleRect.origin = self.collectionView.contentOffset;
visibleRect.size = self.collectionView.bounds.size;
for (UICollectionViewLayoutAttributes *attributes in array){
if (CGRectIntersectsRect(attributes.frame, rect)) {
CGFloat distance = CGRectGetMidX(visibleRect) - attributes.center.x;
CGFloat normalizedDistance = distance / ACTIVE_DISTANCE;
if (ABS(distance) < ACTIVE_DISTANCE) {
//THIS WOULD MAKE THE MIDDLE BIGGER
//CGFloat zoom = 1 + ZOOM_FACTOR *(1- ABS(normalizedDistance));
//attributes.transform3D = CATransform3DMakeScale(zoom, zoom, 1.0);
//attributes.zIndex = round(zoom);
} else {
//THIS MAKES ALL THE OTHERS NOT IN THE RECT SMALLER
CGFloat zoom = 1 + ZOOM_FACTOR *(1- ABS(normalizedDistance));
attributes.transform3D = CATransform3DMakeScale(zoom, zoom, 1.0);
attributes.zIndex = round(zoom);
}
}
}
return array;
}
The problem can be seen in the attached image.
Pink = Collection View Size
Brown = Cell size
Green = Cells Content size and an attached xib to the content size.
The problem I THINK I have is with the layout. When the sell is dequeued it is made smaller by the above code. Then when it is reused the CELL gets bigger again but the content view does not.
I have tired to manually set the frame of the content view but that does nothing.
UPDATE 1: This also only happens when I add a xib to the Cells content view. If there is no subview to the content view then there is no problem
UPDate 2: It appears that the subview of the cell, my xib is not resizing. I have tried to manually change its frame size but the only place this helps is in the cells drawrect method which feels like a hack to me.
reused cell not able to redraw itself so give call to
-(void)setFrame:(CGRect)frame {
[super setFrame:frame];
[self setNeedsDisplay]; // force drawRect:
}
from cellForItemAtIndexPath of the UICollectionView.
also have a look at this link
and this question
My answer is very specific and I am not sure it will help anyone.
The problem was that I had a constraint on the bottom of the grey view. After I changed this constraint to a less than or equal too then for some reason it worked.
Now I know this does not explain why it was not happening to every cell but it fixed my problem.
As such Harsh's answer might also be worth looking at if you have landed here after doing a search.
Edit: there also appears to be some bugs in the 6.0 UiCollectionView controller which seem to be fixed in 6.1
I have seen this question being addressed several times here at SO, e.g Problem with UIScrollView Content Offset, but I´m still not able to solve it.
My iphone app is basically a tab bar controller with navigation bar. I have a tableview controller made programmatically and a DetailViewController that slides in when I tap a cell in my tableview controller.
The DetailViewController is made in IB and has the following hierarchy:
top view => UIScrollView => UIView => UIImage and a UITextField.
My goal is to be able to scroll the image and text field and this works well. The problem is that my UIScrollView always gets positioned at the bottom instead at the top.
After recommendations her at SO, I have made my UIScrollView same size as the top view and instead made the UIView with the max height (1500) of my variable contents.
In ViewDidLoad I set the contentSize for the UIScrollView (as this is not accessible from IB):
- (void)viewDidLoad {
[scrollView setContentSize:CGSizeMake(320, 1500)];
[scrollView setContentOffset:CGPointMake(0, 0) animated:YES];
NSLog(#"viewDidLoad: contentOffset y: %f",[scrollView contentOffset].y);
}
Specifically setting the contentOffset, I would expect my scrollView to always end up at the top. Instead it always go to the bottom. It looks to me that there is some autoscrolling beyond my control taking place after this method.
My read back of the contentOffset looks OK. It looks to me that there may be some timing related issues as the scrolling result may vary whether animation is YES or NO.
A ugly workaround I have found is by using this delegate method:
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrView {
NSLog(#"Prog. scrolling ended");
[scrollView setContentOffset:CGPointMake(0, 0) animated:YES];
}
This brings my scrollview to top, but makes it bounce down and up like a yo-yo
Another clue might be that although my instance variables for the IBOutlet are set before I push the view controller, the first time comes up with empty image and textfield:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (!detailViewController) {
detailViewController = [[DayDetailViewController alloc] init];
}
// Pass dictionary for the selected event to next controller
NSDictionary *dict = [eventsDay objectAtIndex:[indexPath row]];
// This method sets values for the image and textfield outlets
[detailViewController setEventDictionary:dict];
// Push it onto the top of the navigation controller´s stack.
[[self navigationController] pushViewController:detailViewController animated:NO];
}
If I set animation to YES, and switch the order of the IBOutlet setting and pushViewController, I can avoid the emptiness upon initialization. Why?
Any help with these matters are highly appreciated, as this is really driving me nuts!
Inspired of Ponchotg´s description of a programmatically approach, I decided to skip interface builder. The result was in some way disappointing: The same problem, with the scrollview ending up in unpredictable positions (mostly at bottom), persisted.
However, I noticed that the scroll offset error was much smaller. I think this is related to the now dynamic (and generally smaller) value of ContentOffset. After some blind experimenting I ended up setting
[textView setScrollEnabled:YES];
This was previously set to NO, as the UITextView is placed inside the scrollview, which should take care of the scrolling. (In my initial question, I have erroneously said it was a UITextField, that was wrong)
With this change my problem disappeared, I was simply not able to get into the situation with scrollview appearing at bottom anymore in the simulator! (At my 3G device I have seen a slight offset appear very seldom, but this is easily fixed with scrollViewDidEndScrollingAnimation delegate described previously ).
I consider this as solved now, but would appreciate if anyone understand why this little detail messes up things?
OK! i have a question before i can give a correct answer.
Why are you using a UIView inside the Scrollview?
You can always only put your UIImageView and UITextField inside the UIScrollView without the UIView
and set the contentSize dynamically depending on the size of the text.
to give you an example how i do it:
int contSize = 0;
imageView.frame = CGRectMake(10, 0, 300, 190);
imageView.image = [UIImage imageNamed:#"yourimage"];
contSize = 190 //or add extra space if you dont want your image and your text to be so close
[textField setScrollEnabled:NO];
textField.font = [UIFont systemFontOfSize:15];
textField.textColor = [UIColor grayColor];
textField.text = #"YOUR TEXT";
[textField setEditable:NO];
textField.frame = CGRectMake(5, contSize, 310, 34);
CGRect frameText = textField.frame;
frameText.size.height = textField.contentSize.height;
textField.frame = frameText;
contSize += (textField.contentSize.height);
[scrollView setScrollEnabled:YES];
[scrolView setContentSize:CGSizeMake(320, contSize)];
In the above example I first create an int to keep track of the ysize of my view then Give settings and the image to my UIImageView and add that number to my int then i give settings and text to my UITextField and then i calculate the size of my text depending on how long is my text and the size of my font, then add that to my int and finally assign the contentSize of my ScrollView to match my int.
That way the size of your scrollview will always match your view, and the scrollView will always be at top.
But if you don't want to do all this, you can allways just:
[scrollView setContentOffset:CGPointMake(0, 0) animated:NO];
at the end of the code where you set your image and your text, and the NOto avoid the bouncing.
Hope this helps.
EDIT - I've worked out what I was originally doing wrong. I was changing the size of the UIScrollView, instead of the pattern subview. I have fixed that, but amended my question with the new problem this has thrown up.
I am making a notes section in my app with a lined-paper effect. The lines are on a separate UIScrollView which responds to scrollViewDidScroll: so the lines and text always move together. My lines are set up like this in viewWillAppear:
CGRect noteLinesRect = CGRectMake(self.view.bounds.origin.x,
self.view.bounds.origin.y,
self.view.bounds.size.width,
noteTextView.contentSize.height+self.view.bounds.size.height);
UIScrollView *anoteXLinesView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
self.noteXLinesView = anoteXLinesView;
[anoteXLinesView release];
LinePatternView *linesPattern = [[LinePatternView alloc] initWithFrame:noteLinesRect];
self.linesPatternView = linesPattern; [linesPattern release];
[self.noteXLinesView addSubview:self.linesPatternView];
[linesPattern release];
CGPoint newOffset = CGPointMake(self.noteTextView.contentOffset.x, noteTextView.contentOffset.y - NOTE_LINES_OFFSET);
self.noteXLinesView.contentOffset = newOffset;
[self.view insertSubview:self.noteXLinesView atIndex:0];
This works fine when the user first looks at a stored note - all the text is nicely underlined. But when they write more text, eventually they get to the bottom of the lines I created in viewWillAppear and are writing on 'blank paper'. So I need my lined-paper pattern to dynamically get bigger and smaller so it is always a bit bigger than the contentSize of my textView. I am trying to do that like this:
-(void)textViewDidChange:(UITextView *)textView
{
self.linesPatternView.frame = CGRectMake( self.linesPatternView.frame.origin.x, //-self.noteTextView.contentOffset.y+NOTE_LINES_OFFSET,
self.linesPatternView.frame.origin.y,
self.linesPatternView.frame.size.width,
noteTextView.contentSize.height+self.view.bounds.size.height );
}
The problem is, although the lined-paper pattern does increase in size, it doesn't add new lines at the bottom. Instead, the pattern stretches out and gets bigger as the view gets bigger. What am I doing wrong?
One of the solutions is to make 3 views, each containing the lines of the size of your scrollview frame on screen. You position the three one underneath the other in the scrollview and monitor the scrollview through its delegate.
When scrolling down you check:
As soon as the topmost one goes offscreen for more than Y pixels you remove it from the scrollview and insert it underneath the bottom one.
When scrolling up you check:
As soon as the bottommost one goes offscreen for more than Y pixels you remove it from the scrollview and insert it above the top one.
Is there a reason you’re not simply using a tiled pattern as your background view’s backgroundColor? UIColor’s +colorWithPatternImage: will let you set a background that’ll tile indefinitely and won’t stretch as your view resizes. If part of the background has to be different—like the top of your paper, for instance—you can just place an image view containing that at the top of your background view.
Fixed! In addition to the changes outlined in my edit to the question above, I just needed to call [self.linesPatternView setNeedsDisplay]; after the resize.
I met a really strange problem while using UITextView, I try to use "GrowStyle" of UITextView, wire up the frame with contentSize, turn off the .scrollEnabled, Build & Run: but when click the bottom of the screen, the keyboard showing up, the UITextView moves up a short distance, and its Top lines disappear, here is the code:
- (void)viewDidLoad {
[super viewDidLoad];
//Turn off the scrollEnabled.
UITextView *growStyleText.scrollEnabled = NO;
//Wire the growStyleText's contentSize to its frame, let it grow.
CGRect selfHack = growStyleText.frame;
selfHack.size = growStyleText.contentSize;
growStyleText.frame = selfHack;
//Make a UIScrollView
UIScrollView *scroll.contentSize = selfHack.size;
scroll.clipsToBounds = NO;
[self.view insertSubview:scroll atIndex:1];
//Add the TextView on the ScrollView, make it scrollable.
[scroll addSubview:growStyleText];
}
After click the last line, Keyboard shows up, then the Top line Disappears! I thought about for all day long, anybody seen this? how can I make Top line moves up instead of disappear? hard question for me, guess there may be simple answers, thank you, very much.
I don't know what you are trying to do, but, since UITextView is a subclass of UIScrollView, why do you need to create it as a subview of a UIScrollView?
Then, in my experience, you can't get the contentSize of a UIScrollView before you add it to a view.
I found this answer very useful
How do I size a UITextView to its content?
Hope it helps.
I have a UITextView and I would like to only allow it to be scrollable horizontally only.
Basically when the UITextView word-wraps I want the user to have to scroll horizontally to be able to view the rest of the contents.
You can set the content size of the text view to the height of the view. Just make sure the width of the content extends past the width of the textView's frame or else it won't scroll.
// UITextView* myTextView: gets declared somewhere...
// The text view (subclass of a UIScrollView) won't go past its content size
[myTextView setContentSize:CGSizeMake(width, myTextView.frame.size.height)];
// Just in case, if you don't want your user bouncing the view up/down
[myTextView setAlwaysBounceVertical:NO];
I hope that's what you were looking for.
The solution is to turn off all the scroll options on the UITextView itself, then embed it in another UIScrollView. You can get actual code by searching on this term "DualScrollTextView" in google. You cannot force changes to contentSize to accomplish this - many have tried.
This worked for me:
self.dishNameLabel.text = #"Here is some very longgggg text to test with";
float width = ceil([self.dishNameLabel.text sizeWithAttributes:#{NSFontAttributeName: [UIFont fontWithName:#"WorkSans-SemiBold" size:15.0]}].width);
self.dishNameLabel.frame = CGRectMake(self.dishNameLabel.frame.origin.x, self.dishNameLabel.frame.origin.y, width, self.dishNameLabel.frame.size.height);
self.dishNameScrollView.contentSize = CGSizeMake( width, self.dishNameScrollView.frame.size.height);
Of course, you will have to replace your text and font with your respective specs