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.
Related
My UIScrollView is a ~4500px horizontal view that the user needs to scroll horizontally through to view the content.
I have set it up as follows:
- (void)viewDidLoad
{
[super viewDidLoad];
sview.frame = CGRectMake(0, 0, 568, 320);
sview.contentSize = CGSizeMake(4500, 320);
[sview setScrollEnabled:YES];
}
Yet the scroll view does nothing. Is there something obvious I missed? i've tried literally every tutorial on the web.
I got similar issue. I did following modifications and the scrollView started scrolling for me:
Select to check the 'Bounce Horizontally' property for UIScrollView
in xib.
Move the code following code to viewDidAppear instead of
viewDidLoad:
-(void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
sview.frame = CGRectMake(0, 0, 568, 320);
sview.contentSize = CGSizeMake(4500, 320);
[sview setScrollEnabled:YES];
}
I think this should help you.
I've explained it here, but there are so many answers to this problem that suggests turning off Auto Layout. That fixes the problem but that's not really the correct solution. Here's my answer:
Turning Auto Layout works, but that's not the solution. If you really need Auto Layout, then use it, if you don't need it, turn it off. But that is not the correct fix for this solution.
UIScrollView works differently with other views in Auto Layout. Here is Apple's release note on Auto Layout, I've copied the interesting bit:
Here are some notes regarding Auto Layout support for UIScrollView:
In general, Auto Layout considers the top, left, bottom, and right edges of a view to be the visible edges. That is, if you pin a view to
the left edge of its superview, you’re really pinning it to the
minimum x-value of the superview’s bounds. Changing the bounds origin
of the superview does not change the position of the view.
The UIScrollView class scrolls its content by changing the origin of its bounds. To make this work with Auto Layout, the top, left, bottom,
and right edges within a scroll view now mean the edges of its content
view.
The constraints on the subviews of the scroll view must result in a size to fill, which is then interpreted as the content size of the
scroll view. (This should not be confused with the
intrinsicContentSize method used for Auto Layout.) To size the scroll
view’s frame with Auto Layout, constraints must either be explicit
regarding the width and height of the scroll view, or the edges of the
scroll view must be tied to views outside of its subtree.
Note that you can make a subview of the scroll view appear to float (not scroll) over the other scrolling content by creating constraints
between the view and a view outside the scroll view’s subtree, such as
the scroll view’s superview.
Apple then goes on to show example of how to correctly use UIScrollView with Auto Layout.
As a general rule, one of the easiest fix is to create a constraint between the element to the bottom of the UIScrollView. So in the element that you want to be at the bottom of the UIScrollView, create this bottom space constraint:
Once again, if you do not want to use Auto Layout, then turn it off. You can then set the contentSize the usual way. But what you should understand is that this is an intended behaviour of Auto Layout.
First of all you have to add some content to UIScrollSiew as subview for scrolling,without content on UIScrollView how can you scroll?. Here is what i did,just add UIImageView to UIScrollView as subview of size same as size of UIScrollView...
In viewDidLoad method try the following code..
-(void)viewDidLoad
{
UIScrollView *scroll=[[UIScrollView alloc] init];
scroll.frame=CGRectMake(0, 0, 320, 460);
UIImageView *imageView=[[UIImageView alloc] init];
imageView.frame=CGRectMake(0, 0, 320,460);
imageView.image=[UIImage imageNamed:#"chiranjeevi.jpeg"];
scroll.contentSize = CGSizeMake(4500, 460);
[scroll setScrollEnabled:YES];
[scroll addSubview:imageView];
[self.view addSubview:scroll];
}
I tested this code it works well.I hope this code will be helpful to you..
I assume you are adding UISrollingView in your Xib file. This will work for you.
sview.delegate = self;
sview.backgroundColor=[UIColor clearColor];
[sview setCanCancelContentTouches:NO];
sview.indicatorStyle = UIScrollViewIndicatorStyleWhite;
sview.clipsToBounds = YES;
sview.scrollEnabled = YES;
sview.contentSize = CGSizeMake(320,570);
CGPoint topOffset = CGPointMake(0,0);
[sview setContentOffset:topOffset animated:YES];
Also, make sure to give IBOutlet connection in your Xib file.
I also faced the same issue.I added the scroll view in xib.I also added some subviews to this scroll view. The scroll view would stop scrolling after I added the subviews. The solution for this problem was in the xib for the view in file inspector Use Autolayout was checked. I unchecked it and the scroll view scrolled after adding the subviews.
The solution was uncheking the Use Autolayout in file inspector in xib.
For example in Tweetbot's iPhone app. When you open up the app and new tweets come in, it will just be appended to the top of the UIScrollView and the current tweet you see did not get refreshed. How can I achieve the same thing effect?. Say I have a UIScrollView with a UIView added to the UIScrollView starting at origin 10,10.
I then downloaded a few items and I want to put it at 10,10.. so I basically need to shift this old item at 10,10 down right? If I do so then during that shifting user's will see it shifted, which is not the effect I want. Where as in Tweetbot's app it seems that nothing is being shifted around, it's just that you grow the area above the 10,10 and append new stuff's there.
How do I do this?
Basically I wanted to implement the insertRowAtIndexPath in a UIScrollView.
Will restate the question this way: how to add content to the top of a UIScrollView without moving the content that's already there (relative to it's current offset).
If this is the right question, the right answer is to do the add and shift down just as you suggested, but then scroll by the same height as added content, giving the illusion that the old content didn't move.
- (void)insertRowAtTop {
// not showing insert atIndexPath because I don't know how you have your subviews indexed
// inserting at the top, we can just shift everything down. you can extend this idea to
// the middle but it requires that you can translate from rows to y-offsets to views
// shift everything down
for (UIView *view in self.scrollView.subviews) {
if ([view isKindOfClass:[MyScrollViewRow self]]) {
MyScrollViewRow *row = (MyScrollViewRow *)view; // all this jazz so we don't pick up the scroll thumbs
row.frame = CGRectOffset(row.frame, 0.0, kROW_HEIGHT); // this is a lot easier if row height is constant
}
}
MyScrollViewRow *newRow = [[MyScrollViewRow alloc] initWithFrame:CGRectMake(0.0,0.0,320.0,kROW_HEIGHT)];
// init newRow
[self.scrollView addSubview:newRow];
// now for your question. scroll everything so the user perceives that the existing rows remained still
CGPoint currentOffset = self.scrollView.contentOffset
self.scrollView.contentOffset = CGPointMake(currentOffset.x, currentOffset.y + kROW_HEIGHT);
}
If you set the contentOffset without animating there wont be a visible scrolling animation. So if your new view is 200 points tall you can set the origin of the new view at (10,10) and the old view at (10,210) and set the contentOffset of the scroll view to (10,210) you should achieve the effect you intend. You'll also need to increase the contentSize of your scroll view to be big enough for all of the content it contains.
I am developing an application in which i am creating small sub views in the same view.
What i want is when i change the value of alpha of the view, the value of alpha for sub view is also getting changed which i do not want.
How to implement the code for changing the value of the view not the small sub views created.
Thanks,
You cannot do that, the alpha is inheritate, so what you have to do is to change the view structure from
YourMainView -> Your SubView
To
ContainerView ->YourMainView
-> Your SubView
So now YourMain View the one that you want to apply the animation, is not the paret view of your current subView, the both views are sibilings, also ContainerView will have a clear background, so it wont affect it will just contain both the views
As suggested already, you should not add YourSubVew as subview of YourMainView.
Make both of your views a subview of an empty and transparent common subview (ContainerView) which has the same size and position that YourMainView currently has.
ContainerView -> YourMainView
-> YourSubView
Make sure to add YourMainView first as subview of ContainerView before you add YourSubView as subview of ContainterView. Otherwise YourMainView may overlap/hide YourSubView.
Doing so you can set both views' alpha independend from each other.
(Omar's answer is quite correct, but his "graphical visualisation" is misleading and it missed the point of the sequence of the subviews.)
Edit:
What you have today is like this:
yourMainView.alpha = 1.0;
...
[yourMainView addSubView:yourSubView];
yourMainView.alpha = 0.1; //probably with animations etc.
What happens is, that yourSubView will "inherit" the alphaValue of its superview.
ANd there is even more to that. Assuming that your subView has an alpha of 0.5, that would effectively become 0.05 when when its superview's alpha is set to 0.1.
Change that code to:
containerView = [[UIView alloc] init]; //you may choose a different init method
//If you use initWithFrame then use the frame of yourMainView.
//However, make sure that ContainterView is of the same size as yourMainView and has the same position.
[containerView addSubView:yourMainView];
yourMainView.alpha = 1.0;
...
[containerView addSubView:yourSubView]; //add it to the container too!
yourMainView.alpha = 0.1; //this will now effect the MainView only.
That is basically all the trick. Views can perfectly well overlap each other without being subviews. Make them subviews only then when they really are subveiws, when they are moved togehter, appear and disappear together, etc.
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!
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.