How to achieve similar UI with UITextField inside UITableView (UITableViewCell)? - iphone

I am looking to mimic the following UI using a UITextField within a UITableViewCell (within a UITableView). I am new to MonoTouch and I can't seem to figure out what the code would look like for this.

This is very simple. Just add a UITextField with no background color to the cell. Add the below code in your cellForRowAtIndexPath method.
UITextField *inputText = [[UITextField alloc]initWithFrame:CGRectMake(10,10,280,22)];
inputText.textAlignment = UITextAlignmentLeft;
inputText.backgroundColor = [UIColor clearColor];
inputText.placeHolder = #"Street";
[cell.contentView addSubview:inputText];
[inputText release];

The cell is a custom cell. It has some properties, a editable UITextField, and a placehold string for empty content. The following code is writed by hand, so maybe there are some bugs inside.
#interface EditableCell : UITableViewCell {
UITextField *mTextField;
}
#property UITextField *textField;
- (void)setPlaceHoldString:(NSString *)placeHolder;
#end
#implement EditableCell
#synthesize textField = mTextField;
- (void)setPlaceHoldString:(NSString *)placeHolder
{
self.textField.placeHolder = placeHolder;
}
- (UITextField *)textField
{
if (mTextField == nil) {
mTextField = [[UITextField alloc] init];
// Configure this text field.
...
[self addSubView:mTextField];
}
return mTextField;
}
- (void)dealloc
{
self.textField = nil;
[super dealloc];
}
#end

Related

How can i implemented delete button in AQGridViewCell

