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.
Related
I have a UIScrollView for which I have a UIView which is the subview of the scroll view , the UIView has a lot of other subviews and I am getting the height for it dynamically after adding the subviews , this is my piece of code to add the view to scroll view
CGRect frameOfView = CGRectMake(0, 0,Get_Bounds.width, globalYPosition);
self.parentProductDetailView = [[UIView alloc]initWithFrame:frameOfView];
I am first initialising the view this way and then after adding all subviews I am doing this,
frameOfView.size.height = globalYPosition;
[self.parentProductDetailView layoutSubviews];
self.parentProductDetailView.frame = frameOfView;
[self.productDetailScrollView addSubview:self.parentProductDetailView];
self.productDetailScrollView.contentSize = CGSizeMake(0, self.parentProductDetailView.frame.size.height *1);
But my scrollview does not scroll properly it either sticks to top or bottom.
Here globalYPosition is the sum of height of all subviews added to parentProductDetailView
The procedure you used seems correct. No matter the subviews your scroll view should scroll properly by simply using a larger content size then its frame size.
The scroll view may stick, snap to some points if paging is enabled which is what is happening in your case. If the content view is larger then 1.5th of the frame size then the scroll view will snap to top/bottom or left/right. If it is smaller then it will only snap to starting position.
This may be very useful for situations like having a side menu that takes a part of a screen but in your case you should simply disable the paging and scrolling should work fine.
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) {
}
}
Searched a lot on stack overflow, but didn't find any solution that works for us.
What we have are a couple of Views and UILabels and UIButtons in UIScrollView as below format. On Click of button we are hiding couple of views and labels and trying to recalculate UIScollView height.
UIScrollView
-->UIView
-->UIView2
-->UIView3
-->UILabel1
-->UILabel2 ( Please note these labels are not inside UIView, they are directly added to scrollview. Is this correct approach or they should be added inside a UIView?)
-->UITextField (Directly added to scrollview)
-->UITextField1 (Directly added to scrollview)
-->UIButton ( On Click of Button above textfields and labels are hidden or shown based on business logic)
When we try to reset size of UIScrollview on UIButton click it doesn't calculate height correctly. Tried below solution shared by lot of answers in stack overflow
Is the problem with labels and buttons added directly to UIScrollView?
Is there better way to set height of UIScrollview correctly?
We don't want to use AutoConstraint
CGRect contentRect = CGRectZero;for (UIView *view in uiScrollViewObj.subviews) {
contentRect = CGRectUnion(contentRect, view.frame);
}
uiScrollViewObj.contentSize = contentRect.size;
No it's not, in fact UILabels and UIButtons are UIViews.
I think you are confusing two concepts. The UIScrollView height is the height of the viewport (the visible part of the scrollview). What you want to change is the contentSize height that is the height of the whole content which you want to scroll through (I don't know if I have explain myself clear).
If the structure is the way you said it, so the UIButton is the closest element to the button, you should move its frame and place it upper, otherwise the contentSize is always gonna be the same.
Besides that, your code is iterating through all the views of the scrollview and those are not only the ones you added but also the ones that Apple inserted.
The best way to calculate the contentsize dynamically is to sum scrollview subviews y position and their height. Something like this should work:
CGFloat viewY, maxY=0;
for (UIView *view in uiScrollViewObj.subviews) {
if (view.hidden) continue;
viewY = view.frame.origin.y + view.frame.size.height;
maxY = (viewY > maxY) ? viewY : maxY;
}
[uiScrollViewObj setContentSize:CGSizeMake(uiScrollViewObj.frame.size.width, maxY)];
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];
}
So a little explanations of what my view is doing before the problem, the page loads a bunch of buttons that are clickable into the contentView which is a subView of my scrollView.
i got a UIViewController, inside i have my
UIScrollView scrollView to handle the scrolling and zooming
UIView contentView which i add all the UIButtons to.
Alright i'll try to only put the code which i believe might need to be changed.
in viewDidLoad
scrollView.contentSize = CGSizeMake(320, (20+totalRows*OFFSET_Y) );
[scrollView setMaximumZoomScale:4];
[scrollView setMinimumZoomScale:1];
[scrollView setDelegate:self];
[contentView setFrame:CGRectMake(0, 0, 320, (20+totalRows*OFFSET_Y) )];
[self.scrollView addSubview:contentView];
Doing some calculation to see how big i need to content size to be to fit all the buttons, then i add the contentView as subView to my scrollView.
I then add all the UIButtons as subview of my contentView
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return [self contentView];
}
Got my delegate method for zooming returning the contentView.
Ok so everything is scrollable and zoomable like it should be..all my UIButtons are still clickable and works how it should be.
The problem is after i zoom in/out when i scroll all the way to the bottom of my scrollView it's being cut off from the bottom, so the last row of buttons are being cut in half. even when i rezoom to 1:1 it's still cut off.
I've got a NavigationController in the app which is 44 pixels, not sure if that's screwing something up somehow.
I was checking the contentSize of the scrollView and contentView and before any zooming is done, the Height of my scrollView is 44 pixels bigger than the contentView, but after any zooming the ratio is 1:1 and that seems to be the problem.
I'm not changing the size anywhere in the code though.
Any help is appreciated!
Thanks
Like i thought before I added this piece of code
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale (float)scale
{
self.scrollView.contentSize = CGSizeMake(self.scrollView.contentSize.width, self.scrollView.contentSize.height + (44 * scale));
}
And now Zooming doesn't cut anything off and seems to be working correctly.
I still don't believe this is what I should have to do but I guess it works for now.
Still hoping someone has a better answer!
After playing more with my app I realized that the zooming was never the problem to begin with. The actual problem was with my UIView *contentView. After changing the background colour of my scrollView and my contentView (to 2 very diff colours) I noticed that my contentView wasn't long enough to cover all of the buttons.
So at first load the scrollView was big enough to see everything but once you zoom and it takes the size of the contentView it wasn't being adjusted properly!
All that to say, it finally works how it should!..haha no replies but hopefully someone might find this useful! Best tip was to change the background colours.
Good Day,
I realize very late to the game, but wanted to updated what i found on this, should anyone else come across this issue.
All did was set BOTH the UIImageView and the UIScrollView to "Aspect Fit" and this fixed the issue for me. This may be an Xcode 7 feature, but it works.