I have a scrollView which is a UIScrollView in a CustomCell which is a subclass of UITableViewCell. I have two different pages in a cell. So, I'm using my scrollView in pagingEnabledmode.
My question is that can i change my scrollView background color after passing second page then set it back to initial color after returning back ?
So far, i tried to use two different UIScrollView, then i realized that i can't use pagingEnabled mode.
To be more specific, i want my initial screen which width is 360 and height is 70 in blue,and my second screen is green which starts after 360 px.
Try to use the scrollViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)sender {
CGFloat pageWidth = 360;
int page = floor(scroll.contentOffset.x / pageWidth) ;
if (page == 1) { /// second scroll page
myView.backgroundColor = [UIColor greenColor];
} else { ///first scroll page
myView.backgroundColor = [UIColor blueColor];
}
}
try this one :
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
int page = scrollView.contentOffset.x / scrollView.frame.size.width;
if (page == 0){
// first page's background color
}
else{
// first page's background color
}
}
Also in the viewDidLoad add this :
mainScroll.ContentSize = CGSizeMake(320*2, 70);
Related
Stuck on something and i'm not sure if it's even possible. Is there a way to set the background of a UITableView as a custom image, but NOT let that background apply to the tableHeaderView. I have a header on my table that needs to remain transparent, because I have a parallax type effect (like the path 2 app) implemented with an image behind the transparent table header & the top 1/3rd of the tableview... but i need to get a custom image behind the rest of the table.
I can successfully get close to the background style im looking for that fills in behind each cell, with:
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
However, this is not quite what Im looking for because I would like a radial gradient background view behind the entire tableview on the screen, minus the transparent header... not just the same image for each cell. Also, this approach really hits my tableview's scrolling performance loading a new BG image with each cell.
I know you can use:
UIImageView *tempImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"image.png"]];
[tempImageView setFrame:self.tableView.frame];
self.tableView.backgroundView = tempImageView;
to set the BG image for the tableview, and it is really close to what I'm trying to do, but I neeeeeed that header transparent. Is there any way to use this, but also tell the tableHeaderView to ignore it and be transparent?
Thanks everyone, & happy Halloween!
Yes, you can. I implemented a solution for the parallax effect for a grouped UITableView. You could use the same approach except instead of a black background (example below) you could use your image. Essentially, you have two views behind the tableview (which is clear, header view background clear as well as the table view background itself). These two views you move based on scrolling (UIScrollViewDelegate). Your tableview background image you'll "scroll" 1 for 1 with the table, while your parallax image will "scroll" at a different rate of course. In the below example i think my "_secondParaView" would be your background image for the table.
Firstly, in viewDidLoad, create a view to partially hide your image for the parallax effect, should be the same color as the background you want the tableview to be, in my case blackColor. I placed the view at a fixed offset based on the size of my image, you want the top of this view to line up with the top of the end of 'section 0' header view. It will then "scroll" just as the tableview scrolls. Insert this view below the tableview.
_secondParaView = [[UIView alloc] initWithFrame: CGRectMake(0.0, kTableViewOffset, self.view.frame.size.width, 200.0)];
_secondParaView.backgroundColor = [UIColor colorWithRed: 0.0 green: 0.0 blue: 0.0 alpha: 1.0];
[self.view insertSubview: _secondParaView belowSubview: _tableView];
_headerImageYOffset = -40.0;
_headerImageView = [[UIImageView alloc] initWithImage: [UIImage imageNamed: #"SpaceRedPlanet640x480.png"]];
CGRect headerImageFrame = _headerImageView.frame;
headerImageFrame.origin.y = _headerImageYOffset;
_headerImageView.frame = headerImageFrame;
[self.view insertSubview: _headerImageView belowSubview: _secondParaView];
_tableView.backgroundColor = [UIColor clearColor];
Then implement the two grouped tableview methods for the header view / header view size:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
if (section == 0) {
UIView * tableHeaderView = [[UIView alloc] initWithFrame: CGRectMake(0.0, 0.0, self.view.frame.size.width, kTableViewOffset)];
tableHeaderView.backgroundColor = [UIColor clearColor];
return tableHeaderView;
} else
return nil;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
if (section == 0) {
return kTableViewOffset;
} else
return 2;
}
Just like in the "normal" tableview parallax implementation, make your VC a UIScrollViewDelegate and implement this scrollViewDidScroll like so:
#pragma mark -
#pragma mark UIScrollViewDelegate methods
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat scrollOffset = scrollView.contentOffset.y;
CGRect headerImageFrame = _headerImageView.frame;
CGRect underParaFrame = _secondParaView.frame;
if (scrollOffset < 0) {
// Adjust top image proportionally
headerImageFrame.origin.y = _headerImageYOffset - ((scrollOffset / 3));
} else {
// We're scrolling up, return to normal behavior
headerImageFrame.origin.y = _headerImageYOffset - scrollOffset;
}
underParaFrame.origin.y = kTableViewOffset - scrollOffset;
_headerImageView.frame = headerImageFrame;
_secondParaView.frame = underParaFrame;
}
Hope this helps, or at the very least helps someone implement the parallax effect for a grouped tableview. I could find no solution for it.
Is there a reason why you cannot have the tableHeaderView be a container for the image you wish to have the parallax-type effect?
Create a UIView and stick it as the tableHeaderView of the UITableView, and then add your UIImageView (or whatever) to that tableHeaderView. With UIScrollView's delegate methods, you will be able to reposition this UIView however you please within it's parent view in reaction to user scrolling.
See this open source project for a Path inspired parallax UITableView: RBParallaxTableViewController
I've got a VC with a table view. When an event occurs, I want to drop in a UIView from the top of the main view. When the user scrolls the table view, I want to re-layout the view so that the dropped in view "scrolls away". I figured I'd do this by moving the upperView's frame and resizing the table view (both in relation to the scroll offset). I've got it almost working as follows:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat contentOffsetY = scrollView.contentOffset.y;
if (contentOffsetY > 0) {
CGFloat upperHeight = self.upperView.frame.size.height;
CGFloat fullTableHeight = self.view.frame.size.height;
CGFloat offsetY = (contentOffsetY < upperHeight)? -scrollView.contentOffset.y : -upperHeight;
self.upperView.frame = CGRectMake(0, offsetY, 320, upperHeight);
scrollView.frame = CGRectMake(0, upperHeight+offsetY, 320, fullTableHeight-(upperHeight+offsetY));
}
NSLog(#"%f", self.upperView.frame.origin.y);
}
The upper view origin starts at 0,0.
The problem is, after a little dragging back and forth, I lose the top few pixels of that upper view. It can't seem to get it's origin y back to zero. The logging reads negative values, and only gets to -1, with the most careful dragging. Has anybody done something like this? Much obliged if you can help.
It sounds like you always scroll the table view to the top when you show the drop-in view. Assuming that's the case, there is a better way to do this.
UITableView inherits the contentInset property from UIScrollView. The contentInset property defines a border on each edge of the scroll view. Each border has its own thickness, which is zero by default. These borders just affect how far the scroll view is willing to let the user scroll the content - they don't hide the content! If you set the top inset larger than zero, and give the scroll view a subview with a negative Y origin, that subview can be visible in the border, and will scroll with the rest of the scroll view's content.
So we'll set the table view's top inset to the height of the drop-in view, and add the drop-in view as a subview of the table view with its origin set to the negative of its height. This will make it fit perfectly on the screen above the first row of the table view, and it will scroll with the table view. When we detect that the drop-in view has been scrolled fully off-screen, we can just remove it from the table view and set the table view's top inset back to zero.
We'll need an instance variable that tracks the current state of the drop-in view:
typedef enum {
DropInViewStateHidden,
DropInViewStateAppearing,
DropInViewStateVisible
} DropInViewState;
#implementation ViewController {
DropInViewState _dropInViewState;
}
In my test project, I just used a button to trigger the drop-in view. Here's the action:
- (IBAction)dropIn {
if (_dropInViewState != DropInViewStateHidden)
return;
CGRect frame = self.dropInView.frame;
frame.origin.y = -frame.size.height;
self.dropInView.frame = frame;
[self.tableView addSubview:self.dropInView];
self.tableView.contentInset = UIEdgeInsetsMake(frame.size.height, 0, 0, 0);
[self.tableView setContentOffset:frame.origin animated:YES];
_dropInViewState = DropInViewStateAppearing;
}
When the table view scrolls, we check the state of the drop-in view. If it is in the “visible” state and has been scrolled off-screen, we hide it. There's a tricky bit because when we make the drop-in view visible, and scroll it onto the screen, we can receive scrollViewDidScroll: messages that would make us think the drop-in view has been hidden. That's why we start out in the DropInViewStateAppearing state, and transition to the DropInViewVisible state when we know the view has appeared.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
switch (_dropInViewState) {
case DropInViewStateHidden:
break;
case DropInViewStateVisible:
if (scrollView.contentOffset.y >= 0) {
// dropInView has been scrolled off-screen
self.tableView.contentInset = UIEdgeInsetsZero;
[self.dropInView removeFromSuperview];
_dropInViewState = DropInViewStateHidden;
break;
}
case DropInViewStateAppearing:
// When I first add dropInView to tableView and tell tableView
// to scroll to reveal dropInView, I may get a bunch of
// scrollViewDidScroll: messages with contentOffset.y >= 0.
// I don't want those messages to hide dropInView, so I sit in
// DropInViewStateAppearing until contentOffset.y goes negative,
// which means at least part of dropInView is actually on-screen.
if (scrollView.contentOffset.y < 0)
_dropInViewState = DropInViewStateVisible;
break;
}
}
Figured this out: The UITableView doesn't thoroughly message didScroll during the bounce. This is why I was missing a few pixels. Resizing during the bounce makes the bounce get mixed up and stop. This fix on my code above allows the bounce to work (by moving, not resizing the table) and makes sure the upper view is correctly placed during the bounce (when contentOffset.y <= 0).
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat contentOffsetY = scrollView.contentOffset.y;
CGFloat upperHeight = self.upperView.frame.size.height;
CGFloat fullTableHeight = self.view.frame.size.height;
CGFloat offsetY = (contentOffsetY < upperHeight)? -scrollView.contentOffset.y : -upperHeight;
if (contentOffsetY > 0) {
self.upperView.frame = CGRectMake(0, offsetY, 320, upperHeight);
scrollView.frame = CGRectMake(0, upperHeight+offsetY, 320, fullTableHeight-(upperHeight+offsetY));
} else {
self.upperView.frame = CGRectMake(0, 0, 320, upperHeight);
scrollView.frame = CGRectMake(0.0, upperHeight, 320, scrollView.frame.size.height);
}
[super scrollViewDidScroll:scrollView];
}
I have a view that have some images, text, and more to show and two button in left and right when user click on left or righr button page should get side and another page should get open with new info.
How i can do it please help.
try with this link.. You will get the logic to solve your problem. Place a button on each side where you want & use the logic from this thread
Enable paging for the scrollview.
When a button is tapped modify the content offset of the scrollview by the width of the scrollview using setContentOffset:animated:
Use this code
-(IBAction)prevButtonPage:(id) sender
{
CGFloat xOffset = pagingScrollView.contentOffset.x;
CGFloat yOffset = pagingScrollView.contentOffset.y;
if (pagingScrollView.contentOffset.x != pagingScrollView.frame.origin.x)
{
[pagingScrollView setContentOffset:CGPointMake(xOffset- 320, yOffset) animated:YES];
// [arrayIndia objectAtIndex:i];
}
NSLog(#" custom x==%f %f", pagingScrollView.contentOffset.x, pagingScrollView.contentSize.width);
}
-(IBAction)nextButtonPage:(id) sender
{
CGFloat xOffset = pagingScrollView.contentOffset.x;
CGFloat yOffset = pagingScrollView.contentOffset.y;
if ((pagingScrollView.contentOffset.x != pagingScrollView.frame.origin.x)&&(pagingScrollView.contentOffset.x !=[imageArray count]) )
{
[pagingScrollView setContentOffset:CGPointMake(xOffset + 320, yOffset) animated:YES];
}
NSLog(#" custom x==%f %f", pagingScrollView.contentOffset.x, pagingScrollView.contentSize.width);
}
I'm a beginner when it comes to page control, and that's why I'm not sure 100% if my title agrees with what I want. I want to make a UIPageControl that when the user swipes on the screen, the view would switch over to another view and the UIPageController at the bottom of the screen would update itself. Also, to make my request even more confusing, I want a tab bar at the bottom of the screen that would stay put as the views change.
A great example of this is The Iconfactory's Ramp Champ:
http://img.slidetoplay.com/screenshots/ramp-champ_5.jpg
The bar at the bottom stays put while the rest of the items on the screen moves. What would be the easiest way to do this?
EDIT: I know I have to use a UISrollView, I just don't know how to go about implementing it...
I believe what you're looking for is actually a UIScrollView with pagingEnabled set to YES. You can leave the scrollview as a view above a regular UITabBar. You'll use a UIPageControl to get the little dots. You can update it programmatically when the UIScrollView scrolls to a page by implementing an appropriate delegate method of the scroll view, maybe -scrollViewDidScroll:.
Assume you have two ivars: scrollView and pageControl. When you know how many pages your scroll view will have, you can set the contentSize of scrollView. It should be a multiple of the scrollView's bounds. For example, if the number of pages is static you can hardcode it in your -viewDidLoad...
- (void)viewDidLoad {
// Any other code.
scrollView.pagingEnabled = YES;
scrollView.contentSize = CGSizeMake(scrollView.bounds.size.width * 3, scrollView.bounds.size.height); // 3 pages wide.
scrollView.delegate = self;
}
Then, to update your little dots...
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat pageWidth = scrollView.bounds.size.width;
NSInteger pageNumber = floor((scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
pageControl.currentPage = pageNumber;
}
You need to use a UIScrollView
Assuming you have a named ivar called scrollView
int amountOfFrames = 10;
scrollView.pagingEnabled = TRUE;
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * amountOfFrames, scrollView.frame.size.height);
scrollView.delegate = self;
You will then need to implement the required delegate methods, so that you can update your page control
- (void)scrollViewDidScroll:(UIScrollView *)sender
{
// Switch the indicator when more than 50% of the previous/next page is visible
CGFloat pageWidth = scrollView.frame.size.width;
int page = floor((scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
pageControl.currentPage = page;
}
You need to place whatever content you want to be scrollable inside these scrollview, ideally lazyload into it, if the content you will displaying will require a lot of heap memory, use the scrollviewDidScroll to remove and add content at the required positions
I'm trying to do a horizontal scroll of UILabels with different widths.
I've already put all labels next to each other inside the UIScrollView, but since the page scrolling, bouncing and snapping is done in scrollview.frame.width "steps", i cannot set it to work as I'd wish.
Can this be done? Thank you so much :)
What happens if you set the size of your width property to be the width of the next label? Something like (in your scroll view delegate) :
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
// Get the label that's going to slide into view
UIView *label = [self getCurrentLabel];
// Get it's width
float width = [label frame].size.width;
// Set our size
CGRect frame = [scrollView frame];
frame.size.width = width;
[scrollView setFrame:frame];
}
PS I've not tried this so it might just fail horribly!