MFMessageComposeViewController Semi-Transparent Keyboard - iphone

I'm trying to initiate a MFMessageComposeViewController with a semi transparent keyboard. I would like to make it as transparent as I want, but I don't think we are allowed to do that from the reading that I've done.
How would you set the property of the UIKeyboard when you create the MFMessageComposeViewController?
Many Thanks!

You do not. From the documentation:
Important The message composition interface itself is not customizable and must not be modified by your application. In addition, after presenting the interface, your application is unable to make further changes to the SMS content. The user can edit the content using the interface, but programmatic changes are ignored. Thus, you must set the values of content fields, if desired, before presenting the interface.
You are not supposed to change this interface, since UIKeyboard is private and the textfields on this view are not accessible by you. Attempting to access and modify this textfield via the view hierarchy might get your app rejected in the app store.

Setting the keyboardAppearance property of your text field or text view to UIKeyboardAppearanceAlert will change the keyboard to the transparent keyboard.
I heard that there's only two styles available in the public API:
[textView setKeyboardAppearance:UIKeyboardAppearanceAlert];
[textView setKeyboardAppearance:UIKeyboardAppearanceDefault];
But you can use private API methods to retrieve the keyboard implementation:
id keyboardImpl = [objc_getClass("UIKeyboardImpl") sharedInstance];
And Make it less opaque,
[keyboardImpl setAlpha:0.8f];
Tint it,
UIView *tint = [[UIView alloc] initWithFrame:[keyboardImpl frame]];
[tint setBackgroundColor:[UIColor colorWithRed:0.0f green:0.0f blue:1.0f alpha:0.3f]];
[tint setUserInteractionEnabled:NO];
[[keyboardImpl superview] insertSubview:tint aboveSubview:keyboardImpl];
[tint release];
Or even flip it:
[[keyboardImpl window] setTransform:CGAffineTransformMakeScale(-1.0f, 1.0f)];
Hope it was the solution for your problem.

Related

UILabel - string as text and links

