How can I add a menu option to the NSTextAttachment popup menu is UITextView? - uitextview

I want to add another menu option to the default image attachment menu options (Copy Image, Save to Camera Roll). Note that these options are shown when you long press on an image embedded in the UITextView if the textView is not in editing mode.
I have tried adding a custom menu to the uimenucontroller and using -(void)canPerformAction to enable or disable the option, however this seems to add the menu item to the uitextView's edit menu and has no affect on the attachments popup menu.
-(void)canPerformAction never seems to get called when long pressing on the image attachment.

Well according to Apple there is no public API for doing this, however as it turns out its relatively straight forward to replace the default menu with one that looks and behaves the same.
In the viewController that contains the UITextView add the following or similar and set it up as the textView's delegate.
- (BOOL)textView:(UITextView *)textView shouldInteractWithTextAttachment:(NSTextAttachment *)textAttachment inRange:(NSRange)characterRange {
// save in ivar so we can access once action sheet option is selected
_attachment = textAttachment;
[self attachmentActionSheet:(UITextView *)textView range:characterRange];
return NO;
}
- (void)attachmentActionSheet:(UITextView *)textView range:(NSRange)range {
// get the rect for the selected attachment (if its a big image with top not visible the action sheet
// will be positioned above the top limit of the UITextView
// Need to add code to adjust for this.
CGRect attachmentRect = [self frameOfTextRange:range inTextView:textView];
_attachmentMenuSheet = [[UIActionSheet alloc] initWithTitle:nil
delegate:self
cancelButtonTitle:#"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:#"Copy Image", #"Save to Camera Roll", #"Open in Viewer", nil];
// Show the sheet
[_attachmentMenuSheet showFromRect:attachmentRect inView:textView animated:YES];
}
- (CGRect)frameOfTextRange:(NSRange)range inTextView:(UITextView *)textView {
CGRect rect = [textView.layoutManager boundingRectForGlyphRange:range inTextContainer:textView.textContainer];
// Now convert to textView coordinates
CGRect rectRange = [textView convertRect:rect fromView:textView.textInputView];
// Now convert to contentView coordinates
CGRect rectRangeSuper = [self.contentView convertRect:rectRange fromView:textView];
// Get the textView frame
CGRect rectView = textView.frame;
// Find the intersection of the two (in the same coordinate space)
CGRect rectIntersect = CGRectIntersection(rectRangeSuper, rectView);
// If no intersection then that's weird !!
if (CGRectIsNull(rectIntersect)) {
return rectRange;
}
// Now convert the intersection rect back to textView coordinates
CGRect rectRangeInt = [textView convertRect:rectIntersect fromView:self.contentView];
return rectRangeInt;
}
- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex {
if (actionSheet == _attachmentMenuSheet) {
switch (buttonIndex) {
case 0:
[self copyImageToPasteBoard:[_attachment image]];
break;
case 1:
[self saveToCameraRoll:[_attachment image]];
break;
case 2:
[self browseImage:[_attachment image]];
break;
default:
break;
}
}
}
- (void)saveToCameraRoll:(UIImage*)image {
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
}
- (void)copyImageToPasteBoard:(UIImage*)image {
UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
NSData *data = UIImagePNGRepresentation(image);
[pasteboard setData:data forPasteboardType:#"public.png"];
}
-(void)browseImage:(UIImage*)image
{
OSImageViewController *_imageViewerController = [[OSImageViewController alloc] init];
UIImage *img = [[UIImage alloc] initWithData:UIImagePNGRepresentation(image)];
_imageViewerController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
_imageViewerController.modalPresentationStyle = UIModalPresentationFullScreen;
_imageViewerController.delegate = self;
[self presentViewController:_imageViewerController animated:YES completion:^(void){
[_imageViewerController setImage:img];
}];
}

Related

UITextView to Mimic UITextField [for basic round corner text field]

I want to have UITextField with multiple lines, after a quick google on this issue I found that I should use TextView so I did switch my code to use UITextView when I want multiple lines. My View still have other one line textField that I want to keep.
To make my TextView looks like TextField, I had to add code to set border and radius, but they look a little bit different on iOS7. Does anyone know:
what is the color for the UITextField border? when both enabled and disabled so I can sent my textview to match it.
what is radius of the corner of TextField.
what is the background color for UITextField when it is disabled[attached picture shows the text field has lighter shade of grey when it is disabled]? so i can set my text view to the same color when i disable user interaction.
If there is away to keep using textfield for multiline text, I am all ears and i switch to use it.
Best Regards,
I use this:
textView.layer.borderColor = [[UIColor colorWithRed:215.0 / 255.0 green:215.0 / 255.0 blue:215.0 / 255.0 alpha:1] CGColor];
textView.layer.borderWidth = 0.6f;
textView.layer.cornerRadius = 6.0f;
little differences in the params make it looks more like UITextField(I hope).
I use this:
#import <QuartzCore/QuartzCore.h>
-(void) textViewLikeTextField:(UITextView*)textView
{
[textView.layer setBorderColor:[[UIColor colorWithRed:212.0/255.0
green:212.0/255.0
blue:212.0/255.0
alpha:1] CGColor]];
[textView.layer setBorderWidth:1.0f];
[textView.layer setCornerRadius:7.0f];
[textView.layer setMasksToBounds:YES];
}
and get a good resut.
I have a small subclass of UITextView that gives in iOS 7 the same look as the UITextField
The interface is empty:
#interface MyTextView : UITextView
#end
The implementation overwrites the initialization and the setter of the 'editable' property:
#implementation MyTextView
//================================================================================
- (id) initWithFrame: (CGRect) frame
{
self = [super initWithFrame:frame];
if (self)
{
[self commonInit];
}
return self;
}
//================================================================================
- (id) initWithCoder: (NSCoder *) aDecoder
{
self = [super initWithCoder:aDecoder];
if (self)
{
[self commonInit];
}
return self;
}
//================================================================================
- (void) commonInit
{
self.layer.borderWidth = 1.0f;
self.layer.borderColor = [[UIColor colorWithRed:232.0/255.0
green:232.0/255.0 blue:232.0/255.0 alpha:1] CGColor];
self.layer.cornerRadius = 6;
}
//================================================================================
- (void) setEditable: (BOOL) editable
{
[super setEditable:editable];
if (editable)
{
self.backgroundColor = [UIColor whiteColor];
}
else
{
self.backgroundColor = [UIColor colorWithRed:250.0/255.0
green:250.0/255.0 blue:250.0/255.0 alpha:1];
}
}
//================================================================================
#end
This is the closest I got with enabled UITextView
[yourTextView.layer setBorderColor:[[[UIColor lightGrayColor] colorWithAlphaComponent:0.2] CGColor]];
[yourTextView.layer setBorderWidth:2.0];
yourTextView.layer.cornerRadius = 5;
yourTextView.clipsToBounds = YES;
yourTextView.textColor = [UIColor lightGrayColor];

Rotation issue using UIActivityViewController in a MapView

In my iOS app I have a Map View that I called mappa.
I just add a UIActivityViewController that appears when a callout is pressed from an annotation View.
I use this code to display it:
- (void)mapView:(MKMapView *)mapView
annotationView:(MKAnnotationView *)view
calloutAccessoryControlTapped:(UIControl *)control {
[mappa deselectAnnotation:view.annotation animated:YES];
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 6.0) {
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:#[self, [NSURL URLWithString:#"http://www.AppStore.com/iToretto"]]
applicationActivities:nil];
activityViewController.excludedActivityTypes = #[UIActivityTypePostToWeibo, UIActivityTypeAssignToContact, UIActivityTypeCopyToPasteboard ];
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
UIPopoverController *pop = [[UIPopoverController alloc] initWithContentViewController:activityViewController];
self.annotationPopoverController = pop;
//show the popover next to the annotation view (pin)
[pop presentPopoverFromRect:view.bounds
inView:view
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
self.annotationPopoverController.delegate = self;
}
}
}
My problem is that when I rotate this popover, I have a frame Issue (like this). I understand that the solution is to override :
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
duration:(NSTimeInterval)duration;
But when I try to display popover in landscape mode in this way I have multiple errors:
if (UIInterfaceOrientationLandscapeLeft && [self.annotationPopoverController isPopoverVisible]) {
[self.annotationPopoverController presentPopoverFromRect:view.bounds
inView:view
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
}
Because "view.bounds" and "view" is a local declaration of MKAnnotation
So, How can I fix it?! Does anyone have a solution?! Thanks in advance.

iOS4 MKMapKit - map not zooming in when more than one pin

Sure this is something simple as I'm just starting with the maps. I already have a map showing one location, but when I've added a second anotation the map stays zoomed all the way out rather than going to my locations. The pins are there when I zoom in, so I know that bit's working.
Code snippets:
- (void)viewDidLoad
{
...
...
...
// Set coordinates for our position
CLLocationCoordinate2D location;
location.latitude = [self.lat doubleValue];
location.longitude = [self.lon doubleValue];
// Add the annotation to our map view
MapViewAnnotation *newAnnotation = [[MapViewAnnotation alloc]
initWithTitle:self.placename
andSubtitle:self.subtitle
andCoordinate:location];
[self.mapView addAnnotation:newAnnotation];
[newAnnotation release];
// Set coordinates for our second position
CLLocationCoordinate2D amenitylocation;
amenitylocation.latitude = self.latitude;
amenitylocation.longitude = self.longitude;
// Add the annotation to our map view
MapViewAnnotation *amenityAnnotation = [[MapViewAnnotation alloc]
initWithTitle:self.callouttitle
andSubtitle:self.calloutsubtitle
andCoordinate:amenitylocation];
[self.mapView addAnnotation:amenityAnnotation];
[amenityAnnotation release];
[super viewDidLoad];
}
#pragma mark - MKMapView Delegates
// When a map annotation point is added, zoom to it (1500 range)
- (void)mapView:(MKMapView *)mv didAddAnnotationViews:(NSArray *)views
{
MKAnnotationView *annotationView = [views objectAtIndex:0];
id <MKAnnotation> mp = [annotationView annotation];
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance([mp coordinate], 1500, 1500);
[mv setRegion:region animated:YES];
[mv selectAnnotation:mp animated:YES];
}
- (MKAnnotationView *)mapView:(MKMapView *)mv viewForAnnotation:(id<MKAnnotation>)annotation
{
if(mapView.userLocation==annotation)
{
return nil;
}
NSString *identifier = #"IDENTIFIER";
MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if(annotationView==nil)
{
annotationView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier]autorelease];
annotationView.pinColor=MKPinAnnotationColorPurple;
annotationView.canShowCallout=YES;
}
return annotationView;
}
I'd appreciate any pointers.
Also, am I right in thinking I'll have to make custom callouts if I want more than one to appear on the map at the same time?
Sorry, found the answer - I didn't have the MKMapView delegate linked to File's Owner in IB, although I do have in my header file. Linked that up and it's working.

