How do I create tooltips or something similar in iOS, without using any third party classes? I have a UIButton that I'd like to have a tooltip popup for a few seconds or until it's cleared. I have seen third party classes and libraries, but want to know if natively it's supported. I also want to show an arrow popping up from where the tooltip is coming from. I've seen some UIActionSheet Popups have this arrow.
Cheers,
Amit
Well I ended up using the third party tooltip CMTopTipView afterall. It's relatively low overhead, just a header and implementation. Modified it slightly to account for ARC. Here is what I did:
#import "CMPopTipView.h"
CMPopTipView *navBarLeftButtonPopTipView;
- (void) dismissToolTip
{
[navBarLeftButtonPopTipView dismissAnimated:YES];
}
- (void) showDoubleTap
{
navBarLeftButtonPopTipView = [[CMPopTipView alloc]
initWithMessage:#"DOUBLE Tap \n to view details"] ;
navBarLeftButtonPopTipView.delegate = self;
navBarLeftButtonPopTipView.backgroundColor = [UIColor darkGrayColor];
navBarLeftButtonPopTipView.textColor = [UIColor lightTextColor];
navBarLeftButtonPopTipView.opaque = FALSE;
[navBarLeftButtonPopTipView presentPointingAtView:catButton1
inView:self.view animated:YES];
navBarLeftButtonPopTipView.alpha = 0.75f;
NSTimer *timerShowToolTip = [NSTimer scheduledTimerWithTimeInterval:5.0
target:self
selector:#selector(dismissToolTip) userInfo:nil repeats:NO];
}
If you are on iPad you could use UIPopoverView. You also have the UIMenuController to work with for 'popover' like functionality on iPhone or iPad: tutorial. Beyond that you could just make your own UIView subclass to do this but then you'd have to handle the arrow yourrself.
Well what I ended up doing was relatively simple. I ended up using UIActionSheet with no Buttons just a text. Then used a showFromRect from a coordinate plane where the UIButton was in self.view.
UIActionSheet *popup = [[UIActionSheet alloc]
initWithTitle:#"DOUBLE Tap \n to view details."
delegate:self cancelButtonTitle:#"Cancel"
destructiveButtonTitle:nil otherButtonTitles: nil];
[popup sizeToFit];
popup.tag = 9999;
CGRect myImageRect = CGRectMake(240.0f, 605.0f, 30.0f, -40.0f);
[popup showFromRect:myImageRect inView:self.view animated:YES];
I may just suck it up and use CMPopTipView (third party control) to adjust it's size and opacity and fading alpha.
I saw that some of you is using CMPopTip, great "library".
Cool way!
Just a few things, if you use that in iOS7, you have some deprecation.
New use of the text deprecated part (this is an example)
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping;
paragraphStyle.alignment = self.titleAlignment;
[self.title drawInRect:titleFrame withAttributes:#{NSFontAttributeName:self.titleFont,NSParagraphStyleAttributeName:paragraphStyle}];
Bye!
Related
Currently, I am trying to set the next/previous buttons on my keyboard toolbar to the new, sleek iOS 7 back button/forward buttons that get put in navigation controllers to go back. Here is what I am trying. How can I use the system bar button item instead of the boring static text?
[self setToolbar:[[UIToolbar alloc] initWithFrame:self.frame]];
[self.toolbar setBarStyle:UIBarStyleDefault];
[self.toolbar setAutoresizingMask:(UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleWidth)];
[self addSubview:self.toolbar];
[self setSegmentedControl:[[UISegmentedControl alloc] initWithItems:#[ NSLocalizedStringFromTable(#"Previous", #"BSKeyboardControls", #"Previous button title."),
NSLocalizedStringFromTable(#"Next", #"BSKeyboardControls", #"Next button title.") ]]];
Here is what it looks like now:
Here is what I want it to look like:
Any ideas on how to access those system items without actually using images? I know its the exact iOS 7 back bar button item, I just don't know how to access it in a tool bar. I've searched everywhere. If it helps, i'm using BSKeyboardControls.
EDIT: To make it look exactly like the second image, use the images provided by Joshua, and save them as back#2x.png, and forward#2x.png into your xcode proj. Use Chun's code, but make sure to call the method for getting the images like this: imageNamed:#"back", and not #"back#2x". You now have iOS 7 back and forward buttons :)
EDIT2: To get it to look exactly like the next/previous arrow buttons use the following customizations in the correct implementation methods:
[self.segmentedControl setWidth:50 forSegmentAtIndex:0];
[self.segmentedControl setWidth:38 forSegmentAtIndex:1];
negativeSeparator.width = -19;
EDIT3: The toolbar with the < > arrows comes by default with all UIWebViews, and it appears when you tap a textfield.
If anyone is interested in a sample project, let me know, and i'll upload a link!
EDIT4: As of May 24, 2014, BSKeyboardControls now has this functionality by default.
These are the images used in toolbar, e.g. the back and forward button images:
Use the icons shared by Joshua and then try with below piece of code and you will be good to go. I have not added the done button here.
UIImage *backImage = [[UIImage imageNamed:#"backImage"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
UIImage *forwardImage = [[UIImage imageNamed:#"forward"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
self.segmentedControl = [[UISegmentedControl alloc] initWithItems:#[backImage, forwardImage]];
[self.segmentedControl addTarget:self action:#selector(segmentedControlChangedState:) forControlEvents:UIControlEventValueChanged];
self.segmentedControl.segmentedControlStyle = UISegmentedControlStyleBar;
self.segmentedControl.tintColor = [UIColor clearColor];
UIBarButtonItem *aSegmentedControlBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:self.segmentedControl];
[self setItems:#[aSegmentedControlBarButtonItem, self.flexibleSpace]];
1) Download latest files from: https://github.com/simonbs/BSKeyboardControls
2) Import the images for back/next buttons. These can be whatever you want and you can set the appropriate sizes so that they look good. Joshua has a good set. I have mine saved as "keyboardBack.png" and "keyboardForward.png"
3) In BSKeyboardControls.m, update initWithFields:fields. Here you can do some customization like setting the width of your back/next buttons. I removed the Done button here too to follow your screenshot but you can add it back.
- (id)initWithFields:(NSArray *)fields
{
if (self = [super initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 44.0f)])
{
// Creates toolbar
[self setToolbar:[[UIToolbar alloc] initWithFrame:self.frame]];
[self.toolbar setBarStyle:UIBarStyleDefault];
[self.toolbar setAutoresizingMask:(UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleWidth)];
[self addSubview:self.toolbar];
// Import images
UIImage *backImage = [[UIImage imageNamed:#"keyboardBack"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
UIImage *forwardImage = [[UIImage imageNamed:#"keyboardForward"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
// Create segmentedcontrol
self.segmentedControl = [[UISegmentedControl alloc] initWithItems:#[backImage, forwardImage]];
self.segmentedControl.tintColor = [UIColor clearColor];
// Set button widths
[self.segmentedControl setWidth:50 forSegmentAtIndex:0];
[self.segmentedControl setWidth:50 forSegmentAtIndex:1];
// Other BSKeyboardControls stuff
[self.segmentedControl addTarget:self action:#selector(segmentedControlValueChanged:) forControlEvents:UIControlEventValueChanged];
[self.segmentedControl setMomentary:YES];
[self.segmentedControl setEnabled:NO forSegmentAtIndex:BSKeyboardControlsDirectionPrevious];
[self.segmentedControl setEnabled:NO forSegmentAtIndex:BSKeyboardControlsDirectionNext];
[self setSegmentedControlItem:[[UIBarButtonItem alloc] initWithCustomView:self.segmentedControl]];
[self setVisibleControls:(BSKeyboardControlPreviousNext)];
[self setFields:fields];
}
return self;
}
4) The left padding on the toolbar is a bit too much, so you can fix it by adding a negative separator in toolbarItems: in BSKeyboardControls.m:
- (NSArray *)toolbarItems
{
NSMutableArray *items = [NSMutableArray arrayWithCapacity:3];
if (self.visibleControls & BSKeyboardControlPreviousNext)
{
UIBarButtonItem *negativeSeperator = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace
target:nil
action:nil];
negativeSeperator.width = -12;
[items addObject:negativeSeperator];
[items addObject:self.segmentedControlItem];
}
if (self.visibleControls & BSKeyboardControlDone)
{
[items addObject:[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]];
[items addObject:self.doneButton];
}
return items;
}
Note: I probably don't have the button widths and paddings to the exact specs, but you can tweak it to your liking!
If you don't mind living on the edge you could use Apple's undocumented system items to achieve the iOS 7 look. Here are left and right bar button items.
[self setDoneButton:[[UIBarButtonItem alloc] initWithBarButtonSystemItem:105 target:nil action:nil]];
[self setDoneButton:[[UIBarButtonItem alloc] initWithBarButtonSystemItem:106 target:nil action:nil]];
Source: http://iphonedevwiki.net/index.php/UIBarButtonItem
You can use this great tool by #iftekhar and customise IQSegmentedNextPrevious according to your need for giving images instead of next previous button.
Using Xcode 7.3, you can also just enter a symbol as the title for the Bar Item. This works both in code and in Interface Builder:
Place your cursor where you want the symbol to appear (eg, title box in IB or within quotes in code).
In Xcode's menu, click Edit, then Emoji & Symbols. (Alternatively, press control-command-space to bring up the list of characters.)
In the search box, type less or greater.
Then, select the symbol you want.
The less-than and greater-than symbols are colored blue in the toolbar by default.
In code:
backButton.title = "<"
In IB:
Use this: https://github.com/simonbs/BSKeyboardControls
But it uses the segmented control which got flattened in iOS 7.
Edit:
Just change the text of the segments:
[self setSegmentedControl:[[UISegmentedControl alloc] initWithItems:#[#"<",#">") ]]];
This may not be the most elegant. (Not even sure this exact code compiles, but you see the point)
Adding some controls to UIAlertView was deprecated in iOS7 using addSubview method. As I know Apple promised to add contentView property.
iOS 7 is released now and I see that this property is not added. That is why I search for some custom solution with ability to add progress bar to this alertView. Something for example similar to TSAlertView, but more ready for using in iOS 7.
Here is a project on Github to add any UIView to an UIAlertView-looking dialog on iOS7.
(Copied from this StackOverflow thread.)
It took me only 1 day to create my own alert view that looks exactly like Apple's
Take a screenshot of Apple's alert for reference (font sizes, spacings, width)
Create a xib with title, message, custom view and tables for buttons (Apple uses tables instead of UIButton now, default table cell is good enough). Note you need 3 button tables: two for left and right buttons (whenever the number of buttons is 2), another one for the other cases (one button or more than 2 buttons).
Implement all the methods from UIAlertView on your custom alert.
Show/Dismiss - you can create a specific modal window for your alerts but I just put my alerts on top of my root view controller. Register your visible alerts to a static array. If showing the first alert/dismissing the last, change tint mode of your window/view controller to dimmed/to automatic and add/remove a dimming view (black with alpha = 0.2).
Blurred background - use Apple's sample code (I used opaque white)
3D dynamic effects - use Apple's sample code (5 lines of code). If you want a nice effect, take a slightly bigger snapshot in step 5 and add inverse animators for alert background and foreground.
EDIT:
Both blurred background and the paralax effect sample code can be found in "iOS_RunningWithASnap" WWDC 2013 sample code
Paralax effect:
UIInterpolatingMotionEffect* xAxis = [[[UIInterpolatingMotionEffect alloc] initWithKeyPath:#"center.x"
type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis] autorelease];
xAxis.minimumRelativeValue = [NSNumber numberWithFloat:-10.0];
xAxis.maximumRelativeValue = [NSNumber numberWithFloat:10.0];
UIInterpolatingMotionEffect* yAxis = [[[UIInterpolatingMotionEffect alloc] initWithKeyPath:#"center.y"
type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis] autorelease];
yAxis.minimumRelativeValue = [NSNumber numberWithFloat:-10.0];
yAxis.maximumRelativeValue = [NSNumber numberWithFloat:10.0];
UIMotionEffectGroup *group = [[[UIMotionEffectGroup alloc] init] autorelease];
group.motionEffects = #[xAxis, yAxis];
[self addMotionEffect:group];
The blurred background is the only complicated thing. If you can use an opaque color instead, use it. Otherwise it's a lot of experimenting. Also note that blurred background is not a good solution when the background is dark.
For the show/dismiss animationg, I am using the new spring animation method:
void (^animations)() = ^{
self.alpha = 1.0f;
self.transform = CGAffineTransformIdentity;
};
self.alpha = 0.0f;
self.transform = CGAffineTransformMakeScale(0.5f, 0.5f);
[UIView animateWithDuration:0.3
delay:0.0
usingSpringWithDamping:0.7f
initialSpringVelocity:0.0f
options:UIViewAnimationOptionCurveLinear
animations:animations
completion:^(BOOL completed) {
//calling UIAlertViewDelegate method
}];
I wrote a full implementation of UIAlertView that mimics the complete UIAlertView API, but adds the contentView property we've all wanted for so long: SDCAlertView.
(source: github.io)
For those who love simple and effective methods with out having to write lines of code. Here is a cool solution without using any other private frame works for adding subviews to ios 7 alert views,i.e.
[alertView setValue:imageView forKey:#"accessoryView"];
Sample code for better understanding,
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(180, 10, 85, 50)];
UIImage *wonImage = [UIImage imageNamed:#"image.png"];
[imageView setImage:wonImage];
//check if os version is 7 or above
if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1) {
[alertView setValue:imageView forKey:#"accessoryView"];
}else{
[alertView addSubview:imageView];
}
Hope it helps some one,thanks :)
For IOS7
UIAlertView *alertView1 = [[UIAlertView alloc] initWithTitle:#"Enter Form Name"
message:#""
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"Ok", nil];
alertView1.alertViewStyle = UIAlertViewStyleSecureTextInput;
UITextField *myTextField = [alertView1 textFieldAtIndex:0];
[alertView1 setTag:555];
myTextField.keyboardType=UIKeyboardTypeAlphabet;
[alertView1 show];
There wont be UIAlertView with custom views in iOS7, nor contentView which Apple changed its mind about, so addSubview is impossible now in UIAlertView.
A good alternative will be SVProgressHUD, according to many threads in Apple's forum.
Edit:
There is officially no addSubview nor subclassing for UIAlertView in iOS7.
The UIAlertView class is intended to be used as-is and does not
support subclassing. The view hierarchy for this class is private and
must not be modified.
Other good alternatives:
ios-custom-alertview by wimagguc
MZFormSheetController.
You can find simple solution without extra classes here
It is based on setting accessoryView for ordinary UIAlertView.
PKAlertController (https://github.com/goodpatch/PKAlertController) is great library. I tested a lot of similar libraries and just this satisfied all my requirements.
Why it is cool:
Supports custom view
Supports iOS7
It is view controller
It behaves and looks like native alert view, including motion effects
Customizable
Similar interface like in UIAlertController
I have researched this question for a few hours, sounds pretty simple to me but haven't been able to find a viable solution. I have an iPad application where I'm using a UIActionSheet to confirm a delete. I'm adding a label to increase the font size. Everything looks and works great. I also have a requirement to dim and lock the background while the Action Sheet is visible. I can dim but cannot see how to lock the background so that the user must make a selection on the Action Sheet to dismiss it. I have tried setting UserInteractionEnabled but it doesn't work. Any Ideas?
// dim the background
UIView *dimViewDelete = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 1024, 768)];
dimViewDelete.backgroundColor = [UIColor blackColor];
dimViewDelete.alpha = 0.3f;
dimViewDelete.tag = 2222;
[self.view addSubview:dimViewDelete];
if ([self.listArray count] > 0)
{
// create Action Sheet
UIActionSheet * action = [[UIActionSheet alloc]
initWithTitle:#" "
delegate:self
cancelButtonTitle:#"Cancel"
destructiveButtonTitle:#"Delete"
otherButtonTitles:nil];
[action addButtonWithTitle:#"Cancel"];
[action setActionSheetStyle:UIActionSheetStyleBlackTranslucent];
[action showInView:self.view];
// change the font size of the title
CGRect oldFrame = [(UILabel*)[[action subviews] objectAtIndex:0] frame];
UILabel *addTitle = [[UILabel alloc] initWithFrame:oldFrame];
addTitle.font = [UIFont boldSystemFontOfSize:22];
addTitle.textAlignment = UITextAlignmentCenter;
addTitle.backgroundColor = [UIColor clearColor];
addTitle.textColor = [UIColor whiteColor];
addTitle.text = #"Are You Sure?";
[addTitle sizeToFit];
addTitle.frame = CGRectMake(oldFrame.origin.x, oldFrame.origin.y,
oldFrame.size.width, addTitle.frame.size.height);
[action addSubview:addTitle];
}
Your best option is to implement your own custom action sheet-like control.
You need a simple view controller that has the two buttons and a label (for the title). Show the view controller in a popover. Make the view controller modal so it can only be dismissed by tapping one of the buttons. This also makes the background appear locked.
If you really need to dim the background as well, just before displaying the popover, add a screen sized UIView to the main window. Set this view's background to [UIColor whiteColor:0 alpha:0.7]. Adjust the alpha as needed to get the right dimming effect. You can even animate the alpha of the view so it fades in and out as needed.
I have three buttons and a textview in uialertview, and tried to move down the buttons with add "\n" in uialertview's message property. But it's not work. The string will become "..." when it reach the limit of a line. the textview always cover my buttons. Do you have any suggestions? Sorry that I don't have the right to post image.
- (void)addMessage
{
self.addMessageAlertView = [[UIAlertView alloc] initWithTitle:#"Add Title"
message:#"\n\n\n\n function normal function normal function normal function normal function normal "
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"OK",#"Search", nil];
self.addMessageTextView = [[UITextView alloc] initWithFrame:CGRectMake(10.0, 75, 260.0, 25*2)];
[addMessageTextView setBackgroundColor:[UIColor whiteColor]];
addMessageTextView.font = [UIFont systemFontOfSize:20];
addMessageTextView.delegate=self;
addMessageTextView.layer.masksToBounds=YES;
addMessageTextView.layer.cornerRadius=10.0;
addMessageTextView.layer.borderWidth=0.0;
[addMessageAlertView addSubview:addMessageTextView];
[addMessageAlertView show];
[addMessageAlertView release];
[addMessageTextView release];
}
- (void)willPresentAlertView:(UIAlertView *)openURLAlert
{
[openURLAlert setFrame:CGRectMake( 10, 60, 300, 300 )];
[openURLAlert setBounds:CGRectMake(0, 10, 290, 290 )];
}
UIAlert view has maximum height (I've tried this same thing with no success); you won't be able to make it bigger. I suggest that you use a custom pop-over instead. A popover can act like an alert but will give you more flexibility.
This question has some links to tutorials: Are there examples of how to use UIPopoverController on iOS?
For God's sake somebody tell me how to add a picture on an UIActionSheet.
I am adding it, but can't force the sheet to restretch its height, so the Subview would fit.
var sheet = new UIActionSheet ("Sheet with a picture");
sheet.AddButton ("Pick New Picture");
var subView = new UIView(new RectangleF(20,100,280,200)){
BackgroundColor = UIColor.FromPatternImage(Picture)};
sheet.AddSubview(subView);
sheet.AddButton ("Cancel");
sheet.CancelButtonIndex = 1;
I've tried to change contentMode of subView and the sheet. Didn't work. What am I doing wrong?
Picture should fit between buttons, or fit on the sheet somehow through any other way around
I know this sounds really stupid, but the easiest solution I found is to add a few dummy buttons (to preserve space) and then on top of them add the UIImageView accurately defining the frame coordinates.
var sheet = new UIActionSheet ("");
sheet.AddButton ("Discard Picture");
sheet.AddButton ("Pick New Picture");
sheet.AddButton ("Cancel");
sheet.CancelButtonIndex = 2;
// Dummy buttons to preserve the space for the UIImageView
for (int i = 0; i < 4; i++) {
sheet.AddButton("");
sheet.Subviews[i+4].Alpha = 0; // And of course it's better to hide them
}
var subView = new UIImageView(Picture);
subView.ContentMode = UIViewContentMode.ScaleAspectFill;
subView.Frame = new RectangleF(23,185,275,210);
// Late Steve Jobs loved rounded corners. Let's have some respect for him
subView.Layer.CornerRadius = 10;
subView.Layer.MasksToBounds = true;
subView.Layer.BorderColor = UIColor.Black.CGColor;
sheet.AddSubview(subView);
UIActionSheet doesn't support customization of this type. You can subclass UIActionSheet and muck with the default layout (override layoutSubviews, call the super implementation, then move things around). If you do this, there's no guarantee your sublcass will work in future versions of iOS if Apple changes the framework implementation.
The other alternative is to find or implement an alternative class that does what you want.
Actually it is quite easy and you don't need a hack:
Change the size of the UIActionSheet AFTER calling showInView (or showFromTabBar, etc), like they do in this example.
You might have to change the Frame instead of the Bounds, in my experience the action sheet is not moved to the right position if you change the Bounds.
On the iPad this doesn't work unfortunately. But there you can use a UIPopoverController. (Tip: you can use 0 for the UIPopoverArrowDirection if you do not want arrows).
This is Agzam's answer, but refreshed for most recent objc and without the background button hack, as suggested by Marcel W. it is shorter and possibly cleaner.
UIActionSheet *actionSheet = [[UIActionSheet alloc] init];
actionSheet.actionSheetStyle = UIActionSheetStyleAutomatic;
actionSheet.title = #"some text";//here type your information text
actionSheet.delegate = self;
[actionSheet addButtonWithTitle:#"Button 1"];
[actionSheet addButtonWithTitle:#"Button 2"];
[actionSheet setCancelButtonIndex:1];
//it is up to you how you show it, I like the tabbar
[actionSheet showFromTabBar:self.tabBarController.tabBar];
//here lays the trick - you change the size after you've called show
[actionSheet setBounds:CGRectMake(0,0,320, 480)];
//now create and add your image
UIImageView *subView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"exampleimage.png"]];
subView.ContentMode = UIViewContentModeScaleAspectFit;
subView.Frame = CGRectMake(0,130,320,180);//adjust these, so that your text fits in
[actionSheet addSubview: (subView)];
[subView release];
[actionSheet release];