I have used two scrollviews,one for horizontal and second for vertical scrolling. I am using scrollViewWillBeginDragging delegate method. When I scroll in horizontal direction, vertical scrollview does not show imageview.
Help me.
Whether or not it is a good idea to nest scrollviews is a different question, but generally you have two scrollviews and check which one is dragging. In your scrollViewWillBeginDragging to the following:
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
if (scrollView == horizontalScrollView) {
// handle horizontal scrolling
else if (scrollView == verticalScrollView) {
// handle vertical scrolling
}
}
Related
Anyone has an idea how to control two scroll views while one in on the top of the other. One scrolls, the other one scrolls too. Same with zoom, gesture recognisers, etc ... Kinda like passing replica of the touches received by the first view onto the the one underneath. Subclass of the top scroll view has got a weak reference to the "dependant" scroll view underneath. Very important is to get the delegate methods working for both scrollviews as there is a lot of logic in these ...
use the scrollView Delegate methood
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if([scrollView isEqual:scrollViewA]) {
CGPoint offset = scrollViewB.contentOffset;
offset.y = scrollViewA.contentOffset.y;
[scrollViewB setContentOffset:offset];
} else {
CGPoint offset = scrollViewA.contentOffset;
offset.y = scrollViewB.contentOffset.y;
[scrollViewA setContentOffset:offset];
}
}
or simply in the same method for both horizontal an vertical scrolling
if([scrollView isEqual:scrollViewA]) {
scrollViewB.contentOffset = scrollViewA.contentOffset;
}
and viceVersa
I'm having difficulty though. As soon as i make the content size of the outer scrollview be bigger than it's frame, the image that i'm zooming on it's subview (also a scrollview) is behaving weirdly.
Anybody have any ideas on how to do this? I'm making my own because i have problems with various ones on the internet and i also want it to support video, so i'm making it myself.
FOR ZOOMING inner scrollview you have to right this method.
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView{
if(scrollView!=Innerscr){
UIImageView *v=(UIImageView*)[scrollView viewWithTag:kTagImageViewInScrollView];
return v;
} else {
return nil;
}
}
and for scrolling images you have to write code in under method
-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
if(scrollView==Outerscr){
}
}
I'm using UIScrollView's canceling touch ability with canCancelContentTouches.
However, I 'd like the uiscrollview to attempt to cancel touch when it detected horizontal dragging(not vertical).
(Hope solution would be available under < iOS 3.13)
Thank you
Implement the UIScrollViewDelegate and then use something like this:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
[scrollView setContentOffset: CGPointMake(0, scrollView.contentOffset.y)];
}
Another way would be having a UIScrollView which is smaller or equal to the size of its parent view and with a disabled "Always bounce horizontal".
The safest and most successful method I've found to constrain the movement of a scroll view is to subclass UIScrollView and override setContentOffset:animated: and setContentOffset: methods (code below).
The advantage of overriding these methods is that it directly alters the requested contentOffset before any of the UIKit code starts to act on it, avoiding any of the side effects that can occur when modifying the contentOffset in scrollViewDidScroll: or other UIScrollViewDelegate methods.
- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated {
// restrict movement to horizontal only
CGPoint newOffset = CGPointMake(contentOffset.x, 0);
[super setContentOffset:newOffset animated:animated];
}
- (void)setContentOffset:(CGPoint)contentOffset {
// restrict movement to horizontal only
CGPoint newOffset = CGPointMake(contentOffset.x, 0);
[super setContentOffset:newOffset];
}
i guess i would use the method scrollViewWillBeginDragging
found in the UIScrollViewDelegate
and inside i could control if user is going horizontally or not...
scrollViewWillBeginDragging:
Tells the delegate when the scroll view is about to start scrolling the content.
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
Parameters
scrollView
The scroll-view object that is about to scroll the content view.
Discussion
The delegate might not receive this message until dragging has occurred over a small distance.
Availability
Available in iOS 2.0 and later.
Setup: I have a UITableView, each UITableViewCell has a UIScrollView. What I am trying to do is to get all of the UIScrollViews to scroll together, such that when you scroll one of them all of the UIScrollViews appear to scroll simultaneously.
What I've done is subclass UITableView so that it has an array of all of the UIScrollViews within its table cells. I then forwarded TouchesBegan, TouchesMoved, TouchesCancelled, and TouchesEnded from the UITableView to all of the UIScrollViews in the array.
This doesn't appear to work. The UIScrollViews do not scroll! The only way I've managed to get this to work is to call the setContentOffset: method on the scrollviews. However, this is a pretty bad solution since it doesn't give you the swiping and deceleration features of the UIScrollView.
Any ideas on why my touches methods aren't getting to the UIScrollViews? Or a better way to implement this?
Ok, got it working. Thanks for the tips Ricki!
2 things to add to Ricki's solution, if you want to avoid an infinite loop, you have to check to see whether the scrollView's tracking or dragged properties are set. This will insure that only the ScrollView that is actually being dragged is calling the delegate.
- (void)scrollViewDidScroll:(UIScrollView *) theScrollView {
if (theScrollView.dragging || theScrollView.tracking)
[self.delegate scrolling:[theScrollView contentOffSet]];
}
Also, in the scrolling method of the delegate, I set animated to NO, this got rid of the delay between the initial swipe and the other scrollviews getting updated.
I did something "similar" where I had 4 scrollViews incased inside a parent view.
I placed a scrollView inside a UIView, this UIView was passed a delegate from its parentView, that was the view who kept track of all the scrollViews. The UIView containing a scrollVIew implemented the UIScrollViewDelegate and this method;
- (void)scrollViewDidScroll:(UIScrollView *) theScrollView {
[self.delegate scrolling:[self.scrollView contentOffSet]];
}
Now the parent view did this on all the scrollViews:
- (void) scrolling:(CGFloat) offset {
for(UIScrollView *s in self) {
[s setContentOffset:offset animated:YES];
}
}
It is of course a bit of a strain on the CPU, but scrolling several views will be that under any circumstances :/
Hope this was something in the direction of what you needed, and that it made any sense.
Added:
I took me 8 different paths and a lot of mass chaos before I made it work. I dropped the touchedBegan approach early, there is just no way to write something that comes close to Apples swipe, flick, scroll algorithms.
I don't know if the tableview and scrollview will "steal" each others touch events, but as I can read from your description you made that part work.
A follow up idea to ease the CPU usage. add each scrollview to a cell, set its tag=14, now when scrolling asked for all visible cells only, ask for viewWithTag=14, set the contentOffset on this. Save the content offset globally so you can assign it to cells being scrolled onto the screen in cellForRowAtIndexPath.
So set the offSet to a global property, in cellForRowAtIndexPath find the view with tag = 14, set its offset. This way you don't even need a reference to the scrollViews only the delegate.
If you have differently sized UIScrollViews and are using paging, this works great:
- (void)scrollViewDidEndDecelerating:(UIScrollView *)_scrollView {
#pragma unused(_scrollView)
categoryPageControlIsChangingPage = NO;
for (UIImageView *iv in [categoryScrollView subviews]) {
iv.alpha = (iv.tag != categoryPageControl.currentPage+1)?0.5f:1.0f;
ILogPlus(#"%i %i", iv.tag, categoryPageControl.currentPage+1);
}
[self scrolling:_scrollView];
}
- (void)scrolling:(UIScrollView *)sv {
CGFloat offsetX = sv.contentOffset.x;
CGFloat ratio = offsetX/sv.contentSize.width;
if ([sv isEqual:categoryScrollView]) {
[categoryScrollViewLarge setContentOffset:CGPointMake(ratio*categoryScrollViewLarge.contentSize.width, 0) animated:YES];
}else {
[categoryScrollView setContentOffset:CGPointMake(ratio*categoryScrollView.contentSize.width, 0) animated:YES];
}
}
I have a UIScrollView with nested UIImageViews. Each imageview can zoom, but when I try to scroll the inner scrollview while zoomed on the image, the outer scrollview picks it up and switches imageviews.
How can I prevent this from happening so that the outer scrollview only scrolls when the inner is not zoomed?
I will post my answer that I got to work to help others out.
One easy way to handle nested UIScrollViews is to share the same delegate. This way, when you detect one UIScrollView scrolling, you can easily share controller logic and apply settings to the other.
to solve this particular problem I was having, All I had to do was keep a BOOL with the current zoom state. Once the app detected that the inner scrollview was zooming,
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView1 {
return [innerScrollViews objectAtIndex:[self indexOfComicViewWithOffset:currentOffset]];
}
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView1 withView:(UIView *)view atScale:(float)scale {
if (scale == 1) {
zooming = NO;
[outerScrollView setScrollEnabled:YES];
} else {
zooming = YES;
[outerScrollView setScrollEnabled:NO];
}
}