Normally, tutorials of UIScrollView talk about multiple pages with the size of the screen.
Beginning with the first page in the screen and the second page appearing a little in the right side:
And when scrolled, the same thing occurs with the second page: the first and the third page appears in the left/right side.
This scrollView is "implementable"? There's a way to use pages but with not entire screen width?
Yes you can do that, just change the size of your scroll view to your desired size,
Content Size as (numberOfPages * width) of your scrollview
Also enable pagination
scrollView.pagingEnabled = YES;
scrollView.contentSize = CGSizeMake(numberOfPages * scrollView.frame.size.width, 1);
For more idea, refer to this sample project, just change scrollview size in xib :)
Hope it helps :)
try setting your scroll view content size
scrollView.contentSize = CGSizeMake(W, 1);
remember that "W" has to be a number greater then your scroll view's width in order to scroll horizontal. 1 is where you set the hight of your content size, if you'd like it to scroll vertically you'd make the "1" greater then your scrollview's hight.
You need to implement a scroll view container (e.g. ScrollViewContainer) to handle -hitTest:withEvent: method:
ScrollViewContainer.h:
#interface BookAlbumScrollViewContainer : UIView {
UIScrollView * theScrollView_;
}
#property (nonatomic, retain) UIScrollView * theScrollView;
#end
ScrollViewContainer.m:
#implementation BookAlbumScrollViewContainer
#synthesize theScrollView = theScrollView_;
//...
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
UIView * child = [super hitTest:point withEvent:event];
if (child == self)
return self.theScrollView;
return child;
}
#end
HERE is a related QA on -hitTest:withEvent: method.
When you set your scroll view, set it like:
CGFloat yourScrollViewPageWidth = 280.f;
CGRect yourScrollViewFrame = CGRectMake((320.f - yourScrollViewPageWidth) / 2.f, 0.f, yourScrollViewPageWidth, 200.f);
CGRect theScrollViewContainerFrame = CGRectMake(0.f, 0.f, 320.f, 200.f);
// Your scroll view
yourScrollView_ = [[UIScrollView alloc] initWithFrame:yourScrollViewFrame];
//...
[self.view addSubview:bookScrollView_];
// Your scroll view container to handle touches, it should be over |yourScrollView_|
theScrollViewContainer_ = [ScrollViewContainer alloc];
[theScrollViewContainer_ initWithFrame:theScrollViewContainerFrame];
[theScrollViewContainer_ setBookAlbumScrollView:yourScrollView_];
[self.view theScrollViewContainer_];
Related
I've been playing around with adding different interactions to a test project of mine, and I'm having trouble adding something like Facebook's post status bar, the one that sits on the timeline scrollview and scrolls with the scrollview when you're scrolling down the view but stays stuck under the navbar when you're scrolling up it.
I've been creating a separate UIViewController (not UIView) and adding it as a subview to the main ViewController. I'm not exactly too sure where to go from there though... How does the new view scroll with the scrollview? Should I even be using a separate viewcontroller?
Any help would be greatly appreciated! Thanks!
Here's some sample code you can use to get started, just add it to your view controller. It uses a generic UIView for the floating bar and a generic UIScrollView for the scroll view but you can change that to whatever you want.
#interface BNLFDetailViewController () <UIScrollViewDelegate> {
UIScrollView *_scrollView;
UIView *_floatingBarView;
CGFloat _lastOffset;
}
#end
And in the #implementation add:
- (void)viewDidLoad {
[super viewDidLoad];
_scrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
_scrollView.delegate = self;
_scrollView.contentSize = CGSizeMake(self.view.bounds.size.width, self.view.bounds.size.height * 2);
[self.view addSubview:_scrollView];
CGRect f = self.view.bounds;
f.size.height = kFloatingBarHeight;
_floatingBarView = [[UIView alloc] initWithFrame:f];
_floatingBarView.backgroundColor = [UIColor blackColor];
[self.view addSubview:_floatingBarView];
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (scrollView == _scrollView) {
CGFloat offsetChange = _lastOffset - scrollView.contentOffset.y;
CGRect f = _floatingBarView.frame;
f.origin.y += offsetChange;
if (f.origin.y < -kFloatingBarHeight) f.origin.y = -kFloatingBarHeight;
if (f.origin.y > 0) f.origin.y = 0;
if (scrollView.contentOffset.y <= 0) f.origin.y = 0; //Deal with "bouncing" at the top
if (scrollView.contentOffset.y + scrollView.bounds.size.height >= scrollView.contentSize.height) f.origin.y = -kFloatingBarHeight; //Deal with "bouncing" at the bottom
_floatingBarView.frame = f;
_lastOffset = scrollView.contentOffset.y;
}
}
You should be doing it as a UIView, not a UIViewController. The general rule in iOS development is that view controllers take up the entire screen and views are used for "subviews" that take up part of the screen (though this is less the case for iPad). Either way, a UIViewController has it's own lifecycle (willAppear, didAppear, etc.) which is not needed/wanted for the floating bar so it should definitely be a UIView.
I made UIScrollView with some UIButton inside. The problem is that when I scroll down at the end of view, it return on start. What can i do? I use this in viewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad]; // step 3
scroll.scrollEnabled=YES;
scroll.contentSize = [self.view sizeThatFits:CGSizeZero];
}
According to Apple Documentation: sizeThatFits returns the size portion of the view’s bounds rectangle.
So your scroll view content size is of the same size of the UIView, thats why the scroll view returns to its original position. You need to set the height of the content size to the total height of your entire content in the scroll view. Normally this is bigger, because otherwise it won't make sense to use a UIViewController.
So, use something like this and it should work:
- (void)viewDidLoad
{
[super viewDidLoad]; // step 3
scroll.scrollEnabled=YES;
CGSize scrollViewSize = [self.view sizeThatFits:CGSizeZero];
scrollViewSize.height = 800.0; // Set here the height of the total area of your ScrollView. Should be bigger than the visible area.
scroll.contentSize = scrollViewSize;
}
I'm trying to add a ScrollView to a Tab Bar Controller. Problem is the ScrollView won't scroll, and I can't for the life of me find out why on Google. If I replace the ScrollView with a TextView, that one scrolls, and so does a TableView.
You can get the code demonstrating this from here: git://gitorious.org/scrollview-in-tabbar-project/scrollview-in-tabbar-project.git
Can anyone tell me what I'm doing wrong? Please notice that, annoyingly, the TextView that is inside the ScrollView scrolls. Not sure if this is related, but I don't get a viewWillAppear call when I select the ScrollView's tab.
You haven't set the contentSize of your scrollview. You are responsible to set the contentSize property. In your case, you can add this to viewDidLoad in your SecondViewController:
-(void)viewDidLoad {
[super viewDidLoad];
UIScrollView *scrollView = (UIScrollView *)self.view;
scrollView.contentSize = CGSizeMake(self.view.frame.size.width, 1024);
}
Set the height of the contentSize to what ever fits your needs (possibly you have to calculate the height to fit what you are putting in the scrollview).
Here's an example from the Apple documentation: Creating Scroll Views in Interface Builder
Based on Erik Tjernlund's answer, my code now looks like this:
- (void) viewDidLoad
{
[super viewDidLoad];
CGFloat maxDepth = 0;
for (int i = 0; i < scrollView.subviews.count; i++)
{
UIView *aSubview = (UIView *) [scrollView.subviews objectAtIndex:i];
CGFloat depth = aSubview.frame.origin.y + aSubview.frame.size.height;
if (depth > maxDepth)
maxDepth = depth;
}
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width, maxDepth);
}
and right now it looks like it satisfies my needs. It's also probably not 100% correct, and I'll find that out as I go deeper.
I'm currently using the method shown in this Cocoa with Love article to create a custom NSWindow subclass. As in the example, I needed to have a roughly 10px margin around the content of the window in order to draw an arrow (I'm creating a popover style window). I had to have the margin around the entire window instead of just the side with the arrow on it because I wanted to be able to change the arrow position without having to reposition the content.
To summarize, the method I'm using to do this is (relevant code is at the bottom):
Override the contentRectForFrameRect: and frameRectForContentRect:styleMask: methods of NSWindow to add the padding around the content:
Sets the custom drawn frame view of the window as the contentView and then overrides the setter and getter for the contentView so that the view that is passed in is added as a subview of the frame view.
The problem is that the autoresizing masks of views inside the actual content view of the window are completely messed up. Here is how I'm setting up the content in interface builder:
Here's how the autoresizing mask of the table view scroll view is set up:
And here's how the text label's autoresizing mask is set:
And here's what the result looks like in-app:
Relevant code (derived from the aforementioned article)
#define CONTENT_MARGIN 10.0
- (NSRect)contentRectForFrameRect:(NSRect)windowFrame
{
windowFrame.origin = NSZeroPoint;
return NSInsetRect(windowFrame, CONTENT_MARGIN, ICONTENT_MARGIN);
}
- (NSRect)frameRectForContentRect:(NSRect)contentRect
{
return NSInsetRect(contentRect, -CONTENT_MARGINT, -CONTENT_MARGIN);
}
+ (NSRect)frameRectForContentRect:(NSRect)contentRect
styleMask:(NSUInteger)windowStyle
{
return NSInsetRect(contentRect, -CONTENT_MARGIN, -CONTENT_MARGIN);
}
- (NSView*)contentView
{
return _popoverContentView;
}
- (void)setContentView:(NSView *)aView
{
if ([_popoverContentView isEqualTo:aView]) { return; }
NSRect bounds = [self frame];
bounds.origin = NSZeroPoint;
SearchPopoverWindowFrame *frameView = [super contentView];
if (!frameView) {
frameView = [[[SearchPopoverWindowFrame alloc] initWithFrame:bounds] autorelease];
[super setContentView:frameView];
}
if (_popoverContentView) {
[_popoverContentView removeFromSuperview];
}
_popoverContentView = aView;
[_popoverContentView setFrame:[self contentRectForFrameRect:bounds]];
[_popoverContentView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
[frameView addSubview:_popoverContentView];
}
I thought that maybe the popover content was going over the margins somehow, so I drew a border around the content view, but no, everything is as should be. The only issue is that the autoresizing masks of the label and table view inside the content view do not work as they should. Any advice is greatly appreciated.
EDIT: If anyone's interested, I've open-sourced the complete code for this popover window/controller on github as INPopoverController. Includes a sample project in case you want to try and reproduce the issue.
-( void )scaleWindowForHeight:( float )height
{
if (height > 22)
{
NSWindow* window = [self window];
NSRect old_window_frame = [window frame];
NSRect old_content_rect = [window contentRectForFrameRect: old_window_frame];
NSSize new_content_size = NSMakeSize( old_window_frame.size.width, height );
// need to move window by Y-axis because NSWindow origin point is at lower side:
NSRect new_content_rect = NSMakeRect( NSMinX( old_content_rect ), NSMaxY( old_content_rect ) - new_content_size.height, new_content_size.width, new_content_size.height );
NSRect new_window_frame = [window frameRectForContentRect: new_content_rect];
[window setFrame: new_window_frame display:YES animate: [window isVisible] ];
}
else
NSLog(#"window size too small");
}
I've created an NSScrollView which itself contains a NSClippedView as content view (this is all default, created by IB). Inside the contents view there is the (default) document view.
This NSScrollView has horizontal scroller disabled and vertical enabled and, most importantly auto hide scrollers enabled.
When I add new views (via code, runtime) to the document view the scroller does not unhide automatically, until the moment I vertically resize the window (and which in turn resizes the scrollview as well). 1px is enough. Just the new painting of the window seems enough.
What I am looking for is triggering this by code: so when I add views to the scrollviews' content view I would like the scrollbar to appear.
int numberOfChildViews = 10; //hard coded for example here
int childViewHeight = 80; //same as above
NSRect rect = NSMakeRect(0, 0, [[self.scrollView contentView] bounds].size.width, [numberOfChildViews*childViewHeight);
[[self.scrollView documentView] setFrame:rect];
[[self.scrollView documentView] setBounds:rect]; //just added to make sure
Then I added the custom views to the document view, like:
for (int i=0; i<numberOfChildViews; i++) {
NZBProgressViewController *item = [nzbProgressArray objectAtIndex:i];
int y=i*[[item view] bounds].size.height;
rect= NSMakeRect(0, y, [[scrollView contentView] frame].size.width, [[item view] bounds].size.height);
[[item view] setFrame:rect];
currentPosition++;
}
I am using a FlippedView so the origin will be displayed in left-top, like so:
#interface NSFlippedClipView : NSClipView {
}
#implementation NSFlippedClipView
- (BOOL)isFlipped {
return YES;
}
- (BOOL)isOpaque {
return YES;
}
#end
And added the following code to the awakeFromNib
NSFlippedClipView *documentView = [[NSFlippedClipView alloc] init];
[documentView setAutoresizingMask:NSViewWidthSizable];
[documentView setBackgroundColor:[self.scrollView backgroundColor]];
[self.scrollView setDocumentView:documentView];
[documentView release];
The scrollbars should become visible as soon as the document view is resized to be larger than the current viewport of the scroll view. Are you resizing the document view when you add your subviews to it?
Ahh, it's my own bad. For future reference: if you want to move the origin (0,0) to left-top use a NSView instead of NSClippedView extended class with IsFlipped method overriden to YES.
Thanks irsk for answering.