""

Archive for February, 2013

UIScrollView Case: Who are they?

Found something of interest, I noticed it during the use of UIScrollView. I was adding multiple UIImageView to scrollview dynamically, at some point later I was iterating through subviews of scrollview and doing some manipulation stuff. I was getting weird results. I printed a log for total count of scrollview’s subviews, found that total count was two more extra than I was supposed to have. I was adding five UIImageView to UIScrollView and total count of subview array was 7. Going more deeper with log prints, found that those two extra views were UIImageView [sighs] I was wondering how was those two extra UIImageView getting added to UIScrollView?

I removed all subviews from UIScrollView before adding my other UIImageView/s. This trick worked just partially. There were no extra two UIImageView and I was not getting any weird result from my processing code. I was thinking if it was some bug with UIScrollView but I was so wrong. I looked more closer to the output and found that two scroll indicators (horizontal and vertical) are missing :P, then it struck me that those two extra UIImageView were actually indicators. I changed my processing/iteration code instead of just plainly removing all subviews. All was well in the end.

Happy Valentines Day 🙂

instagram

Posting photo to instagram from your app could be tricky if some basic things isn’t handled properly. I’l be talking about small things where i made mistake. We cannot post image directly to instagram from app/code. Instead we have to use Documentation Interaction API, UIDocumentInteractionController and URL Schemes to open photo on instagram and share/post from there. Here control also won’t be returned back to your app.

The identifier for UTI is “com.instagram.photo”. Before triggering instagram to open your photo, always check if instagram is available on your device:

NSURL *instagramURL = [NSURL URLWithString:@"instagram://location?id=1"];
if ([[UIApplication sharedApplication] canOpenURL:instagramURL]) {
    //handle
}

Here is the code to open photo on instagram app

-(void) openFileOnInstagram{
	CGRect rect = CGRectMake(0 ,0 , 0, 0);
    UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, self.view.opaque, 0.0);
    [self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIGraphicsEndImageContext();
    NSString  *imagePath = [NSHomeDirectory() stringByAppendingPathComponent:@"InstagramPost.app/no_image.ig"];
    
    NSURL *imageAttachFile = [[NSURL alloc] initWithString:[[NSString alloc] initWithFormat:@"file://%@", imagePath]];
    
    self.dic.UTI = @"com.instagram.photo";
    self.dic = [self setupControllerWithURL:imageAttachFile usingDelegate:self];
    self.dic=[UIDocumentInteractionController interactionControllerWithURL:imageAttachFile];
    [self.dic presentOpenInMenuFromRect: rect inView: self.view animated: YES ];
}
- (UIDocumentInteractionController *) setupControllerWithURL: (NSURL*) fileURL usingDelegate: (id ) interactionDelegate {
    UIDocumentInteractionController *interactionController = [UIDocumentInteractionController interactionControllerWithURL: fileURL];
    interactionController.delegate = interactionDelegate;
    return interactionController;
}

First mistake i did was with getting filepath of my image. My failed attempt was:

NSString  *imagePath = [NSHomeDirectory() stringByAppendingPathComponent:@"Document/no_image.ig"];

So i was assuming that device will have same path structure as my macbook have:

/Users/gaanza/Library/Application Support/iPhone Simulator/6.1/Applications/Documents/no_image.ig

It was my mistake, path in device is like this:

/var/mobile/Applications/40591A2D-B464-49FF-8BA2-64CC4886F7A0/InstagramPost.app/no_image.ig

I simply replaced “Documents” with “InstagramPost.app”, InstagramPost is a name of my application so you have to provide yours with .app extension.

Second mistake i did was with file extension of image. You cannot trigger the instagram app to open if we don’t use “.ig” extension, so save the image in PNG/JPEG format but with .ig extension.

Third mistake i did was with not saving file with .ig extension, i was saving file with png extension but using .ig on code call, so this also won’t work :P, you have to save your file in png/jpeg format but with .ig extension.

Please also check instagram reference page.

Source: http://osx.wdfiles.com/local--files/icon:iruler/iRuler.png

Source: http://osx.wdfiles.com/local–files/icon:iruler/iRuler.png


I was supposed to detect the event when scroller/page of a webview reaches bottom so that i can show one decent translate animation of another small view(like an ad banner). That view will be overlayed definitely and when web page scrolls above center of page then view will hide via translate animation. I came up with a simple solution to detect scroll position. I made an subclass of webview and override onScrollChanged method. Inside this method i am checking scrollY position with the height of content height.

@Override
	public void  onScrollChanged (int l, int t, int oldl, int oldt){
		int height = (int) Math.floor(this.getContentHeight() * this.getScale());
		if(this.getScrollY() >= height){
			Log.i("THE END", "reached");
		}
	}

I could get content height from getContentHeight but i need to keep zoom level of page in mind too so i have multiplied scale factor. Now whenever scrollY reaches height then page end has been reached. It is not so, because we haven’t checked for offset value. That offset value is height of the scroller according to theory if scrollY is the exact Y coordinates of scroller :P. I tried many ways to calculate the height but still i am missing something. I checked the reference documentation and found lots of helpful stuffs. I’l cover everything that i used where i failed and had success. First i used getBottom and getTop, according to doc it returns top and bottom position relative to parent, since parent on my case was “relative layout” with “match_parent”. I would calculate the heght of scroller:

int webViewHeight = this.getBottom() - this.getTop();

Now i have height of content and height of web view so i calculated the height of the scroller from this:

int scrollerHeight = (webViewHeight * webViewHeight) / height; //height is content height

I calculated detection of end reach with this condition:

if(this.getScrollY() + scrollHeight >= height){
	Log.i("THE END", "reached");
}

But it wasn’t any way near to perfection 😛 I logged the values and saw that calculation for view of webview was getting wrong output. Even getBottom was no way near accurate since it was returning way low value than expected with respect to my 7 inch nexus tablet density.

Next, i used getMeasuredHeight() and this one gave me accurate value. So i applied same above calculation with new height of web view and result still not very accurate. After all this i did small change to my formula and BINGO!!

public void  onScrollChanged (int l, int t, int oldl, int oldt){
	int height = (int) Math.floor(this.getContentHeight() * this.getScale());
	int webViewHeight = this.getMeasuredHeight();
	if(this.getScrollY() + webViewHeight >= height){
		Log.i("THE END", "reached");
	}
}

Yes above code worked absolutely accurate and am still analyzing the formula on above condition :P, i.e offset here is height of the webview but not height of scroll [sighs]. I would love to hear your opinion on this. You can optimize the above code though i just wanted to share the idea behind.