Horizontal dragging of UIScrollView - ios

I have a subclass of UIScrollView class and this scroll have vertical content. But I need drag and drop this UIScrollView in the parent view on horizontal direction. How can I implement this?

You must have a specific hierarchy:
Before you do anything you must go to your StoryBored and deselect the Autolayout option under the FileInspector.
View
ScrollView
ContainerView (if you want one or have one)
View
UIControl (if you have one)
THE CONTENTS OF YOUR VIEW.
You must however make a declaration of the scrollView in your header file:
IBOutlet UIScrollView *yourScrollViewName;
In your main under viewDidLoad:
-(void)viewDidLoad {
yourScrollViewName.translatesAutoresizingMaskIntoConstraints = NO;
[yourScrollViewName setScrollEnabled:YES];
[yourScrollViewName setContentSize:CGSizeMake(320 ,554)]; //320 is the x which is the width. change this to make it horizontal.
//554 is the Height this has to be larger that the screen size in order to have vertical scrolling.
[yourScrollViewName setPagingEnabled:NO];
}

Related

keep area outside scrollview also scrollable

I have a scrollview where I have added different views (like tutorial).
What I wanted to have is slider with below design where on scroll I will see previous tut on left side and next on right side.
For this what I have added is scrollview with paging enabled and adding UILabel (for now) in for loop. After adding label in scrollview below is what I had.
To see the data on the left & right, what I did is uncheck clip subviews from storyboard.
However what I noticed is I can scroll only in scrollview area and not outside.
Any idea how can I make UILabel make scrolling outside & inside scrollview.
As of now to make it working, what I have done is added swipe gesture on view and making scrolling programmatically. However what I was looking is if I scroll outside scrollview, it should scroll scrollview little too.
Phewww...
Finally I managed to make it done..
What I did is added one more scrollview (dummyScrollView) with full screen width above main scrollview (mainScrollView) (which I am using to show label).
Now I enabled paging for the dummyScrollView too and implement below where I am scrolling my mainScrollView based on the factor calculation for the dummyScrollView
#pragma mark - UIScrollView Delegate
- (void) scrollViewDidScroll:(UIScrollView *)sender
{
float myFactor = 0;
// 44232 is tag for new scrollview
if (sender.tag==44232) {
myFactor = mainScrollView.frame.size.width/duplicateSV.frame.size.width;
myFactor = duplicateSV.contentOffset.x*myFac;
CGRect mCC = CGRectMake(myFactor, 0, mainScrollView.frame.size.width, mainScrollView.frame.size.height);
[mainScrollView scrollRectToVisible:mCC animated:NO]; // NO is very important... YES will not work
}
// 44231 is main scrollview tag where I won't be doing anything...
if (sender.tag==44231) {
}
}

UITableView dynamic content size height inside UIScrollView with AutoLayout

I have a UIScrollView, inside this UIScrollView I have a UIView and inside the UIView I have some UITextField's, some UILabel's and at the bottom there is a UITableView.
I want the UITableView to fit it's content height, the UIView to fit it's content height and the UIScrollView to fit it's content height.
The UITableView height might change as I add / remove cells from it during usage.
What is the best way to handle it using AutoLayout?
- UIViewController
-- UIView
--- UIScrollView
---- UIView
----- UILabel
----- UITextField
----- UITextView
----- UITableView (at the bottom of the superview)
or as in the xib:
The best way to implement this is to scrap the hierarchy that you have now and do the following...
- UIViewController (or UITableViewController)
--- UITableView
----- UIView (as the tableView.tableHeaderView)
------- UILabel
------- UITextField
------- UITextView
----- Rest of the cells for the table view.
The tableView.tableHeaderView is a single (not reusable, concrete) view that is placed at the top of the content of the table view and scrolls with the content of the table view. It doesn't stick to the top of the screen like a section header view does.
This will allow you to delete the scroll view and place everything inside the table view and still doesn't change the methods that you are using to populate the cells as that remains untouched.
#Jan Greve is correct. But if you still want to do it
Set Bottom Space to Container constraint between the Table View and its super view to 0
Increase/decrease the height constraint of the Table View with each insert/delete (You will have to do this programmatically)
Set the content offset of the scrollview to the new view height
The best part of AutoLayout is now you don't have to worry about UIScrollView content size.
If you set all constraints properly(without any warnings) AutoLayout manage content size for scrollView itself.
Set all subview's constraints but don't add height and width constraints.
And for contentSize add bottom constraint of inner view (subview of scrollview) to UIScrollView. This will increaser scrollView content size and height as per inner view expand or shrink.
For more details: I asked question for same, you can check it. You can find code in question itself.
You can set a fixed height to the tableView and link the constraint to an outlet. Then you'd need to override viewDidLayoutSubviews() in order to set the height dynamically based on the contentSize of the table:
#IBOutlet weak var dynamicTVHeight: NSLayoutConstraint!
internal override func viewDidLayoutSubviews() {
let height = min(self.view.bounds.size.height, self.tableView.contentSize.height)
self.dynamicTVHeight.constant = height
self.view.layoutIfNeeded()
}

