Image and Html content on app screen with combined scrolling - ios

Problem
I want to display an image and Html text on the app screen. The text is large so it may not fit on a screen so I want the content to be scrollable. WebView by default has scroll functionality for content going beyond screen size. But I don't want just the text to move upwards as I scroll down but also the image to move upwards i.e. I do not want the image to stick around on the screen when I scroll downwards.
One simple solution for this is to have the image rendered within the html content, but I do not want to do that because ImageView allows me additional functionality that I want to use.
Possible solution
The solution I tried for this was having an ImageView and a WebView within a ScrollView but when I try implementing it, only the webview content is scrolling and the image is fixed. (This is possibly because the WebView's scroll is getting preference over the parent ScrollView's scroll. I even tried setting WebView's child scroll view's delegate to outer scroll View but that didn't help and html text was not scrollable at all after build:
webview.scrollView.delegate = self.scrollView
How can I solve the problem of combined scrolling for ImageView and content in WebView possibly using other container views (if necessary)?

It sounds like you could use a UITableView with a UIImageView as your tableViewHeader. The UIWebView component could be a UITableViewCell or a tableFooterView depending on how you want to architect your view.
Set your UIImageView as your UITableView's tableHeaderView. That way, as the table scrolls, your image will scroll off screen.
Create a UITableViewCell that contains a UIWebView. You can set the height of the cell to whatever your content size is, or the screen size. The webview itself will be scrollable in this cell, and the user also is able to scroll back up to see the image header.

You can try this method :
Disable the scrolling of webview. Place the image on top of webview.
self.yourScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
self.yourWebView = [[UIWebView alloc] initWithFrame:CGRectMake(x position, y position, width, height)];`
self.yourWebView.opaque = NO;
self.yourWebView.scrollView.scrollEnabled = NO;
self.yourNewsArticleImageData = ({
UIImageView* imgView = [[UIImageView alloc] initWithFrame:CGRectMake(x position, y position, width, height)];
imgView.contentMode = UIViewContentModeScaleAspectFit;
imgView.backgroundColor = [UIColor clearColor];
imgView;
});
[self.yourScrollView addSubview:self.yourWebView];
[self.yourScrollView addSubview:self.yourNewsArticleImageData];
self.yourScrollView.contentSize = CGSizeMake(self.view.frame.size.width, self.view.frame.size.height);
self.yourScrollView.scrollEnabled = YES;
[self.view addSubview:self.yourScrollView];
Main thing you need to do is disable the scrolling of webview and enable scrolling of your scroll view. Put image and webview content as subviews of scrollview.
You can change the height of the scroll view in the webview didFinish delegate method. Once you get the height of the webView loaded content change the "content size" of scroll view accordingly.

Related

IOS/Objective-C: Unhindered scrolling of tableview created in code (remove rubber band effect)

I have created a tableview in code as follows:
_myTableView = [[UITableView alloc] initWithFrame:
CGRectMake(160, 80, 140, 100) style:UITableViewStylePlain];
_myTableView.delegate = self;
_myTableView.dataSource = self;
_myTableView.scrollEnabled = YES;
[self.view addSubview:_myTableView];
It largely works as it should with the following exception. Because the results in the table vary, I manually adjust the height of the tableview so that it only takes up as much space as the returned rows need as follows:
-(void) changeTVHeight: (float) height {
//height calculated from number of items in array returned.
CGRect newFrame = CGRectMake(120, 80, 180, height);
self.myTableView.frame = newFrame;
}
This works great for shrinking the tableview if there aren't that many results.
However, if there are a lot of results, the tableview expands below the visible part of the screen or the keyboard. In this case, I would like to be able to scroll the Tableview to see the lower rows.
scrollEnabled is set to YES.
But while it does allow one to scroll a bit, the scroll is resisted so with effort you can scroll a little bit but due to rubber band effect you cannot get further than a few rows below the screen and you cannot tap on the lower rows.
I am using autolayout in storyboard for much of the screen. The overall screen scrolls fine but this merely moves the tableview anchored to the screen up and down. There are no constraints on this tableview but it is added as a subview of the view.
My question is how can I make the tableview scrollable so that it scrolls without resistance?
Thanks in advance for any suggestions.
Edit:
I tried adding the tableView to self.scrollView instead of self.view. This anchored the tableView to the scrollview so it is possible to scroll the whole screen down and see the bottom of the tableview. However, this is not ideal because the rest of the screen is empty way down and you can't see the context for the tableview. (It's an autocomplete for a textfield at top of screen.)
In contrast when the tableview is added to self.view, it is in correct place, it semi-scrolls or bounces. It just doesn't scroll down to where I need it to scroll.
You need to set a limit so that the table view cannot be larger than the view itself. Tableviews are built on UIScrollView and will handle scrolling on their own, you don't need to try to size it manually. The reason the table view bounces but doesn't scroll is because it is extending below the bottom of the screen. It wont scroll because it has already scrolled to the bottom, you just can't see it because it's outside of the superview.
-(void) changeTVHeight: (float) height {
CGFloat limitedHeight = MIN(height, self.view.frame.size.height)
CGRect newFrame = CGRectMake(120, 80, 180, limitedHeight);
self.myTableView.frame = newFrame;
}

Scrollable UITableView as an overlay

I'm trying to replicate the following GIF from Postmates checkout - a scrollable UITableView positioned on top of a MapView. This tableview can be scrolled, with the normal bounce effect if I go too far down or up.
Currently, I have the MapView and UITableView added as sibling views to my ViewController's view. I have adjusted the frame of the table view to move it down.
CGRect rect = CGRectMake(
0.f,
200.f,
self.view.bounds.size.width,
self.view.bounds.size.height - self.navigationController.navigationBar.bounds.size.height - 200.f
);
The two main issue's I'm having are:
I cannot figure out how to drag the entire tableview down when pulling down. E.g. the grey (my tableView.backgroundColor) sticks when I scroll down. If however, I make that background clear, then when I drag up, you see the map emerging from behind the view.
My cells keep disappearing when I scroll up. I have clipsToBounds = false, and I'm not actually dequeuing cells, just creating them in my cellForRow method, but they still disappear.
I feel like this should be a straightforward layout, but I'm missing something!
I've tried adjusting the contentInset of the table view, but then the scrollbar does not align with the cells as it does in the gif and does not look nice.
We needed similar effect in our app, along with parallax in the underlying view(map here/ we had a photos gallery).
I assume you want something like shown on this blogs video here
I wrote a small blog on how to achieve this. You can find this here
Basically its just a play of contentInsets and contentOffset properties of UITableView
If this does not suits you, here my suggestion in your two main points.
Controller's View has subviews
Map View (fills complete super view)
UITableView (fills complete super view) and in code set content insets.top = kHeightOfVisibleMap
The solution was simpler than I thought, no autolayout or crazy weird tricks required.
Add a full screen table view to your controller, and insert a full screen map view behind it.
self.mapView = [[MKMapView alloc] initWithFrame:self.view.bounds];
[self.view insertSubview:self.mapView belowSubview:self.tableView];
Add a dummy view with the background color of your table view with a height of around 200 pixels, and a full width, into the tableFooterView on your table view.
CGFloat footerHeight = 200.0;
UIView *dummyView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.tableView.bounds.size.width, footerHeight)];
dummyView.backgroundColor = [UIColor whiteColor];
self.tableView.tableFooterView = dummyView;
Set the content offset of the table view to be the inverse of that footer view's height:
CGFloat footerHeight = dummyFooterView.bounds.height;
self.tableView.contentOffset = CGPointMake(0, -footerHeight);
Set the content inset of your table view to offset the footer view.
self.tableView.contentInset = UIEdgeInsetsMake(footerHeight, 0, -footerHeight, 0)
Adjust the scrollbar position, again, based on the footer's height.
self.tableView.scrollIndicatorInsets = UIEdgeInsetsMake(footerHeight, 0, 0, 0);
This will push down the tableview, ensure the scroll bars match the table view, but allow it to bounce 'up' above its initial position and will ensure the background does not peek through the bottom of the tableview.

Scrolling a UITextview with UIScrollview

So I've created an UITextView and put it inside an UIScrollView. However, I disabled scrolling for UITextView, so I was wondering is it possible for me to scroll the textview at the same time while I'm scrolling through my UIScrollView?
I'm not sure if someone has already asked something like this, I tried to search through the site and couldn't find any topics related to my problem. If there's an existing post like this I would appreciate it if someone plink me to it.
UIScrollView is a scrolling UIView. So you need just to add the UITextView to the scroll view as a subview and it will scroll with it, basically something like this:
UIScrollView *scrollView = [UIScrollView alloc]initWithFrame:CGRectMake(0,0,320,460)];//adjust the frame to fit your needs
scrollView.contentSize = CGSizeMake(400, 600);//make sure the size in contentSize is bigger than the size of the scrollView frame: (400, 600) is bigger than (320, 460), otherwise the scroll effect won't be performed
UITextView *textView = [UITextView alloc]initWithFrame:CGRectMake(0,0,200,400)];//adjust the frame to fit your needs
[scrollView addSubview:textView];//need to add the text view as a subview
[self.view addSubview:scrollView];

UIScrollView keep scroll rect while resizing

I have got a UIScrollView with a UIImageView as subview. The contentSize of the ScrollView has been set to the size of the UIImageView.
I implemented zooming and scrolling of the UIImageView.
I need the UIScrollView to keep the scroll rect when I change its frame (proportionally).
How is this done?
My problem is, whenever I change the frame of the UIScrollView the visible rect of the UIImageView changes.
Thanks!
If I understand your problem correctly, you want to shrink the frame of the scroll view without changing what you are able to see inside of the scroll view. You can do this in the following way:
Create a new UIView and set its frame to the position and size that you want to see the content of the scroll view. Turn on the clips to bounds on that view, view.clipsToBounds = yes. Add the scroll view as a subview to the view you created. [view addSubview:scrollview]. Turn clips to bounds off on the scrollview, scrollview.clipsToBounds = no.
Hope that helps.

how to expand image on UITableView like in CNN app

I have the CNN app on my iPhone.
If you open it will show "top stories", and has always a picture on the top of the table.
When we slide our finger down it expands/zooms the image.
When we slide our finger up to show more rows it does not move the image upwards at the same speed has the table rows instead the table rows move faster than the picture going off the screen.
Do you know how to do this effect?
You need UIImageView to UIScrollView contentInset and set top inset more than zero.
UIScrollView *scroll = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
UIImage *topImage = [UIImage imageNamed:#"photo"];
topImage.frame = CGRectMake(0, -topImage.frame.size.height, topImage.frame.size.width, topImage.frame.size.height);
[scroll addSubview:topImage];
self.contentInset = UIEdgeInsetsMake(topImage.frame.size.height, 0, 0, 0);
After that set UIScrollView's contentOffset like this
scroll.contentOffset = CGPointMake(0, topImage.frame.size.height);
So you have the UIScrollView with image inside it. Now you just need to add delegate to UIScrollView and wait for - (void)scrollViewDidScroll:(UIScrollView *)scrollView. Resize image and change contentInset right after this method called.
This advice you also can apply to UITableView similar way, or create category on UIScrollView.
I also advice you to read code of this project https://github.com/samvermette/SVPullToRefresh. It's also about UITableView and adding view to it's top side
It seems like a completely custom effect that you will have to implement yourself. To point you in the right direction, I'd first monitor contentOffset changes in the scrollViewDidScroll: messages sent by your myTableView instance, and when the contentOffset.y < 0, change the scale of your imageView via
[myImageView setValue:[NSNumber numberWithFloat:scaleIncrementAmountFloat] forKeyPath:#"transform.scale"];
My guess is that the top cell (or cells) of the tableview are transparent and there is a UIImageView behind the tableview that is resized/moved based on how the table view is scrolled.
Since the table view inherits from UIScrollView, its delegate (UITableViewDelegate) inherits from the UIScrollViewDelegate protocol which is notified when a the user scrolls the scroll view. Implement the - (void)scrollViewDidScroll:(UIScrollView *)scrollView method to receive these notifications and check the contentOffset property on the scroll view.
You may have to implement you own table view controller to build the desired UI in the interface builder.

Resources