i want to add button in my Customized AQGridViewCell with ImageView. when i Click Edit button its showing delete button on the ImageGridViewCell like below image.i added delete button in cellForItemAtIndex method. here my code
- (AQGridViewCell *) gridView: (AQGridView *) gridView cellForItemAtIndex: (NSUInteger) index
{
static NSString *photoCellIdentifier = #"IBImageGridViewCell";
IBImageGridViewCell *cell = (IBImageGridViewCell *)[self.gridView dequeueReusableCellWithIdentifier:photoCellIdentifier];
if (cell == nil) {
cell = [[IBImageGridViewCell alloc] initWithFrame:CGRectMake(3.0, 3.0, 100.0, 120.0) reuseIdentifier:photoCellIdentifier];
cell.selectionStyle = AQGridViewCellSelectionStyleNone;
}
PTKEntry *entry = [_objects objectAtIndex:index];
UIButton *deletebutton = [UIButton buttonWithType:UIButtonTypeCustom];
[deletebutton addTarget:self
action:#selector(deleteimage:)
forControlEvents:UIControlEventTouchDown];
[deletebutton viewWithTag:index];
deletebutton.frame = CGRectMake(70,0,30,30);
UIImage * buttonImage = [UIImage imageNamed:#"delete.png"];
[deletebutton setImage:buttonImage forState:UIControlStateNormal];
if (self.gridView.editing) {
deletebutton.hidden=NO;
}
else{
deletebutton.hidden=YES;
}
[cell.contentView addSubview:deletebutton];
[cell.contentView bringSubviewToFront:deletebutton];
if (entry.data && entry.data.photo) {
cell.imageView.image = entry.data.photo;
NSLog(#"load table");
} else {
cell.imageView.image = nil;
NSLog(#"Not load table");
}
return cell;
}
when the view loading didn't show delete button. and while click delete button it showing delete for each grid cell and click done button that delete button didn't hidden from my grid View cell view here
You can create delegate method in AQGridView and implement it in your class like
-(void) gridView:(AQGridView *)gridView didSelectItemAtIndex:(NSUInteger)index
This a delegate method approach.
If you create delegate method
-(void) gridView:(AQGridView *)argGridView deleteCell:(AQGridViewCell *)cell atIndex:(NSUInteger)index;
This will get invoked as didSelectItemAtIndex: when you click on delete button.
To do this follow this procedure.
Add a method canHideDelete: to show and hide delete button in your custom cell IBImageGridViewCell.
When you click on a specified cell then [cell canHideDelete:NO] to show delete button.
In your IBImageGridViewCell,
you can create a block to delete a specified cell.
To do this,
create an extension AQGridViewCell_Extension.h to AQGridViewCell like
#import "AQGridViewCell.h"
typedef void(^AQGridViewCellDeleteBlock)(AQGridViewCell*);
#interface AQGridViewCell ()
#property(nonatomic, copy) AQGridViewCellDeleteBlock deleteBlock;
#end
import "AQGridViewCell_Extension.h" in IBImageGridViewCell.m and AQGridView.m
Now, create a selector to handle delete button and call a block to delete cell.
-(void)deleteButtonAction
{
self.deleteBlock(self);
}
Create a delegate method to be implemented in your class to delete cell
Add this to AQGridView.h under #protocol AQGridViewDelegate
-(void) gridView:(AQGridView*) gridView deleteCell:(AQGridViewCell*) cell atIndex:(NSUInteger) index;
Now, in AQGridView.m,
change method
- (AQGridViewCell *) createPreparedCellForIndex: (NSUInteger) index usingGridData: (AQGridViewData *) gridData
{
[UIView setAnimationsEnabled: NO];
AQGridViewCell * cell = [_dataSource gridView: self cellForItemAtIndex: index];
cell.separatorStyle = _flags.separatorStyle;
cell.editing = self.editing;
cell.displayIndex = index;
cell.frame = [self fixCellFrame: cell.frame forGridRect: [gridData cellRectAtIndex: index]];
if ( _backgroundView.superview == self )
[self insertSubview: cell aboveSubview: _backgroundView];
else
[self insertSubview: cell atIndex: 0];
[UIView setAnimationsEnabled: YES];
__block AQGridView *localAQGridView = self;
// DELETE BUTTON BLOCK - TO CALL DELEGATE METHOD
cell.deleteBlock = ^(AQGridViewCell *argCell)
{
NSInteger index = [localAQGridView indexForCell:argCell];
//NSLog(#"Cell to be deleted is %d", index);
[localAQGridView.delegate gridView:localAQGridView deleteCell:argCell atIndex:index];
};
return ( cell );
}
Implement following method to delete a cell in your class
-(void) gridView:(AQGridView *)argGridView deleteCell:(AQGridViewCell *)cell atIndex:(NSUInteger)index
{
NSLog(#"ON deleting cell at %d", index);
[mediaItemsArray removeObjectAtIndex:index];
NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:index];
[argGridView beginUpdates];
[argGridView deleteItemsAtIndices:indexSet withAnimation:AQGridViewItemAnimationFade];
[argGridView endUpdates];
}
I hope this helps you.
Another way of doing it without modifying the AQGridView class
Add a delete button in your IBImageGridViewCell.xib file and Modify your IBImageGridViewCell.h as
#class IBImageGridViewCell;
#protocol CustomGridCellViewDelegate<NSObject>
#optional
-(void) onDeleteButtonTouched:(IBImageGridViewCell *)sender;
#end
#interface IBImageGridViewCell : AQGridViewCell
+ (id) cellFromNib;
#property (nonatomic,assign) id <CustomGridCellViewDelegate> delegate;
#property (nonatomic, readonly, retain) IBOutlet UIView *contentView;
#property (weak, nonatomic) IBOutlet UIButton *deleteButton;
#property (nonatomic, copy) NSString *reuseIdentifier;
- (IBAction)deleteButtonAction:(UIButton *)sender;
#end
In your IBImageGridViewCell.m file add
- (IBAction)deleteButtonAction:(UIButton *)sender
{
[self.delegate onDeleteButtonTouched:self];
}
Now in your mainViewController.h add the delegate
#interface mainViewController : UIViewController<CustomGridCellViewDelegate>
In your mainViewController.m file
In the method
- (AQGridViewCell *) gridView: (AQGridView *) gridView cellForItemAtIndex: (NSUInteger) index
Add
cell.delegate=self;
cell.deleteButton.tag =index;
Handle the delete button action
-(void)onDeleteButtonTouched:(NTGridViewCell *)sender
{
NSLog(#"Selected Button:%d",sender.deleteButton.tag);
[yourArrayList removeObjectAtIndex:sender.deleteButton.tag];
[self.gridView reloadData];
//***Animated delete
// [yourArrayList removeObjectAtIndex:sender.deleteButton.tag];
// NSIndexSet* set = [NSIndexSet indexSetWithIndex:sender.deleteButton.tag];
// [self.gridView beginUpdates];
// [self.gridView deleteItemsAtIndices:set withAnimation:AQGridViewItemAnimationFade];
// [self.gridView endUpdates];
}

how to trigger update of a custom UITableViewCell after returning to view via back button?

Background
have a custom UITableCellView in which I'm using a custom UITextField that I've added as a subview (i.e. not using normal UITableCellView views
in the scenario is pressing on the cell => jump to screen to modify value (via pushViewController / navigationControl). Then after changing hitting the BACK button to go back to the UITableView
using this approach there is no specific call back for that scenario, so I've been using the approach where you trap this using the general viewDidAppear method of the UITableViewController - the technique I'd used to update the change was:
Code:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
self.myNormalCell.textLabel.textColor = myColor;
[self.tableView reloadData];
}
But what I note is that the above code:
works for for normal/existing fields in a UITableViewCell
does NOT work for my custom textField subviews I've put in my custom UITableViewCell
QUESTION - How to, in this use case, get my custom fields to be udpated/shown on the UITableView when I come back to it after making a change?
For example:
do I need to somehow set my custom field/subview as "needs to be updated"?
do I need to override reloadData somewhere/somehow to set the custom field?
EDIT: Add some code:
CODE FROM cellForRowAtIndexPath
(a) Code that works with standard UITableViewCell
self.lookAheadDaysCell = (ConfigCell*)[tableView dequeueReusableCellWithIdentifier:#"LookAheadWeeks"];
if (self.lookAheadDaysCell == nil) {
self.lookAheadDaysCell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:#"LookAheadWeeks"] autorelease];
self.lookAheadDaysCell.textLabel.text = #" Weeks into Future";
self.lookAheadDaysCell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
self.lookAheadDaysCell.detailTextLabel.text = [self.weConfig.lookAheadWeeks stringValue];
return self.lookAheadDaysCell;
(b) Code that doesn't work with custom field in custom cell
self.lookAheadDaysCell = [ConfigCell cellForReuseId:#"LookAheadWeeks"
TableView:tableView
Title:#"Number of Weeks"
ShowHelp:true
Tag:9999
Delegate:self
UseTextField:false
ContentText:[self.weConfig.lookAheadWeeks stringValue]];
return self.lookAheadDaysCell;
CODE FROM CUSTOM CELL
Interface:
#interface ConfigCell : UITableViewCell <UITextFieldDelegate> {
UITextField *_textField;
UILabel *_titleLabel;
}
#property (nonatomic, retain) UITextField *textField;
#property (nonatomic, retain) UILabel *titleLabel;
+ (ConfigCell*) cellForReuseId:(NSString *)reuseId TableView:(UITableView*)tableView Title:(NSString*)titleStr ShowHelp:(BOOL)showHelp Tag:(NSInteger)tag Delegate:(id)delegate UseTextField:(BOOL)useTextField ContentText:(NSString*)text;
#end
Key Methods:
+ (ConfigCell*) cellForReuseId:(NSString *)reuseId TableView:(UITableView*)tableView Title:(NSString*)titleStr ShowHelp:(BOOL)showHelp Tag:(NSInteger)tag Delegate:(id)delegate UseTextField:(BOOL)useTextField ContentText:(NSString*)text
{
// Get Cell (via reuse or create a new one)
ConfigCell *cell = (ConfigCell*)[tableView dequeueReusableCellWithIdentifier:reuseId];
if (cell == nil) {
// Create Cell
cell = [[[ConfigCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseId] autorelease];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
// View 1 - Title Label
<<cut>>
// View 2 - TextField for entry
cell.textField = [[[UITextField alloc] initWithFrame:CGRectMake(0,0,0,0)] autorelease];
cell.textField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
cell.textField.font = [UIFont systemFontOfSize:16];
cell.textField.textAlignment = UITextAlignmentLeft;
cell.textField.text = text;
if (useTextField) {
cell.textField.delegate = delegate;
cell.textField.tag = tag;
cell.textField.returnKeyType = UIReturnKeyDone;
} else {
cell.textField.userInteractionEnabled = false;
}
[cell.contentView addSubview:cell.textField];
}
return cell;
}
well I did fix it by putting the following line in "viewDidAppear"
self.lookAheadDaysCell.textField.text = [self.weConfig.lookAheadWeeks stringValue];
however it doesn't really help me understand why I didn't need this line when I was using the standard text fields in a UITableViewCell before...noting I'm effectively setting the value of the cell text by reference

How do i remove the blue highlight when selection occurs in a UIPickerView

when i select a cell in my modified picker view, a blue background colour appears.
all other treads i have seen do not give me a good answer.
anyone has a solution?
pickerView.showsSelectionIndicator = NO;
Just set the UITableViewCell selectionStyle property to UITableViewCellEditingStyleNone
cell.selectionStyle = UITableViewCellEditingStyleNone;
I have add toolbar at the top of picker view and add cutom button as a sub view of toolbar and both picker view and toolbar are add as a subview of Main view so you can handle this.
I've met this one. Let's get a look at it in details. To create your custom picker view, you create your custom UIView class, e.g. :
#interface TimeAroundView : UIView
{
NSString *title;
UIImage *image;
}
#property (nonatomic, retain) NSString *title;
#property (nonatomic, retain) UIImage *image;
#end
Then in your custom picker view controller you create some container, e.g. NSArray, which will get all TimeAroundView objects you want to represent in your picker view. So, for every object you must do
timeAroundViewObject.userInteractionEnabled = NO;
I think -(id)init is the best place for filling that container in, so you get something like this:
- (id)init
{
self = [super init];
if (self) {
// create the data source for this custom picker
NSMutableArray *viewArray = [[NSMutableArray alloc] init];
TimeAroundView *earlyMorningView = [[TimeAroundView alloc] initWithFrame:CGRectZero];
earlyMorningView.title = #"Early Morning";
earlyMorningView.image = [UIImage imageNamed:#"12-6AM.png"];
earlyMorningView.userInteractionEnabled = NO;
[viewArray addObject:earlyMorningView];
[earlyMorningView release];
TimeAroundView *lateMorningView = [[TimeAroundView alloc] initWithFrame:CGRectZero];
lateMorningView.title = #"Late Morning";
lateMorningView.image = [UIImage imageNamed:#"6-12AM.png"];
lateMorningView.userInteractionEnabled = NO;
[viewArray addObject:lateMorningView];
[lateMorningView release];
// .... (more of objects)
self.customPickerArray = viewArray;
[viewArray release];
}
return self;
}
And in your pickerView:viewForRow:forComponent:reusingView: you just return proper element from array.
That works for me.

How to implement a TableView where the background scrolls at the same time?

Imagine you have a normal table view where each row is an item on a conveyor belt. You will put the items in each cell of the table view but when you scroll you also want the background image (the conveyor belt) to scroll as well. How can you do this?
You should be able to accomplish this by setting the background color of the table view:
tableView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"background.png"]];
Have the UITableView background transparent, and add a UIScrollView behind it with the UIImageView inside it. Add a listener for when the UITableView scrolls (since it is a subclass of UIScrollView it has all the same delegate methods). Then, when it scrolls, set the scroll position of the UIScrollView behind it to the same programmatically.
You could technically do it without a second UIScrollView behind the UITableView, just with a plain UIIImageView, if you want to reverse the offset values.
I haven't tried this, so I'm not sure what the best approach would be, but one option would be to add your background image as a UIImageView to each of your cells so that every cell has a full-sized copy of your background image. Set clipsToBounds to NO on your cell, and give the bounds of the UIImageView a negative y value equal to the offset from your cell to the top of the table.
You may also want to consider using UIScrollView instead of UITableView.
UITableView is itself a UIScrollView, so you could try just adding your background image as a subview of your UITableView, but I'd be surprised if that worked. I'm guessing the UITableView implementation won't play nice with foreign subviews.
** EDIT **
While I still suspect that UIScrollView may be a more appropriate base class to use here, I decided to try the UIImageView trick I described above. It's fairly simple and doesn't consume excessive memory as long as all your UIImageViews share a single UIImage. Here's my sample code:
// LadderCell.h
#import <UIKit/UIKit.h>
#interface LadderCell : UITableViewCell {
UIImageView *backgroundImageView;
UILabel *titleLabel;
}
#property (nonatomic, retain) UIImageView *backgroundImageView;
#property (nonatomic, retain) UILabel *titleLabel;
- (void)setIndexPath:(NSIndexPath *)indexPath;
- (id)initWithImage:(UIImage *)theImage;
+ (NSString *)reuseIdentifier;
+ (CGFloat)height;
#end
// LadderCell.m
#import "LadderCell.h"
#implementation LadderCell
#synthesize backgroundImageView, titleLabel;
- (void)dealloc {
self.backgroundImageView = nil;
self.titleLabel = nil;
[super dealloc];
}
- (id)initWithImage:(UIImage *)theImage {
if (self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:[LadderCell reuseIdentifier]]) {
self.frame = CGRectMake(0.0, 0.0, 320.0, [LadderCell height]);
self.clipsToBounds = YES;
self.backgroundImageView = [[[UIImageView alloc] initWithImage:theImage] autorelease];
backgroundImageView.autoresizingMask = UIViewAutoresizingFlexibleRightMargin;
self.titleLabel = [[[UILabel alloc] initWithFrame:self.bounds] autorelease];
titleLabel.textAlignment = UITextAlignmentCenter;
titleLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
titleLabel.backgroundColor = [UIColor colorWithWhite:1 alpha:0];
[self addSubview:backgroundImageView];
[self addSubview:titleLabel];
}
return self;
}
- (void)setIndexPath:(NSIndexPath *)indexPath {
backgroundImageView.frame = CGRectMake(0.0,
-(CGFloat)indexPath.row * [LadderCell height] + 100.0,
backgroundImageView.frame.size.width,
backgroundImageView.frame.size.height);
}
+ (NSString *)reuseIdentifier {
return #"LadderCell";
}
+ (CGFloat)height {
return 30;
}
#end
// TableBackgroundTestViewController.h
#import
#interface TableBackgroundTestViewController : UITableViewController {
UIImage *backgroundImage;
}
#property (nonatomic, retain) UIImage *backgroundImage;
#end
// TableBackgroundTestViewController.m
#import "TableBackgroundTestViewController.h"
#import "LadderCell.h"
#implementation TableBackgroundTestViewController
#synthesize backgroundImage;
- (void)dealloc {
self.backgroundImage = nil;
[super dealloc];
}
- (void)viewDidLoad {
[super viewDidLoad];
self.backgroundImage = [UIImage imageNamed:#"background.png"];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section {
return 1000;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return [LadderCell height];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
LadderCell *cell = (LadderCell *)[tableView dequeueReusableCellWithIdentifier:[LadderCell reuseIdentifier]];
if (!cell) {
cell = [[[LadderCell alloc] initWithImage:self.backgroundImage] autorelease];
}
[cell setIndexPath:indexPath];
cell.titleLabel.text = [NSString stringWithFormat:#"Row %d", indexPath.row];
return cell;
}
#end
My suggestion is similar to Ed Marty (what he suggests "without a second UIScrollView"):
Place the UITableView inside a simple UIView. Make the cell backgrounds transparent so background from below the tableview would show
Below the UITableView, place an UIImageView with your desired background. Both the UITableView and UIImageView now sit inside the same enclosing UIView.
Listen to scroll events of UITableView. When detecting a scroll, simply change the background UIImageView position (frame.origin.y) appropriately, so that it would "stick with" the tableview.
You can have the background as one gigantic image, or have a series of them so you do tiling. You can have an array of the images and add to the array from top/bottom when needed, and also remove the images that have "scrolled away" from screen to conserve memory. You will need to calculate the positions for all these background images yourself, but there's nothing complicated in that.

UISearchBar text color

Browsed the documentation and I couldn't find anything to change the color of UISearchBar. Does anybody know how to change it? There isn't any textColor property :/
Thx
Works on iOS 7 and later:
[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setDefaultTextAttributes:#{
NSForegroundColorAttributeName : [UIColor whiteColor],
NSFontAttributeName : [UIFont systemFontOfSize:15]
}];
You may remove unused attribute as well.
UPDATE. Due to appearanceWhenContainedIn is deprecated in iOS 9, see the Dishant's answer below: https://stackoverflow.com/a/38893352/2799722
You can do the following: Just get the searchField property from the SearchBar, and then change its textColor property.
UITextField *searchField = [searchbar valueForKey:#"_searchField"];
searchField.textColor = [UIColor redColor]; //You can put any color here.
That's it! Now you manipulate the textField in any way possible.
iOS 8: See https://stackoverflow.com/a/28183058/308315
iOS 6 / 7:
[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setTextColor:[UIColor redColor]];
I suspect you could use techniques described in this post
Modifying the code presented there slightly, you subclass UISearchBar:
#interface SearchBar : UISearchBar {
}
#end
Then in your implementation:
- (void)layoutSubviews {
UITextField *searchField;
NSUInteger numViews = [self.subviews count];
for(int i = 0; i < numViews; i++) {
if([[self.subviews objectAtIndex:i] isKindOfClass:[UITextField class]]) {
searchField = [self.subviews objectAtIndex:i];
}
}
if(!(searchField == nil)) {
searchField.textColor = [UIColor redColor];
}
[super layoutSubviews];
}
I haven't tested either the original post's code or this code, but looks like it ought to work.
-wkw
Here's a category that adds this functionality:
#implementation UISearchBar (UISearchBar_TextColor)
- (UITextField *)field {
// HACK: This may not work in future iOS versions
for (UIView *subview in self.subviews) {
if ([subview isKindOfClass:[UITextField class]]) {
return (UITextField *)subview;
}
}
return nil;
}
- (UIColor *)textColor {
return self.field.textColor;
}
- (void)setTextColor:(UIColor *)color {
self.field.textColor = color;
}
#end
For iOS11, I found this worked:
After setting the searchController into the navigationItem, the search text was black on black. To make it white, I had to do:
searchController.searchBar.barStyle = .blackTranslucent
It was the only thing that worked for me. My app has a transparent navigation bar to let the background gradient show through, and I am guessing the SearchBar takes on that appearance since my appearance settings for UISearchBar were largely ignored with one exception:
UISearchBar.appearance().tintColor = UIColor.red
This made the Cancel button and the text insertion cursor red. The placeholder text was light gray.
Note that: UISearchBar.appearance().barStyle = .blackTranslucent did not work - it had to be set on the instance. This also had no visible effect on the search bar (it was still transparent like the navigation bar); it just made the search text white.
appearanceWhenContainedIn is deprecated in iOS 9 , so we have to use below method for iOS 9 and above.
[[UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:#[[UISearchBar class]]]
setTintColor:[UIColor whiteColor]];
With iOS 11 the search bar is expected to become part of the navigation bar which, as you might expect, adds all kinds of new "features."
I think it's a bug but I found that I needed to do the following to change the text (and cancel button) colour:
self.searchController.searchBar.barStyle = UISearchBarStyleMinimal;
[[UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:#[[UISearchBar class]]]
setTintColor:[UIColor whiteColor]];
I found that the bar-style, when left to "default," would make the text black no matter the tint colour, etc. When set to either Minimal or Prominent the text was visible.
Here's a cleaner approach:
UITextField *searchField = nil;
for (UIView *v in self.searchBar.subviews)
{
if ([v isKindOfClass:[UITextField class]])
{
searchField = (UITextField *)v;
break;
}
}
if (searchField)
{
searchField.textColor = [UIColor whiteColor];
}
Modified the category suggested by David Foster (#david-foster) to work on iOS 8.
static UITextField *PBFindTextFieldInView(UIView *view) {
for(UIView *subview in view.subviews) {
if([subview isKindOfClass:UITextField.class]) {
return (UITextField *)subview;
} else {
UITextField* textField = PBFindTextFieldInView(subview);
if(textField) {
return textField;
}
}
}
return nil;
}
#implementation UISearchBar (Appearance)
- (UITextField *)field {
return PBFindTextFieldInView(self);
}
- (UIColor *)textColor {
return self.field.textColor;
}
- (void)setTextColor:(UIColor *)color {
self.field.textColor = color;
}
#end
After setting the searchController in the navigationItem for iOS 11, I found that attempting to set the textColor via UIAppearance for any UITextField within a UISearchBar had no affect, but a custom appearance property that simply called the regular textColor worked just fine.
// Implement a custom appearance property via a UITextField category
#interface UITextField (SearchBarTextColor)
#property (nonatomic, strong) UIColor * textColorWorkaround UI_APPEARANCE_SELECTOR;
#end
#implementation UITextField (SearchBarTextColor)
- (UIColor *)textColorWorkaround {
return self.textColor;
}
- (void)setTextColorWorkaround:(UIColor *)textColor {
self.textColor = textColor;
}
#end
And then use as follows:
UITextField *textFieldProxy = [UITextField appearanceWhenContainedInInstancesOfClasses:#[UISearchBar.class]];
textFieldProxy.textColorWorkaround = UIColor.lightGrayColor;
P.S. The same trick helped me color the seemingly inaccessible labels of UIDatePicker and UIPickerView