How to allow scrollview subviews to respond to scroll

I am developing a media based application for iOS, It has a scrollview which has three subviews in it - a UIImageView, a title UILabel and a UIButton.
When I scroll the scrollview I want the UILabel to be fixed (i.e it shouldn't scroll with the scrollview) untill the UIImageView scrolls up completely.
Please can you help me, how can I keep the title label frame at a constant height until the scroll view scrolls to a certain height.
I would first make sure the UILabel isn't a subview of the scroll view. Then add <UIScrollViewDelegate> to your view controller class. Then in your .m file add
- (void) scrollViewDidScroll: (UIScrollView *) scrollView
{
CGFloat y = scrollView.contentOffset.y;
if (y > (your number here)) {
// Do something with the UILabel
}
}
Already answered here

Can't scroll both UIScrollView in UITableViewCell and the UITableView itself

My pure AutoLayout UITableViewCell looks like this in Interface Builder:
UITableViewCell
|-> UITableViewCell.contentView
|-> UIView (ScrollViewContainerView)
|-> UIScrollView
|-> left (fixed)
|-> center (fill remaining)
|-> right (fixed)
The UIScrollView contains a left, center, and right UIView. left and right are both fixed width, while center expands to fill the remainder of the UIView. The UIScrollView constraints are to align all edges to ScrollViewContainerView. ScrollViewContainerView constraints are to align all edges to the UITableViewCell.contentView. I have a constraint on center's width to be a multiple of ScrollViewContainerView's width, so the UIScrollView scrolls left and right, but the height is fixed and does not scroll. Note that the UIScrollView has been subclassed to include this code so that the UITableView can detect a tap on the cell to toggle selection.
The issue is that I currently can either scroll the UITableView containing these UITableViewCells up and down or I can scroll the UIScrollViews in the UITableViewCells left and right, not both.
When ScrollViewContainerView.userInteractionEnabled == YES, I can't scroll the UITableView up and down, but I can scroll the UIScrollView left and right. When ScrollViewContainerView.userInteractionEnabled == NO, I can scroll the UITableView up and down, but I can't scroll the UIScrollView left and right. userInteractionEnabled == YES on everything else in the above hierarchy.
I can get away with having ScrollViewContainerView as a sibling view to the UIScrollView (making the UIScrollView the direct descent of contentView -- can't get rid of this view completely, because I require it to get the dimensions for the UIScrollView frame). In that case, the opposite handling with userInteractionEnabled holds.
I know I've done this before in other projects before, but starting fresh again, I can't seem to figure out what step I'm missing. Currently using Xcode 6 6A215l targeting iOS 8, though I have reproduced the issue under Xcode 5 targeting iOS 7.
It sounds like the scrollview is causing your tableview to not allow userInteraction when being scrolled. I'm sure that if you called - (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView in the UIScrollView delegate (not sure for iOS 8), but you could just do
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
if(scrollView.dragging == YES) {
self.<scrollViewName>.userInteractionEnabled = NO;
}
}
This is untested code, but it's just a bit of help to get you where you need to go.
Hope it helps!
I met some similar problem.
I have a scrollView in tableViewCell. All works fine.
Until one day, someone told me that the tableView can't scroll up/down when finger is touched on the scrollView in 6p. Just in 6p, not in 5, 5s,or6.
This makes me almost crazy.
Finally, I set the scrollView's height smaller than the height in storyboard.
Biu ~ It works~~~
Still, I don't know why.
#user2277872's answer put me on the right track to look at the output of the UIScrollView delegate methods of the UIScrollView in my UITableViewCell subclass. Putting an NSLog() in scrollViewWillBeginDragging: made me notice that the UIScrollView was receiving scrolling events while I was trying to scroll the UITableView. My UIScrollView had a contentSize larger than its frame in both directions, but I've forced that view to only scroll horizontal, so ignored the height and reset it. That force was my undoing and I should have known it at the time -- the correct solution is to fix the frame height. If the UIScrollView doesn't think there is more vertical content, it will correctly forward the swipe up/down gesture to the UITableView.
While I attempt to figure out why my contentSize is too large when it wasn't before (thinking I'm missing a clipToBounds somewhere), what I'm doing to force horizontal scrolling temporarily is (in the UITableViewCell's subclass):
- (void)drawRect:(CGRect)rect
{
[super drawRect:rect];
CGSize contentSize = self.scrollView.contentSize;
contentSize.height = self.frame.size.height;
self.scrollView.contentSize = contentSize;
}
EDIT: Actually, this is seemingly better than overriding drawRect. This would be in the UIScrollView subclass:
/*
* Lock to horizontal scrolling only.
*/
- (void)setContentSize:(CGSize)contentSize
{
[super setContentSize:CGSizeMake(contentSize.width, 1)];
}
The height struct member isn't too important, as long as it's guaranteed to be smaller than the frame.size.height of the UITableViewCell. Still hacky, still need to find why I could clip before and not now.