iAds in a Scrolling View

In my application I want to show iAd in table view controller which have both navigation bar and Tab bar. I am able to show iAd in my application but this iAd is give trouble when I try to scroll, the problem is that iAd is also scrolling with the cells due to which I am not able to view the cell in bottom. I am creating the iAd using below code. can some one help me out in resolving following issue.
#pragma mark -
#pragma mark === Banner View Methods ===
#pragma mark -
- (void)createBannerView {
Class cls = NSClassFromString(#"ADBannerView");
if (cls) {
ADBannerView *adView = [[cls alloc] initWithFrame:CGRectZero];
adView.requiredContentSizeIdentifiers = [NSSet setWithObjects:ADBannerContentSizeIdentifierPortrait,
ADBannerContentSizeIdentifierLandscape, nil];
// Set the current size based on device orientation
adView.currentContentSizeIdentifier = ADBannerContentSizeIdentifierPortrait;
adView.delegate = self;
adView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleRightMargin;
// Set intital frame to be offscreen
CGRect bannerFrame =adView.frame;
bannerFrame.origin.y = self.view.frame.size.height;
adView.frame = bannerFrame;
self.bannerView = adView;
[self.view addSubview:adView];
[adView release];
}
}
- (void)showBanner {
CGFloat fullViewHeight = self.view.frame.size.height;
CGRect tableFrame = self.tv.frame;
CGRect bannerFrame = self.bannerView.frame;
// Shrink the tableview to create space for banner
tableFrame.size.height = fullViewHeight - bannerFrame.size.height;
// Move banner onscreen
bannerFrame.origin.y = fullViewHeight - bannerFrame.size.height;
[UIView beginAnimations:#"showBanner" context:NULL];
self.tv.frame = tableFrame;
self.bannerView.frame = bannerFrame;
[UIView commitAnimations];
}
- (void)hideBanner {
// Grow the tableview to occupy space left by banner
CGFloat fullViewHeight = self.view.frame.size.height;
CGRect tableFrame = self.tv.frame;
tableFrame.size.height = fullViewHeight;
// Move the banner view offscreen
CGRect bannerFrame = self.bannerView.frame;
bannerFrame.origin.y = fullViewHeight;
self.tv.frame = tableFrame;
self.bannerView.frame = bannerFrame;
}
- (void)releaseBanner {
if (self.bannerView) {
bannerView.delegate = nil;
self.bannerView = nil;
}
}
- (void)changeBannerOrientation:(UIInterfaceOrientation)toOrientation {
if (UIInterfaceOrientationIsLandscape(toOrientation)) {
self.bannerView.currentContentSizeIdentifier =
ADBannerContentSizeIdentifierLandscape;
}
else {
self.bannerView.currentContentSizeIdentifier =
ADBannerContentSizeIdentifierPortrait;
}
}
#pragma mark -
#pragma mark === ADBannerViewDelegate Methods ===
#pragma mark -
- (void)bannerViewDidLoadAd:(ADBannerView *)banner {
[self showBanner];
}
- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error {
[self hideBanner];
}
yes i got it you use addSubView which i think is wrong Add this Banner in last cell of a tableview or in a fotter of a table view if you are not use load more functionalty in you app
– tableView:viewForFooterInSection:
use that delegate method of table view UItableViewDelegate i think it helps you
– tableView:heightForFooterInSection:
add that method too to specify the height of footer of your table
add the calculate banner size code in
– tableView:heightForFooterInSection:
and add banner in – tableView:heightForFooterInSection:

How to capture Tap gesture on MKMapView

I am trying to capture tap event on my MKMapView, this way I can drop a MKPinAnnotation on the point where user tapped. Basically I have a map overlayed with MKOverlayViews (an overlay showing a building) and I would like to give user more information about that Overlay when they tap on it by dropping a MKPinAnnotaion and showing more information in the callout.
Thank you.
You can use a UIGestureRecognizer to detect touches on the map view.
Instead of a single tap, however, I would suggest looking for a double tap (UITapGestureRecognizer) or a long press (UILongPressGestureRecognizer). A single tap might interfere with the user trying to single tap on the pin or callout itself.
In the place where you setup the map view (in viewDidLoad for example), attach the gesture recognizer to the map view:
UITapGestureRecognizer *tgr = [[UITapGestureRecognizer alloc]
initWithTarget:self action:#selector(handleGesture:)];
tgr.numberOfTapsRequired = 2;
tgr.numberOfTouchesRequired = 1;
[mapView addGestureRecognizer:tgr];
[tgr release];
or to use a long press:
UILongPressGestureRecognizer *lpgr = [[UILongPressGestureRecognizer alloc]
initWithTarget:self action:#selector(handleGesture:)];
lpgr.minimumPressDuration = 2.0; //user must press for 2 seconds
[mapView addGestureRecognizer:lpgr];
[lpgr release];
In the handleGesture: method:
- (void)handleGesture:(UIGestureRecognizer *)gestureRecognizer
{
if (gestureRecognizer.state != UIGestureRecognizerStateEnded)
return;
CGPoint touchPoint = [gestureRecognizer locationInView:mapView];
CLLocationCoordinate2D touchMapCoordinate =
[mapView convertPoint:touchPoint toCoordinateFromView:mapView];
MKPointAnnotation *pa = [[MKPointAnnotation alloc] init];
pa.coordinate = touchMapCoordinate;
pa.title = #"Hello";
[mapView addAnnotation:pa];
[pa release];
}
I setup a long press (UILongPressGestureRecognizer) in viewDidLoad: but it just detect the only one touch from the first.
Where can i setup a long press to detect all touch? (it means the map ready everytime waiting user touch to screen to push a pin)
The viewDidLoad: method!
- (void)viewDidLoad {
[super viewDidLoad];mapView.mapType = MKMapTypeStandard;
UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(handleLongPressGesture:)];
[self.mapView addGestureRecognizer:longPressGesture];
[longPressGesture release];
mapAnnotations = [[NSMutableArray alloc] init];
MyLocation *location = [[MyLocation alloc] init];
[mapAnnotations addObject:location];
[self gotoLocation];
[self.mapView addAnnotations:self.mapAnnotations];
}
and the handleLongPressGesture method:
-(void)handleLongPressGesture:(UIGestureRecognizer*)sender {
// This is important if you only want to receive one tap and hold event
if (sender.state == UIGestureRecognizerStateEnded)
{NSLog(#"Released!");
[self.mapView removeGestureRecognizer:sender];
}
else
{
// Here we get the CGPoint for the touch and convert it to latitude and longitude coordinates to display on the map
CGPoint point = [sender locationInView:self.mapView];
CLLocationCoordinate2D locCoord = [self.mapView convertPoint:point toCoordinateFromView:self.mapView];
// Then all you have to do is create the annotation and add it to the map
MyLocation *dropPin = [[MyLocation alloc] init];
dropPin.latitude = [NSNumber numberWithDouble:locCoord.latitude];
dropPin.longitude = [NSNumber numberWithDouble:locCoord.longitude];
// [self.mapView addAnnotation:dropPin];
[mapAnnotations addObject:dropPin];
[dropPin release];
NSLog(#"Hold!!");
NSLog(#"Count: %d", [mapAnnotations count]);
}
}
If you want to use a single click/tap in the map view, here's a snippet of code I'm using. (Cocoa and Swift)
let gr = NSClickGestureRecognizer(target: self, action: "createPoint:")
gr.numberOfClicksRequired = 1
gr.delaysPrimaryMouseButtonEvents = false // allows +/- button press
gr.delegate = self
map.addGestureRecognizer(gr)
in the gesture delegate method, a simple test to prefer the double-tap gesture …
func gestureRecognizer(gestureRecognizer: NSGestureRecognizer, shouldRequireFailureOfGestureRecognizer otherGestureRecognizer: NSGestureRecognizer) -> Bool {
let other = otherGestureRecognizer as? NSClickGestureRecognizer
if (other?.numberOfClicksRequired > 1) {
return true; // allows double click
}
return false
}
you could also filter the gesture in other delegate methods if you wanted the Map to be in various "states", one of which allowed the single tap/click
For some reason, the UIGestureRecognizer just didn't work for me in Swift. When I use the UIGestureRecognizer way. When I used the touchesEnded method, it returns a MKNewAnnotationContainerView. It seems that this MKNewAnnotationContainerView blocked my MKMapView. Fortunately enough, it's a subview of MKMapView. So I looped through MKNewAnnotationContainerView's superviews till self.view to get the MKMapView. And I managed to pin the mapView by tapping.
Swift 4.1
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
let t = touches.first
print(t?.location(in: self.view) as Any)
print(t?.view?.superview?.superview.self as Any)
print(mapView.self as Any)
var tempView = t?.view
while tempView != self.view {
if tempView != mapView {
tempView = tempView?.superview!
}else if tempView == mapView{
break
}
}
let convertedCoor = mapView.convert((t?.location(in: mapView))!, toCoordinateFrom: mapView)
let pin = MKPointAnnotation()
pin.coordinate = convertedCoor
mapView.addAnnotation(pin)
}

Resources