I have a UILabel whose text I am getting from a server. Some of the text is to be identified as links, and on touching those links some action should be performed. e.g.
NSString *str = #"My phone number is 645-345-2345 and my address is xyz";
This is the complete text for UILabel. I have only one UILabel for displaying this text (Text is dynamic. I just gave an example.). On clicking these links I need to perform actions like navigating to some different screen or make a call.
I know that I can display such text with help of OHAttributedLabel. And the links can be displayed as follows :
[label1 addCustomLink:[NSURL URLWithString:#"http://www.foodreporter.net"] inRange:[txt rangeOfString:someString]];
But I wonder how can I make these text links perform some action like navigation to different screen or making a call.
Let me know if more explanation is required.
You can add custom actions to any of the available UILabel replacements that support links using a fake URL scheme that you'll intercept later:
TTTAttributedLabel *tttLabel = <# create the label here #>;
NSString *labelText = #"Lost? Learn more.";
tttLabel.text = labelText;
NSRange r = [labelText rangeOfString:#"Learn more"];
[tttLabel addLinkToURL:[NSURL URLWithString:#"action://show-help"] withRange:r];
Then, in your TTTAttributedLabelDelegate:
- (void)attributedLabel:(TTTAttributedLabel *)label didSelectLinkWithURL:(NSURL *)url {
if ([[url scheme] hasPrefix:#"action"]) {
if ([[url host] hasPrefix:#"show-help"]) {
/* load help screen */
} else if ([[url host] hasPrefix:#"show-settings"]) {
/* load settings screen */
}
} else {
/* deal with http links here */
}
}
TTTAttributedLabel is a fork of OHAttributedLabel.
If you want a more complex approach, have a look to Nimbus Attributed Label. It support custom links out-of-the-box.
You can use UITextView with Phone numbers and links detection YES, scrolling disabled YES user interaction enabled YES, instead of UILabel.
My project has successfully used OHAttributedLabel for this. Check out the
-(BOOL)attributedLabel:(OHAttributedLabel*)attributedLabel shouldFollowLink:(NSTextCheckingResult*)linkInfo;
method in OHAttributedLabelDelegate (link). It allows you to decide what happens when a link is clicked. If you look at the source for the example from the OHAttributedLabel project, it's used to display an alert. If you returned NO in this case (to keep the default action from happening too), you could just do whatever you wanted like navigation, etc.
Note however that this requires that you can determine the action correctly just from the text. For our project, we used a slightly fancier solution, where the server sent us text with tags in them and a list of commands to perform for each tag.
There a project called FancyLabel that is about what you need. It might need some customization though.
Also, I think Three20 has this functionality, but it might be an overkill if you don't already use it.
There's also a much simpler solution, if all of your links are phones \ addresses \ urls. You can simply use a UITextView instead of a UILabel. It has auto detection of phones, address, etc. (just check the boxes in IB)
You can also have custom actions in response to click events on those links by overriding openURL, as explained here
Is there a specific reason that you must use a UILabel instead of a UITextView?
Note that a lot of the implementations of attributed labels inherit from UIView or don't implement all of UILabel's functionality.
You can use custom button to give a look like of link ..Also you can add gesture on the custom label if you dont want to use button ..
UITapGestureRecognizer* gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(userTappedOnLink:)];
// if labelView is not set userInteractionEnabled, you must do so
[labelView setUserInteractionEnabled:YES];
[labelView addGestureRecognizer:gesture];
I'm not a fan of being forced to use UITextView or a third party lib when all I need is a lightweight label that renders links (and that tells me when they're tapped!)
Here's my attempt at a lightweight UILabel subclass able to detect link taps. The approach is different from others I've seen in that it gains access to the UILabel's shared NSLayoutManager via a delegate callback added to NSTextStorage via a category extension. The beauty is that UILabel performs its native layout and drawing - other UILabel replacements often augment or replace the native behavior with an additional NSLayoutManager/NSTextContainer.
Probably App Store safe, but somewhat fragile - use at your own risk!
https://github.com/TomSwift/TSLabel

custom UINavigationBar background in MFMailComposeViewController

I have a need to use a custom background for the UINavigationBar in a MFMailComposeViewController. Previously I was using a category on UINavigationBar to achieve this throughout my app, but Apple specifically requests that you do not do this. Additionally this may or may not work in future versions of iOS that are currently under NDA.
I am now using a subclass of UINavigationBar to achieve the look I'm after in the rest of the app, but I can't see any way to use this with the MFMailComposeViewController. Any ideas?
Note: I'm aware of methods to do this in a future version of iOS, but this needs to be built against a current version (4.3) of the SDK.
I just ran across this -- you can dynamically inject the class a view controller uses using object_setClass.
#import <objc/runtime.h>
object_setClass(mailController.navigationBar, [YourNavigationBarSubClass class]);
You can customize the nav bar's titleView with a custom view using the code below. Expanding upon this idea, you may be able to resize the titleView to cover the entire navigation bar and use a custom background in that to simulate a custom navbar background.
The only possible sticky part I can think of is that you need to make sure the titleView sits behind the buttons in the toolbar.
Once you have your MFMailComposerViewController reference, here is the code to customize the titleView:
[self presentModalViewController:controller animated:YES];
UIView *backgroundView = [[UIView alloc] initWithFrame:CGRectMake(//set size to navbar size)];
[backgroundView setBackgroundColor:[UIColor colorWithPatternImage://your custom image ]];
controller.topViewController.navigationItem.titleView = backgroundView ;
[controller release];
The mail composition interface itself is not customizable and must not be modified by your application.
check apple reference for more info...
http://developer.apple.com/library/ios/#documentation/MessageUI/Reference/MFMailComposeViewController_class/Reference/Reference.html
but we can customizable the mail composition as given oin the above answer....
After some hacking and testing, still not manage to customize the button. But this is the closest I can get, by setting the tint color of mail controller.
Try accessing them through mailController.navigationBar.items, which is an array of the bar items.
MFMailComposeViewController *mailController = [[MFMailComposeViewController alloc] init];
mailController.mailComposeDelegate = self;
mailController.navigationBar.tintColor = [UIColor brownColor];
Although it would be nice to get more control over the appearance, I don't think there is a clean method. When you cant change it...hide it:
NSDictionary *attributes = #{NSForegroundColorAttributeName: [UIColor clearColor]};
[[UINavigationBar appearance] setTitleTextAttributes:attributes];

How to detect the user click a hyper-link

My app will display some text, and I want to make the hyper-link be able to be clicked. I have some questions about this feature.
How do I parse the text to be aware this is a link?
Once a user click the link, I don't want the OS to switch to Safari and open the link, this is very bad because the user can not go back to my application. So I want to open the link within my application. As soon as the user click the link, my app will present a view modally to display the web content. Any advice would be appreciated.
You probably want to subclass UILabel. When you change the text, have it try to see if the text is a hyperlink, if it is, set it to enable user interaction and change the text color to blue. When the user taps on the link, send a message to the main view controller (Possibly through delegation) to open the link.
to display web content in your app, look into UIWebView.
If your text can be formatted as html with hyperlinks (<a> tags), you could use a UIWebView to display it.
The UIWebViewDelegate's webView:shouldStartLoadWithRequest:navigationType: method is called when a user taps a link. Usually you would make your controller implement this method, and set the UIWebView's delegate to the controller.
You're going to want to check out a Github project called LRLinkableLabel.
It will auto-detect any URLs that are inside the .text property.
You can use it like so:
LRLinkableLabel *label = [[LRLinkableLabel alloc] initWithFrame:CGRectMake(0.0, 0.0, 100.0, 20.0)];
label.delegate = self;
label.text = #"Check out http://dundermifflin.com to find some great paper deals!";
Then just make sure self implements this method:
- (void) linkableLabel:(LRLinkableLabel *)label clickedButton:(UIButton *)button forURL:(NSURL *)url {
[[UIApplication sharedApplication] openURL:url];
}
You can also use the linkColor and textColor properties to configure the appearance of the label. From this point you can use it just like any other UILabel.
Remember to set the delegate to nil when you're all done to make sure everything is all cleaned up.
Hope this helps.

MFMailComposer view does not suit with the color theme of my app

Does anyone know how can we send mail without presenting the MFMailComposerView?
OR
Is there any way I can add a background image on the MFMailComposerView?
I tried changing the backgroud color. it doesn't work.
Only thing i could do was change the navigationBar Tint color
Code:
MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
picker.mailComposeDelegate = self;
picker.navigationBar.tintColor=[UIColor blackColor];
picker.view.backgroundColor=[UIColor brownColor];
Thanks in advance!
From the apple documentation:
Important: The mail composition interface itself is not customizable and must not be modified by your application. In addition, after presenting the interface, your application is not allowed to make further changes to the email content. The user may still edit the content using the interface, but programmatic changes are ignored. Thus, you must set the values of content fields before presenting the interface.
I don't think it's possible, or even if possible, it would be probably rejected by AppStore.

iPhone OS: Tap status bar to scroll to top doesn't work after remove/add back

Using this method to hide the status bar:
[[UIApplication sharedApplication] setStatusBarHidden:YES animated:YES];
When setting "hidden" back to NO, the tap-to-scroll-to-top (in UIWebView, UITableView, whatever) doesn't work any more, and requires a restart of the app to get the functionality back.
Is this a bug (I filed a rdar anyhow) or have I missed a step? Should I perhaps expect this behavior since the statusBar "loses touch" somehow with the respective view?
You could try setting the ScrollsToTop property to true again after re-showing it:
[currentView setScrollsToTop:YES];
If that's not working, are you definitely only showing one view? If there is more than one scrolling view a scrollViewDidScrollToTop message is ignored...
In iOS 5.0 you can access the scrollview property of the UIWebView
webView.scrollView.scrollsToTop = YES;
The following fix by Alex worked for me. Thanks!
((UIScrollView *)[[webView subviews] objectAtIndex:0]).scrollsToTop = NO;
Being in a hurry this fix worked great, however given more time I might've subclassed the UIWebView and accessed the protected UIScrollView member directly.
The worry I have with Alex' method is that it assumes that UIScrollView is at index zero of the subviews (encapsulation allows private members to change). Which suggests another solution still:
for (UIView* v in [webView subviews])
{
if ([v isKindOfClass:[UIScrollView class]])
{
(UIScrollView *)v.scrollsToTop = NO;
}
}
I was having a similar problem where the scroll-to-top functionality was lost. Turns out this will only work when you have only one active view at a time (within the same scroll view). In my case I had a table view and another view which would fade in/out. Adding a removeFromSuperview at the end of the animation did the trick.
The answer was in the UIScrollView.h file comments:
/*
this is for the scroll to top gesture. by default, a single scroll visible scroll view with this flag set will get the call. if there is more than one visible with this
flag set or the delegeat method returns NO, the view isn't scrolled
*/
#property(nonatomic) BOOL scrollsToTop; // default is YES. if set, special gesture will scroll to top of view after consulting delegate
You can use the following code to have the UIWebView ignore scrollToTop without the extra UIScrollView:
((UIScrollView *)[[webView valueForKey:#"_internal"] valueForKey:#"scroller"]).scrollsToTop = NO;
I had a similar problem after playing a Youtube video within my app. scrollsToTop was still set to YES but tapping the status bar had no effect.
I finally realised that my app window was no longer the key window. After adding the following line to a UIWindow subclass (which I already had for other reasons) everything worked as it should again:
if (![self isKeyWindow]) [self makeKeyWindow];
I just ran across a similar behavior in the app I'm currently working on. In its case, if you load a YouTube video from within a UIWebView, scroll to top stops working for the rest of the application's life cycle. I kind of assume this might happen after loading the movie player as well, but haven't confirmed. That functionality has been around a lot longer and probably has fewer bugs.
When there are multiple scrollview, you can also set scrollUpToTop to NO for the others scrollview. cf:
setScrollsToTop with multiple UIScrollView classes and/or subclasses(UITableView)
I want to add my case, I add an UIWebView on an UIScrollView, as h4xxr had answered on the top:
If there is more than one scrolling view a scrollViewDidScrollToTop message is ignored
So, I get a simply way to make it work on webView: just set the scrollView·s scrollsToTop property false.
And when tap the status bar, it won`t got intercepted by the scrollView, and the webView scrolls to the top!
UIScrollView *scrollView = [[UIScrollView alloc] init];
scrollView.frame = self.view.bounds;
scrollView.scrollsToTop = false; //igore scrollView`s scrollsToTop
[self.view addSubview:scrollView];
UIWebView *webView = [[UIWebView alloc] init];
webView.frame = scrollView.bounds;
[scrollView addSubview:webView];