Can I tint (black) a UIKeyboard? If so, how? - iphone

Is there a way to get a black keyboard? The default one is bluish. And the Alert style one is semi-transparent black. I was wondering if it was possible to have the keyboard black, e.g. non transparent. Or do I have to pull up a black view behind the keyboard to reduce the transparency effect?

The short answer is, NO. The only two keyboards you can display are the normal and alert style keyboards.
There are ways to hack around, get the ui keyboard and change it's composition. I wouldn't recommend doing this as it will 1) likely make have your app rejected from the app store and 2) likely break the next time an iOS revision comes around.
Seems like putting a black or white view behind the keyboard should work for application. In this case I would recommend looking here for a way to animate that black view up below the keyboard.

As Ben states above you can just use one of these two values:
[textView setKeyboardAppearance:UIKeyboardAppearanceAlert];
[textView setKeyboardAppearance:UIKeyboardAppearanceDefault];

Here is code to remove the UIKeyboard background by hiding it. Feel free to modify it to tint the UIKeyboard:
-(NSArray*)subviewsOfView:(UIView*)view withType:(NSString*)type{
NSString *prefix = [NSString stringWithFormat:#"<%#",type];
NSMutableArray *subviewArray = [NSMutableArray array];
for (UIView *subview in view.subviews) {
NSArray *tempArray = [self subviewsOfView:subview withType:type];
for (UIView *view in tempArray) {
[subviewArray addObject:view];
}
}
if ([[view description]hasPrefix:prefix]) {
[subviewArray addObject:view];
}
return [NSArray arrayWithArray:subviewArray];
}
-(void)removeKeyboardBackground{
for (UIWindow *keyboardWindow in [[UIApplication sharedApplication] windows]) {
for (UIView *keyboard in [keyboardWindow subviews]) {
for (UIView *view in [self subviewsOfView:keyboard withType:#"UIKBBackgroundView"]) {
view.hidden=YES;
}
}
}
}
Just call [self removeKeyboardBackground] after you received a NSNotification for UIKeyboardDidShowNotification. Do whatever you want with the background view by replacing view.hidden=YES; with whatever you would like.

Related

How do I remove the iPhone KeyBoard toolbar border?

I am using the following code to remove the toolbar from the iPhone keyboard when it is displayed.
- (void) keyboardDidShowNotification:(NSNotification *)aNotification {
NSArray *array = [[UIApplication sharedApplication] windows];
for (UIWindow* wind in array) {
for (UIView* currView in wind.subviews) {
if ([[currView description] hasPrefix:#"<UIPeripheralHostView"]) {
for (UIView* perView in currView.subviews) {
if ([[perView description] hasPrefix:#"<UIWebFormAccessory"]) {
[perView removeFromSuperview];
}
}
}
}
}
}
This is removing the toolbar like I want but it is still leaving a 1px border above where the toolbar use to be. How do I remove that as well?
Also this only appears to be an issue on iPhone Retina displays. iPhone 3GS and iPad Retina do not have it.
Seems to be a bug in removeFromSuperView. I had the same problem when adding a toolbar as an input accessory view to some pickers for inline editing. Calling 2x removeFromSuperView left the border.
Using [self.view endEditing:YES] when closing the picker helped to clean up the picker and the accessory view attached to it, with no border. Perhaps this can point you into the right direction?

UISearchDisplayController hide drop shadow

If you look closely to the bottom of the UISearchBar in a UISearchDisplayController, you'll notice it has a subtile drop shadow. This shadow doesn't fit in the design of the app I'm currently working on, so I'm trying to remove/hide it. Unfortunately I have not yet succeeded.
During my research into this drop shadow, I found that it's not part of the UISearchBar. When I remove the UISearchDisplayController's UISearchBar from its superview in - (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller, the shadow remains visible.
The shadow turned out to be part of the UISearchDisplayController's searchResultsTableView: when I hide the searchResultsTableView, the shadow disappears. However, I have not been able to trace down the view that has the shadow on its layer. I tried recursively iterating through all visible views (starting at [[UIApplication sharedApplication] window]) and then hiding the drop shadow of each view and setting its clipsToBounds property to YES, which also did not yield the desired result.
Any ideas?
I finally found a solution. Since setting clipsToBounds to YES and hiding the drop shadow of each view in the hierarchy didn't work, it's obvious that the shadow is an image. After iterating through all subviews of the searchResultsTableView and printing their class property, I found an instance of _UISearchBarShadowView, which obviously is the culprit. So what I'm doing now is finding the _UISearchBarShadowView and setting its alpha to 0.0f.
- (void)searchDisplayController:(UISearchDisplayController *)controller didShowSearchResultsTableView:(UITableView *)tableView
{
[self _findAndHideSearchBarShadowInView:tableView];
}
- (void)_findAndHideSearchBarShadowInView:(UIView *)view
{
NSString *usc = #"_";
NSString *sb = #"UISearchBar";
NSString *sv = #"ShadowView";
NSString *s = [[usc stringByAppendingString:sb] stringByAppendingString:sv];
for (UIView *v in view.subviews)
{
if ([v isKindOfClass:NSClassFromString(s)]) {
v.alpha = 0.0f;
}
[self _findAndHideSearchBarShadowInView:v];
}
}
The accepted answer uses a private API, which could get your app rejected. Instead, I'd just locate and hide any subviews that are also custom subclasses of UIImageView, like so:
- (void)searchDisplayController:(UISearchDisplayController *)controller didShowSearchResultsTableView:(UITableView *)tableView
{
for (UIView *view in tableView.subviews) {
if ([view.class isSubclassOfClass:[UIImageView class]]) {
view.alpha = 0.f;
}
}
}

UISearchBar No Background Landscape Mode

I have the following snippet to remove the background from a UISearchBar:
for (UIView *subview in self.searchDisplayController.searchBar.subviews)
{
if ([subview isKindOfClass:NSClassFromString(#"UISearchBarBackground")])
{
[subview removeFromSuperview];
break;
}
}
However, if the device is rotated to landscape a black background appears behind the search bar. Any ideas how to fix it? I'm not exactly sure if this is undocumented.
Thanks!
I just ran across this problem and found little help searching. Unfortunately, removing the feature was not an option so I had to figure it out. It seems as the the UISearchBar view has a background that goes black when you change orientation. So my code now looks like this:
[searchBar setBackgroundColor:[UIColor clearColor]];
for (UIView *subview in searchBar.subviews)
{
if ([subview isKindOfClass:NSClassFromString(#"UISearchBarBackground")])
[subview removeFromSuperview];
}
Given the undocumented nature, I removed the feature. Appears to be a bug due to the undocumented call.
got it ....
open the interface builder under searchbar attributes in view, Mode is set as 'Redraw' set it to scaleToFill

Custom Delete button On Editing in UITableView Cell

I have gone through this question that shows the following code:
-(NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath{
return #"Sagar";
}
What if I want a custom image instead of the default red button?
Implement this method in custom cell
- (void)willTransitionToState:(UITableViewCellStateMask)state{
[super willTransitionToState:state];
if ((state & UITableViewCellStateShowingDeleteConfirmationMask) == UITableViewCellStateShowingDeleteConfirmationMask) {
for (UIView *subview in self.subviews) {
if ([NSStringFromClass([subview class]) isEqualToString:#"UITableViewCellDeleteConfirmationControl"]) {
UIImageView *deleteBtn = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 64, 33)];
[deleteBtn setImage:[UIImage imageNamed:#"delete.png"]];
[[subview.subviews objectAtIndex:0] addSubview:deleteBtn];
[deleteBtn release];
}
}
}
}
This is a late reply but I hope someone may find this helpful. So the accepted answer seems sort of complicated for me, and #user1684899's answer only works if you just want to change the look of the delete button. I want to completely change the appearance of the delete button (i.e. its frame, position, etc.), so my solution is to add my own delete button to my custom cell and keep it initially hidden, and only show it when the cell is in edit mode. What's more important, I want to hide iOS's original delete button and support backward compatibility, and here's my trick:
- (void)willTransitionToState:(UITableViewCellStateMask)state
{
[super willTransitionToState:state];
if ((state & UITableViewCellStateShowingDeleteConfirmationMask) == UITableViewCellStateShowingDeleteConfirmationMask)
{
if (!IS_IOS_7){
for (UIView *subview in self.subviews)
{
if ([NSStringFromClass([subview class]) isEqualToString:#"UITableViewCellDeleteConfirmationControl"])
{
// hide original button
[[subview.subviews objectAtIndex:0] setHidden:YES];
// show my custom button
[self.deleteButton setHidden:NO];
}
}
} else {
for (UIView *subview in self.subviews) {
for (UIView *subview2 in subview.subviews) {
if ([NSStringFromClass([subview2 class]) rangeOfString:#"Delete"].location != NSNotFound) {
// hide original button
[subview2 setHidden:YES];
// show my custom button
[self.deleteButton setHidden:NO];
}
}
}
}
} else {
// hide my custom button otherwise
[self.deleteButton setHidden:YES];
}
}
And don't forget to add:
[cell.deleteButton addTarget:self action:#selector(deleteEntryAtIndexPath:) forControlEvents:UIControlEventTouchUpInside];
in cellForRowAtIndexPath, so that you can add any thing you want when your delete button is clicked. Here is my result:
The systemwide standard for the intended list-dive-in action, as you said in the comment on luvieere's answer, would be to use the detail-disclosure (blue circled arrow) cell accessory, not the swipe gesture.
That said, if you still want to use the swipe action for this, there's no way to provide your own button without manually intercepting and completely reimplementing the swipe gesture, like what Tweetie does.
luvieere is right -- if you want that same "delete" metaphor, you want to keep it at the red button that Apple provides. Why change it? Its globally recognizable as the standard for delete buttons.
Although, if you want something like Tweetie, where you completely change the behavior of swiping, you could use something like ABTableViewCell where you just draw in your own view. Make a custom table view, override -touchesBegan:withEvent:, and check for touches. Calculate the delta of the two touches (in touchesMoved:withEvent:) and move your own view around.

Changing the size of the UISearchBar TextField?

I have a UITableView with an Index on the side; I want to add a UISearchBar to it, but the index overlaps with the "x" to clear the search. I've noticed in the Contacts application, the textfield within the UISearchBar is resized to accommodate this, but I can't work out how to do this in my own app.
I have tried the following in my viewDidLoad, but it does not seem to work.
UITextField * textField = (UITextField *)[[self.search subviews] objectAtIndex:0];
CGRect r = textField.frame;
[textField setFrame:CGRectMake(r.origin.x, r.origin.y, r.size.height, r.size.width-30)];
Any ideas?
it's much easier than all these suggestions. In interface builder, instead of putting the Search Bar as the header of your Table View, you can put a View instead. Then, put a Navigation Bar inside this View. Grab the left resizing handle of the Navigation Bar and pull it to the right until the N B is only 25 pixels wide. Clear out the Title in the N B (double click to select it, then delete). Then, add a Search Bar into the same View. Move its right resizing handle to the left, adjust so that it abuts the N B. That's it.
You can enable a cancel button if you want too and it also won't overlap the index (remains within the search bar).
Apparently a Table View can only have 1 subview in its header, that's why you need to put the View first, then the N B and Search Bar inside it.
UPDATE: see Beginning iPhone Development from Apress, p. 241 of SDK 3 edition. You just disable the index while searching.
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
if (isSearching) {
return nil;
}
return keys;
}
Also they talk about adding a magnifying glass to the top of the index.
Great book all around.
Why not just make the actual UISearchBar smaller horizontally, and place an (empty) UINavigationBar to the right of it? They will render the exact same background.
Better than hacking the internals of Apple's objects that could change.
Also, when animating the UISearchBar's width, you'll notice that the inner text field is not animated along with it. You can fix this by calling UISearchBar's "layoutSubviews" within your animation block after changing its frame. (that's where it determines the size of the inner text field)
Ok, I've come up with a solution.
Create a subclass of UISearchBar
Include this code in the drawRect: method.
UITextView * textField = [self.subviews objectAtIndex:0];
textField.frame = CGRectMake(5, 6, (310 - kRightSideMargin), 31);
[super drawRect:rect];
Note: kRightSideMargin is a constant I set in my header file; I have it set to 25.
Thanks for the suggestions from everyone else.
As Padraig pointed out all you have to do is subclass out the searchBar. Create your UISearchBar subclass, and add the following code into the layoutSubviews method:
- (void)layoutSubviews
{
UITextField *searchField;
for(int i = 0; i < [self.subviews count]; i++)
{
if([[self.subviews objectAtIndex:i] isKindOfClass:[UITextField class]])
{
searchField = [self.subviews objectAtIndex:i];
}
}
if(!(searchField == nil))
{
searchField.frame = CGRectMake(4, 5, 285, 30);
}
}
This loops through all the subviews and checks them against type UITextField. That way if it ever moves in its line up of subviews this will still grab it. I found 285 to just wide enough not to overlap with the index of my tableView.
As of iOS 6, the navigation bar solution didn't work well for me because of slightly different looks now between the UISearchBar and UINavigationBar. So, I switched to something similar to Padraig's approach by subclassing the UISearchBar.
#interface SearchBarWithPad : UISearchBar
#end
#implementation SearchBarWithPad
- (void) layoutSubviews {
[super layoutSubviews];
NSInteger pad = 50;
for (UIView *view in self.subviews) {
if ([view isKindOfClass: [UITextField class]])
view.frame = CGRectMake (view.frame.origin.x, view.frame.origin.y, view.frame.size.width - pad, view.frame.size.height);
}
}
#end
Edit: Ah, I haven't tried it, but I think you might be able to set a navigation bar's clipToBounds = YES to turn off it's new shadow, thereby creating a consistent look again between the two controls.
I am using ViewDeck and want to show a UISearchbar inside the leftController.
Now the problem is if I open the left side which contains the navigation, the right bit overlaps my search field.
I got rid of this by over writing UISearchBar, the textfield will always have the same width, but in one case there is the ViewDeck overlapping and in the other case I hide the ViewDeck-bit and then the cancel button will take up the space:
Subclassing UISearchBar
#import "ViewDeckSearchBar.h"
#define kViewDeckPadding 55
#interface ViewDeckSearchBar()
#property (readonly) UITextField *textField;
#end
#implementation ViewDeckSearchBar
static CGRect initialTextFieldFrame;
- (void) layoutSubviews {
[super layoutSubviews];
// Store the initial frame for the the text field
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
initialTextFieldFrame = self.textField.frame;
});
[self updateTextFieldFrame];
}
-(void)updateTextFieldFrame{
int width = initialTextFieldFrame.size.width - (kViewDeckPadding + 6);
CGRect newFrame = CGRectMake (self.textField.frame.origin.x,
self.textField.frame.origin.y,
width,
self.textField.frame.size.height);
self.textField.frame = newFrame;
}
-(UITextField *)textField{
for (UIView *view in self.subviews) {
if ([view isKindOfClass: [UITextField class]]){
return (UITextField *)view;
}
}
return nil;
}
#end
ViewController class
In my Navigation class I need to overwrite these two UISearchbarDelegate methods in order to go to fullscreen with the search results:
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar{
[self.viewDeckController setLeftSize:0];
// I am also using scopes, which works fine (they fade out when not searching)
self.searchBar.scopeButtonTitles = #[#"Food",
#"Beverages",
#"Misc"];
}
-(void)searchBarTextDidEndEditing:(UISearchBar *)searchBar{
self.viewDeckController.leftSize = 55;
}
Result
ViewDeck showing to the right:
(source: minus.com)
Search in Fullscreen (The button and the scope buttons are animated in).
(source: minus.com)
searchBar.layoutMargins = UIEdgeInsetsMake(0, 0, 0, rightPad);
My old solution of changing the UITextField frame stopped working in iOS 13. Putting a UINavigationBar to the right of the UISearchBar never worked well for me as they had different looks at top and bottom.
Sorry to drag this all up again.
I wanted the UISearchBar to be shorter, and I'm using a UISearchBarController, but without actually wanting the index. This is because I have an overlay to the right:
To do this, I fake a sectionIndex with one blank item, then hide it. Here's how I do that:
- (void)hideTableIndex {
for (UIView *view in [tableView subviews]) {
if ([view isKindOfClass:NSClassFromString(#"UITableViewIndex")]) {
view.hidden = YES;
}
}
}
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)aTableView {
if (aTableView == self.searchDisplayController.searchResultsTableView) {
return nil;
} else {
[self performSelector:#selector(hideTableIndex) withObject:nil afterDelay:0];
return [NSArray arrayWithObjects:#"", nil];
}
}
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
return 0;
}
This shortens the the UISearchBar and hides the index so it can't be tapped (a small section would otherwise hand to the left of the overlay that when tapped would scroll the UITableView to the top). Like this:
Best of all, when you use the search, you still get the full width bar:
Just put a UIView and put the search bar inside that UIView. UIView must be of same size as UISearchBar.
this worked for me.
The text field used in UISearchBar is a subclass of UITextField called UISearchBarTextField.
AFAIK, there's no way to resize a UISearchBarTextField using the public API, and the private API doesn't reveal much either.
Maybe you can take a look at UISearchBarTextField's subviews, if it has any.
UPDATE: It doesn't.
UPDATE 2: I think you should take a look at UITextField's rightView property. The below code, although it doesn't work, seems like a good starting point:
UIView *emptyView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 25, 25)];
[textField setRightView:emptyView];
[textField setRightViewMode:UITextFieldViewModeAlways];
[emptyView release];
Sorry for Necroposting, but I found another way to make a little space on the right of the textfield.
I was having the problem, that I had an indexed tableview with a searchbar as the first row. Now the index and the searchbar (made in IB, btw.) were overlapping. It tried almost everything with no success. It seems that the width and height properties of the textifield don't respond... So I came up with this:
searchBar.showsCancelButton = YES;
UIView *cButton = [searchBar.subviews objectAtIndex:2];
cButton.hidden = YES;
I still can't adjust the size of the space, but this does it for now... although... pretty weird solution...
Everyone has provided ways to modify the UI. I have discovered how to obtain identical results. You must provide the following two implementations:
Use UISearchDisplayController
More importantly, make sure you initialize it with:
- (id)initWithSearchBar:(UISearchBar *)searchBar contentsController:(UIViewController *)viewController
Failure to set a valid UISearchBar (or passing nil) will prevent the adjustment of the UITextField for the index.
You must return a valid array of titles by implementing:
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView;
If you return nil, the index will not be displayed, and the UITextField will not be properly adjusted.
I've submitted a bug report to Apple, suggesting that it seems logical that only #2 should be required, not #1. I have found nothing in the Human Interface Guideline (iPhone HIG) requiring use of the UISearchDisplayController.
The key is to use the "Search Bar and Search Display Controller" and not the "Search Bar" when using Interface Builder.
It kind of looks as though Apple resize the view (note that the index is animated to the right, off screen), making it bigger than the screen.
I would imagine that you'd need to implement the searchBarTextDidBeginEditing: method of the UISearchBarDelegate to trigger this at the appropriate point. This does, however, feel a bit hacky do maybe there's a better way of doing it.
Another appraoch (though tedious) would be to resize the search bar and fill the 'gap' with a navigation bar. Works for me.
What I've come up with isn't too much better. Basically, I make an empty view with the frame that I want to use for the search bar. Then I create a UIToolbar to go behind the search bar. Be sure to set its frame to the same frame as the UIView, except that the Y value has to be -1; otherwise, you'll get two borders drawn at the top. Next create your UISearchBar, but set the frame's width to 30 (or whatever makes sense for your app) less than the UIView. Add them as subviews and set your UIView as the tableHeaderView.
I followed Mike's advice by making a UIView, then putting a Navigation Bar and UISearch Bar inside it. Only problem is first time the search bar is shown its background is the same as a Navigation Bar normally?
Interestingly, if I activate the search, then click cancel the background of this 'fixed'!?
I'm using SDK 3.0, so I removed the UISearchBar item made when I dragged a UISearchDisplayController in to my NIB, then made the view as described above and wired it up to the file owner and the searchBar outlet in the search display controller.
It work fine!!!
[searchBar setContentInset:UIEdgeInsetsMake(5, 0, 5, 35)];