I'm trying to present local html5 content in a set of 5 UIWebViews.
The idea is that the user would swipe to go to the 4 direction so I got 5 UIWebViews with bouncing disabled :
leftWebView.scrollView.bounces = NO;
middleWebView.scrollView.bounces = NO;
rightWebView.scrollView.bounces = NO;
upWebView.scrollView.bounces = NO;
downWebView.scrollView.bounces = NO;
We would assume that no scroll is possible in the webviews because the html pages displayed are smaller than the iPad Screen.
These web views are loaded so that the transition animated just by moving their center to be smooth.
So is there a way to change the swipe action performed by the gesture recognizers in the UIWebView?
I tried to put 4 SwipeGesturesRecognizers (one per direction) directly on the webViews but for some reason the gestures recognizer loose track of their WebViews when I swap references with :
UIWebView *tmp = leftWebView;
leftWebView = middleWebView;
middleWebView = rightWebView;
rightWebView = tmp;
I tried to use 4 SwipeGesturesRecognizers (one per direction) on a UIView on top of the window, but the taps are now blocked by this view, so that the user is not able anymore to interact with clickable elements.
You could add a custom UISwipeGestureRecognizer to your webView .. and disable the scroll in the webView like this
UIScrollView *scroll = [[self.webView subviews] lastObject];
if([scroll isKindOfClass:[UIScrollView class]])
{
scroll = (UIScrollView*)scroll;
[scroll setScrollEnabled:NO];
}
Related
I have a UIScrollView that is 320 by 100 (width and height) and UIPageControl with 4 pages. My App has 4 icons at the top in the scroll view but only displays one of the icons with portions of the other icons on the edges (so the user can know that they can scroll). The user can either tap on the pagecontrol to have it change left or right and it correspondingly changes the icons in the scroll view. On the same point, the user can scroll the scroll view and I want it to center on the icon they are scrolling towards and the page control to change. My issue is that whenever I scroll in the IOS simulator, the icons are offset weirdly and display as such regardless of how much I change the parameters I am moving to. It always skips the second icon.
Here is the code for the ScrollViewDidScroll
`- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
float roundedValue = floor(_ScrollView.contentOffset.x / 160);//320
NSLog(#"%f",roundedValue);
self.pageControl.currentPage = roundedValue;
[_dataTable reloadData];
}`
And here is the code for my pageAction
UIPageControl *pageCon = (UIPageControl *)sender;
int pageMoved = pageCon.currentPage;
CGRect movedTo = CGRectMake((pageMoved*190), 0, 320, 100);//160
[_ScrollView scrollRectToVisible:movedTo animated:YES];
All the math works out, im just not sure why its offsetting the images and skipping the second icon.
I am having an horizontal scrollview in an UIViewController, where i have many images in small sizes. I am keeping the images in scrollview because the images are more, so user can scroll horizontally and choose images. But, the problem is, i have to select an image and drag and drop to that UIViewController view. But, since the images are in scrollview, drag and drop images into UIViewcontroller's view is not working, not detecting the touch events too.
Please NOTE: If i don't have scrollview but just keeping the images also into UIViewcontroller's view itself, drag and drop the images on the same screen, is working very well.
How can I resolve this when I need to have scrollview and drag and drop images, any advice/help please?
Hi Getsy,
I am not going to provide you code directly but give idea how to manage this.
You can manage this way, When you get touch on your object in scrollView at that time or when you move that object by draging at that time disable scroll by myScroll.scrollEnabled = NO;
Then When on endTouch you can enable Scroll by myScroll.scrollEnabled = YES; So by this you can manage you object moving in scroll hope you got logic.
Here is the demo code : Drag and Drop with ScrollView. which has same logic of Disabling scroll view on touchesMoved: and Enabling scroll view on touchesEnded:.
I did implement that behaviour before without any subclassing.
I used canCancelContentTouches = NO of the UIScrollView to make sure the subviews handle there touches on their own. If a subview (in your case an image) was touched, i moved the view out of the scrollview onto the superview and started tracking it's dragging. (You have to calculate the correct coordinates within the new superview, so it stays in place).
After dragging finishes, i checked if the target area was reached, otherwise I moved it back into the scrollview. If that's not detailed enough I could post some code.
Well here is my example code: Github: JDDroppableView
Getsy,
Try the code for drag and drop the objects :
-(void)dragAndDropWithGesture {
UILongPressGestureRecognizer *downwardGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(dragGestureChanged:)];
[scrollViewAlfabeto addGestureRecognizer:downwardGesture];
for (UIGestureRecognizer *gestureRecognizer in myscrollView.gestureRecognizers)
{
[gestureRecognizer requireGestureRecognizerToFail:downwardGesture];
}
}
- (void) dragGestureChanged:(UIPanGestureRecognizer*)gesture
{
CGPoint point = [gesture locationInView:scrollViewAlfabeto];
if (gesture.state == UIGestureRecognizerStateBegan)
{
[imageViewToMove removeFromSuperview];
[self.view addSubview:imageViewToMove];
UIView *draggedView = [myscrollView hitTest:point withEvent:nil];
if ([draggedView isKindOfClass:[UIImageView class]])
{
imageViewToMove = (UIImageView*)draggedView;
}
}
else if (gesture.state == UIGestureRecognizerStateChanged)
{
imageToMove.center = point;
}
else if (gesture.state == UIGestureRecognizerStateEnded ||
gesture.state == UIGestureRecognizerStateCancelled ||
gesture.state == UIGestureRecognizerStateFailed)
{
// Determine if dragged view is in an OK drop zone
// If so, then do the drop action, if not, return it to original location
NSLog(#"point.x final:%f", point.x);
NSLog(#"point.y final:%f", point.y);
if (CGRectContainsPoint(goal.frame, point)){
imageToMove.frame = CGRectMake(167, 159, 100, 100);
}
else{
[imageToMove removeFromSuperview];
[myscrollView addSubview:imageToMove];
[imageToMove setFrame:CGRectMake(12, 38, 100, 100)];
imageToMove = nil;
}
}
}
May this code will help you out.
For a similar problem, I made UIScrollView subclass like the following: PoliteScrollView passes touch messages to it's subviews when it determines that they are being dragged.
#interface PoliteScrollView : UIScrollView
// number of pixels perpendicular to the scroll views orientation to make a drag start counting as a subview drag
// defaults to 1/10 of the scroll view's width or height, whichever is smaller
#property(nonatomic,assign) CGFloat subviewDraggingThreshold;
// yes when a subview is being dragged
#property(nonatomic,assign) BOOL isDraggingSubview;
// the subview being dragged
#property(nonatomic,strong) UIView *draggingSubview;
#end
#protocol PoliteScrollViewDelegate <NSObject>
#optional
- (void)scrollView:(PoliteScrollView *)scrollView subviewTouchesBegan:(NSSet *)touches;
- (void)scrollView:(PoliteScrollView *)scrollView subviewTouchesMoved:(NSSet *)touches;
- (void)scrollView:(PoliteScrollView *)scrollView subviewTouchesEnded:(NSSet *)touches;
#end
The key design idea is that dragging in a scroll view is ambiguous. Is the user scrolling or dragging a subview? PoliteScroll view handles this by providing two things: (1) a notion of orientation (horizontal if it's longer than it is wide, vertical otherwise), and (2) a threshold distance for what constitutes a drag in the direction perpendicular to it's orientation. (defaults to 1/10 the width or height).
I pasted this and several other files are in a paste bin, containing the following:
PoliteScrollView .h and .m
DraggableImageView.h and .m - that changes it's position when it gets touch messages.
ViewController.m - that demonstrates thetwo in combination.
To combine these in a project, paste the paste bin into files appropriately named, add a storyboard with a PoliteScrollView (be sure to set it's delegate), add in some images (the ViewController tries to add puppy0.jpeg to puppy4.jpeg.
I created an example which illustrates how to drag and drop between two or more views:
http://www.ancientprogramming.com/2012/04/05/drag-and-drop-between-multiple-uiviews-in-ios/
I found it a good idea to register the gesture recognizer to a different view than the actual views being dragged. This will make sure the gestures continue even though the dragged view changes its 'parent' view.
Maybe it can give some inspiration
I load an HTML form in my UIWebView and it so happens that my UIWebView starts from the middle of the view and extends. I have to lock this webView from scrolling and put it on top of a scrollView to allow scrolling. The webView shouldn't scroll internally. I have tried this
[[webView.subviews objectAtIndex:0] setScrollEnabled:NO];
but I am not able to stop the webView from scrolling internally when I load a form in it that has textFields clicking on which brings up the keyboard. When I load plaintext, I am able to get the desired behavior. I want to stop the webView from autoscrolling and handle the scrolling myself using the scrollView that lay beneath the webView. It might not make sense to most of you that I am reinventing the wheel but the requirement is such.
Can anybody suggest what to do?
You can try,
for (id subview in webView.subviews)
if ([[subview class] isSubclassOfClass: [UIScrollView class]])
if([subview respondsToSelector:#selector(setScrollingEnabled:)]) [subview performSelector:#selector(setScrollingEnabled:) withObject:NO];
or you need to stop bouncing of the webview you can try this.
for (id subview in webView.subviews)
if ([[subview class] isSubclassOfClass: [UIScrollView class]])
((UIScrollView *)subview).bounces = NO;
Hope this helps.
Try running this after the webview has loaded (i.e. in the proper delegate method):
[webView stringByEvaluatingJavaScriptFromString:#"document.getElementsByTagName('body')[0].style.overflow='hidden'"]
If you have access to the HTML, you could also just set the correct style on the body element:
body { overflow: hidden; }
If you do either of these, you need to make sure that you make the UIWebView tall enough to display everything. You can get the height by running this (also after the webview has loaded):
CGFloat height = [webView stringByEvaluatingJavaScriptFromString:#"document.body.scrollHeight"]
I'm working on a browser app, and I have an address bar on top the UIWebView. On MobileSafari if you scroll down, the address bar starts to move to the top, out of the screen, and the UIWebView doesn't scroll. Only when the address bar disappears completely, it starts to scroll. I would like to have this effect in my app as well.
What's the best way to implement this?
Thanks
The only way to implement this requires iOS 5.
In iOS 5, UIWebView has an UIScrollView subview.
And use the following code:
Set a area for the address bar:
[[myWebView scrollView] setContentInset:UIEdgeInsetsMake(64, 0, 0, 0)];
Move the address bar using the scrollview delegate:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
if(scrollView.contentOffset.y>=-64&&scrollView.contentOffset.y<30)
{
topBar.frame=CGRectMake(0,-44-scrollView.contentOffset.y, 320, 44);
}
else if(scrollView.contentOffset.y<-64)
topBar.frame=CGRectMake(0,20, 320, 44);//Lock the position
}
There is a way, but I am not sure if it is a bit too hacky. First search for the scrollview within the webview, then alter the contentInset and finally add the searchbar(for example) to the scrollview. The following code is just an example, I did not set any frames correctly and 40 is just a made up height for the searchbar. I am not sure if this will work in every iOS Version.
UIWebView * myWebView = [[UIWebView alloc] init]
UISearchBar * mySearchBar = [[UISearchBar alloc] init];
for (NSObject * aSubView in [myWebView subviews]) {
if ([aSubView isKindOfClass:[UIScrollView class]]) {
UIScrollView * theScrollView = (UIScrollView *)aSubView;
theScrollView.contentInset = UIEdgeInsetsMake(40, 0, 0, 0);
[theScrollView addSubview:mySearchBar];
}
}
PeakJi's solution works but is a bit laggy. A better solution would be adding an observer to the UIScrollView's content offset, something like
[scrollview addObserver:self forKeyPath:#"contentOffset"
options:NSKeyValueObservingOptionNew context:nil];
You can find more document on NSKeyValueObserving protocol at
https://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Protocols/NSKeyValueObserving_Protocol/Reference/Reference.html
Come to think of it, it is simply a scrolling view with an address bar stuck on the top, and both the web view and the bar always move together. Now, lets say you create a scroll view and add two subviews, the address bar and the web view (one below the other). It is to be noted that the height of the web view is determined and fixed after the page has been loaded (in webViewDidFinishLoad:).
Hence, it is simply a scrolling view whose contentSize is equal to the height of the bar + the height of the web view. Now, by default the web view allows scrolling, as it has a scroll view as a subview. As only the outer scroll view should be scrolling, it is required that the web view's scrolling be turned off. For that, fetch the first subview (that's the scroll view) and disable its scrolling using:
(UIScrollView*)[myWebView.subviews objectAtIndex:0].scrollEnabled = NO;
I've used Interface Builder to drop a UIScrollView into the top of a UITableView.
(To do some horizontal scrolling.)
In code, I now wish to selectively show/hide that UIScrollView. I've connected it in IB, and then execute various combinations of code... but the area never disappears.
self.scrView.hidden = TRUE;
or:
CGRect aFrame = self.scrView.frame;
aFrame.size.height = 0;
[self.scrView setFrame:aFrame];
or:
[self.scrView setFrame:CGRectZero];
[self.scrView setContentSize:CGSizeZero];
or even the suggested:
[self.scrView removeFromSuperview];
Any way to make that thing disappear... including the area that it used to be in?
You can remove it from its parent view like this:
[self.scrView removeFromSuperView];