Is there a callback offered by UIWebView that is called when scrolling occurs, and if so, how can I get the current content offset?
Thanks.
You can using this property available in ios 5.0:
#property(nonatomic, readonly, retain) UIScrollView *scrollView
Or prior to iOS 5.0:
NSArray *subViews = [NSArray arrayWithArray:[myWebview subviews]];
UIScrollView *webScroller = (UIScrollView *)[subViews objectAtIndex:0];
You can then implement the UIScrollViewProtocol and do something like this:
UIScrollView *webScrollView = myWebView.scrollView;
webScrollView.delegate = self;
//implement method from delegate..
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
//Scrolled
}
To get the contentOffset all you have to do is:
CGPoint offSet = webScrollView.contentOffset;
Related
Just came across a bug in MapKit, wanted to see what the community is experiencing. When adding a MKUserTrackingBarButtonItem to a UIToolBar, I'm seeing the map is not releasing from memory when switching to another viewController (though I see the dealloc is firing).
Can anyone confirm they are seeing this behavior? My testing shows the map releases properly if I do not add MKUserTrackingBarButtonItem. Using iOS7, testing with Instruments/Leaks.
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
MKUserTrackingBarButtonItem *userTrackingBarButtonItem = [[MKUserTrackingBarButtonItem alloc] initWithMapView:self.mapView];
[userTrackingBarButtonItem setAction:#selector(track:)];
UIBarButtonItem *flexibleSpaceBarButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
[self setToolbarItems:[NSArray arrayWithObjects:flexibleSpaceBarButton, userTrackingBarButtonItem, flexibleSpaceBarButton, nil] animated:YES];
[self.navigationController setToolbarHidden:NO animated:NO];
}
MKUserTrackingBarButtonItem and the MKMapView each hold strong references to each other, resulting in a circular retain. This appears to be a bug in MapKit itself, and it's still present in iOS 7.1.
A solution is to add a dealloc to your view controller that contains the MapView:
-(void)dealloc
{
userTrackingBarButtonItem.mapView = nil; // Circular reference bug workaround
}
I try to open wiki mobile version webpage by a UIWebView within a UIPopoverController. the problem is, not matter how I set my contentSizeForViewInPopover, or just UIWebView frame, or simply set UIWebView.scalesPageToFit = YES. the Wiki mobile version page content size seem to larger than my UIWebView. But if I use it on iPhone, there's no such problem. here's my code for popover controller:
//create a UIWebView UIViewController first
WikiViewController *addView = [[WikiViewController alloc] init];
addView.contentSizeForViewInPopover = CGSizeMake(320.0, 480.0f);
//then create my UIPopoverController
popover = [[UIPopoverController alloc] initWithContentViewController:addView];
popover.delegate = self;
[addView release];
//then get the popover rect
CGPoint pointforPop = [self.mapView convertCoordinate:selectAnnotationCord
toPointToView:self.mapView];
CGRect askRect = CGRectMake((int)pointforPop.x, (int)pointforPop.y+10, 1.0, 1.0);
[popover presentPopoverFromRect:askRect
inView:self.mapView
permittedArrowDirections:UIPopoverArrowDirectionRight animated:YES];
[self.mapView deselectAnnotation:annotation animated:YES];
and this is my code on creating UIWebView:
- (void)viewDidLoad
{
wikiWebView = [[UIWebView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 480.0f)];
wikiWebView.scalesPageToFit = YES;
//or No, doesn't matter, it all get larger than this
wikiWebView.delegate = self;
self.view = wikiWebView;
}
all code seem to be typical...
I wonder if anyone can shed me some light, thank you so much.
This is an enhanced version of auco answer, where if the viewport meta tag is not present it will be added:
- (void)webViewDidFinishLoad:(UIWebView*)webView
{
int webviewWidth = (NSUInteger)webView.frame.size.width;
if (!webView.loading) {
NSString *jsCmd = [NSString stringWithFormat:#"try {var viewport = document.querySelector('meta[name=viewport]');if (viewport != null) {viewport.setAttribute('content','width=%ipx, initial-scale=1.0, user-scalable=1');} else {var viewPortTag=document.createElement('meta');viewPortTag.id='viewport';viewPortTag.name = 'viewport';viewPortTag.content = 'width=%ipx, initial-scale=1.0, user-scalable=1';document.getElementsByTagName('head')[0].appendChild(viewPortTag);}} catch (e) {/*alert(e);*/}", webviewWidth, webviewWidth];
[webView stringByEvaluatingJavaScriptFromString:jsCmd];
}
}
Here is the Javascript pretty formatted code we are injecting in the WebView with a width of 320px
try {
var viewport = document.querySelector('meta[name=viewport]');
if (viewport != null) {
viewport.setAttribute('content',
'width=320px, initial-scale=1.0, user-scalable=1');
} else {
var viewPortTag = document.createElement('meta');
viewPortTag.id = 'viewport';
viewPortTag.name = 'viewport';
viewPortTag.content = 'width=320px,initial-scale=1.0, user-scalable=1';
document.getElementsByTagName('head')[0].appendChild(viewPortTag);
}
} catch (e) {
/*alert(e);*/
}
you can remove the try/catch if you want.
oh, i found in another QA that sometimes if html got a line "width=device-width", and you load a webview from popover controller, this popover controller will automatically send out device-width, not the view width you specified, and make your view ugly and funky. in that post it is a jQuery issue, and it solved with a jQuery way. In my problem, it is just a html issue in wiki mobile version. so I try another way, but similar.
I simple add a code in webViewdidload delegate method, first get URL html into a NSString, then use NSString instance method to search for "device-width" in loaded html, and replace it with my view width to make it a new NSString, then load this page with this new NSString. that's it.
- (void) webViewDidFinishLoad:(UIWebView *)webView
{
if (!alreadyReload)
{
NSString *webHTML = [NSString stringWithContentsOfURL:webView.request.URL encoding:NSUTF8StringEncoding error:NULL];
NSRange range = [webHTML rangeOfString:#"device-width"];
if ((range.location!=NSNotFound)&&(range.length != 0))
{
webHTML = [webHTML stringByReplacingOccurrencesOfString:#"device-width" withString:#"whatever width you need" options:0 range:range];
[webView loadHTMLString:webHTML baseURL:wikiWebView.request.URL];
alreadyReload = YES;
}
}
}
something like this.
by the way, since I only use this on wiki mobile version, the html is simple and this kind of compare and replace is pretty easy. if you wanna use it in a more general case, you might use other way.
It would be much more efficient to manipulate the device-width via JavaScript rather than altering the html after it has fully loaded and then reloading the full page with modified html again.
This should work (and also consider if it's even necessary to change the viewport width):
- (void)webViewDidFinishLoad:(UIWebView *)aWebView {
if(aWebView.frame.size.width < aWebView.window.frame.size.width) {
// width=device-width results in a wrong viewport dimension for webpages displayed in a popover
NSString *jsCmd = #"var viewport = document.querySelector('meta[name=viewport]');";
jsCmd = [jsCmd stringByAppendingFormat:#"viewport.setAttribute('content', 'width=%i, initial-scale=1.0, user-scalable=1');", (NSUInteger)aWebView.frame.size.width];
[aWebView stringByEvaluatingJavaScriptFromString:jsCmd];
}
// stop network indicator
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
I've spent many hours trying to figure how to do this:
Having a placemark/annotation in the centerCoordinate of your mapView, when you scroll the map, the placemark should always stays in the center.
I've seen another app doing this too!
Found my question in How to add annotation on center of map view in iPhone?
There's the answer :
If you want to use an actual annotation instead of just a regular view positioned above the center of the map view, you can:
use an annotation class with a settable coordinate property (pre-defined MKPointAnnotation class eg). This avoids having to remove and add the annotation when the center changes.
create the annotation in viewDidLoad
keep a reference to it in a property, say centerAnnotation
update its coordinate (and title, etc) in the map view's regionDidChangeAnimated delegate method (make sure map view's delegate property is set)
Example:
#interface SomeViewController : UIViewController <MKMapViewDelegate> {
MKPointAnnotation *centerAnnotation;
}
#property (nonatomic, retain) MKPointAnnotation *centerAnnotation;
#end
#implementation SomeViewController
#synthesize centerAnnotation;
- (void)viewDidLoad {
[super viewDidLoad];
MKPointAnnotation *pa = [[MKPointAnnotation alloc] init];
pa.coordinate = mapView.centerCoordinate;
pa.title = #"Map Center";
pa.subtitle = [NSString stringWithFormat:#"%f, %f", pa.coordinate.latitude, pa.coordinate.longitude];
[mapView addAnnotation:pa];
self.centerAnnotation = pa;
[pa release];
}
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
centerAnnotation.coordinate = mapView.centerCoordinate;
centerAnnotation.subtitle = [NSString stringWithFormat:#"%f, %f", centerAnnotation.coordinate.latitude, centerAnnotation.coordinate.longitude];
}
- (void)dealloc {
[centerAnnotation release];
[super dealloc];
}
#end
Now this will move the annotation but not smoothly. If you need the annotation to move more smoothly, you can add a UIPanGestureRecognizer and UIPinchGestureRecognizer to the map view and also update the annotation in the gesture handler:
// (Also add UIGestureRecognizerDelegate to the interface.)
// In viewDidLoad:
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handleGesture:)];
panGesture.delegate = self;
[mapView addGestureRecognizer:panGesture];
[panGesture release];
UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(handleGesture:)];
pinchGesture.delegate = self;
[mapView addGestureRecognizer:pinchGesture];
[pinchGesture release];
- (void)handleGesture:(UIGestureRecognizer *)gestureRecognizer
{
centerAnnotation.coordinate = mapView.centerCoordinate;
centerAnnotation.subtitle = [NSString stringWithFormat:#"%f, %f", centerAnnotation.coordinate.latitude, centerAnnotation.coordinate.longitude];
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
//let the map view's and our gesture recognizers work at the same time...
return YES;
}
I have tried hiding a segmented controller just like a button or label can be hidden in XCode. It's intended to be hidden/shown when touching a parent segmented controller above. This Code would work with Buttons or Labels:
mySegmContr.hidden = YES;
But it just won't work for segmented controllers. Can you help me out?
I figured out that you can use a simple UIView in which you put the things you want to hide. The UIView can then be hidden with
myView.hidden = YES;
still I found no way to hide a segmented control directly.
If you create a property for the segment controller you can do more stuff with it like changing it's location, resizing it and want you want hiding it.
In your .h file do this
UISegmentedControl *mySegment;
#property (nonatomic, retain) UISegmentedControl *mySegment;
-(void) createMySegment;
In your .m file do this
#synthesize mySegment;
- (void) createMySegment {
if ([self mySegment] == nil) {
NSArray *buttons = [NSArray arrayWithObjects:#"One", #"Two", #"Three", nil];
UISegmentedControl *segName = [[UISegmentedControl alloc] buttons];
[self setMySegment:segName];
[segName release];
segName.frame = CGRectMake(110, 62, 120, 25);
segName.segmentedControlStyle = UISegmentedControlStyleBar;
segName.momentary = NO;
segName.selectedSegmentIndex = 0;
[segName addTarget:self
action:#selector(pickMethod:)
forControlEvents:UIControlEventValueChanged];
[self.view addSubview:segName];
}
}
NOTE: With "setMySegment" above make sure you use a capital first letter which is M in "mySegment".
Then when you want to hide it use this. Don't for get to dealloc mySegment.
[[self mySegment] setHidden:YES];
Hi Could you please let me know how to change the default colour of a tababar in Xcode i hav already tried this :
(void)viewDidLoad {
[super viewDidLoad];
UIImageView *img = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"UITabBar.png"]];
img.frame = CGRectOffset(img.frame, 0, 1);
[tabBar1 insertSubview:img atIndex:0];
[img release];
but it doesnt work for me so can you please tel me in detail how can i change the colo
I know, this is an old thread, but nonetheless for all of you looking for an answer.
One of the ways to customize the look of UITabBar is to override drawRect: method with use of categories. Choose to create new file in your Xcode project, choose Objective-C category, then type UITabBar for Category On textfield. Next, declare drawRect: method in your category .h file and implement it in category .m file like this:
- (void)drawRect:(CGRect)rect {
UIImage *img = [UIImage imageNamed: #"tabbarBackground"];
[img drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
}
This will change the looks of all UITabBar instances in your app.
Hope this helps.