Scrolling ViewController Content

What I have in the view controller view are :
An image of fixed height
Few labels
Table view with n rows.
Once rendered I want everything here to be inside the scroll the view so the user can scroll the entire screen as needed. Note that the scrollView needs to expand to the entire size of the tableView to show its full contents. I have tried different ways of doing this but unable to do it. I would appreciate any pointers or code segment to get this done.
There are essentially two ways to do so.
tableHeaderView
The first way involves the tableHeaderView property of the UITableView instance you have. You can simply add the UITableView with the constraints/frame/autoresizingMask that allows you to put it full-screen. Done that, you simply do (i.e. in your viewDidLoad):
UIView *headerView = [UIView new];
// Here I am supposing that you have a 200pt high view and a `self.tableView` UITableView
headerView.frame = CGRectMake(0, 0, self.tableView.frame.size.width, 200.0);
UIImageView *fixedImageView = [UIImageView new];
// configure your imageView..
[headerView addSubview:fixedImageView];
// configure labels as you want and add them to headerView as subviews
// Now set `UITableView` headerView
self.tableView.tableHeaderView = headerView;
If you want to use AutoLayout for your tableHeaderView, I suggest you to take a look at this question
Dynamic scrollView
Another way to do this is to to create an UIScrollView, put everything inside, and let it scroll. The downside of this method is that if you are using floating section headers for your UITableView, they will not float due to the fact that the tableView is going to stay fixed, while the parent scrollView is going to scroll.
On the other side, this approach is more AutoLayout friendly due to the fact you can use constraints easily.
To do so, you start adding an UIScrollView to your view, and placing all your other views inside it.
Be sure to add a Vertical Spacing constraint between the first view inside your scrollView (I suppose the UIImageView) and the scrollView top, and between the last view (I suppose the UITableView) and the scrollView bottom, to avoid an ambiguous content size.
You should have something like that (I omitted the labels for the sake of brevity):
Note that every view is inside a parent UIScrollView
After that, add an Height constraint to the tableView, and add an IBOutlet to your view controller subclass, i.e. like this:
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *tableViewHeightConstraint;
Now you only need to configure this constraint to reflect the tableView natural height, given by its rows, etc. To do so, you simply calculate the height in this way:
// Resize TableView
CGFloat height = self.tableView.contentSize.height;
self.tableViewHeightConstraint.constant = height;
Now the tableView will resize, and due to its constraints it will adapt the parent scrollView contentSize.
Just be sure to refresh this height constraint anytime you reload the UITableView dataSource.

Resources