I am trying to create an NSMatrix of NSButtonCells where between zero and four buttons can be selected (toggled on). I have tried the following (test) code, but am not sure how I can provide the functionality I require. Perhaps it's not possible with NSMatrix and I need to look at an alternative control, or create my own?
#interface MatrixView : NSView
{
NSScrollView *_scrollView;
NSMatrix *_matrixView;
}
#end
#implementation MatrixView
- (id)initWithFrame:(NSRect)frameRect
{
NSLog(#"initWithFrame. frameRect=%#", NSStringFromRect(frameRect));
self = [super initWithFrame:frameRect];
if (self != nil)
{
_scrollView = [[NSScrollView alloc] initWithFrame:NSMakeRect(0, 0, frameRect.size.width, frameRect.size.height)];
[_scrollView setBorderType:NSNoBorder];
[_scrollView setHasVerticalScroller:YES];
[_scrollView setHasHorizontalScroller:NO];
[_scrollView setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
NSSize contentSize = [_scrollView contentSize];
contentSize.height = 300;
// Make it 3 x however-many-buttons-will-fit-the-height
CGFloat gap = 8.0;
CGFloat width = (contentSize.width / 3.0) - (gap * 2.0);
NSUInteger rows = (contentSize.height / (width + gap));
NSLog(#"width=%f, rows=%lu", width, rows);
NSButtonCell *prototype = [[NSButtonCell alloc] init];
[prototype setTitle:#"Hello"];
[prototype setButtonType:NSToggleButton];
[prototype setShowsStateBy:NSChangeGrayCellMask];
_matrixView = [[NSMatrix alloc] initWithFrame:NSMakeRect(0, 0, contentSize.width, contentSize.height)
mode:NSListModeMatrix
prototype:prototype
numberOfRows:rows
numberOfColumns:3];
[_matrixView setCellSize:NSMakeSize(width, width)];
[_matrixView setIntercellSpacing:NSMakeSize(gap, gap)];
[_matrixView setAllowsEmptySelection:YES];
[_matrixView sizeToCells];
[_scrollView setDocumentView:_matrixView];
[self addSubview:_scrollView];
[self setAutoresizesSubviews:YES];
[prototype release];
}
return self;
}
...
I got this to work with the following subclass of NSMatrix. I added one property, onCount, to keep track of how many buttons were in the on state:
#implementation RDMatrix
#synthesize onCount;
-(id) initWithParentView:(NSView *) cv {
NSButtonCell *theCell = [[NSButtonCell alloc ]init];
theCell.bezelStyle = NSSmallSquareBezelStyle;
theCell.buttonType = NSPushOnPushOffButton;
theCell.title = #"";
if (self = [super initWithFrame:NSMakeRect(200,150,1,1) mode:2 prototype:theCell numberOfRows:4 numberOfColumns:4]){
[self setSelectionByRect:FALSE];
[self setCellSize:NSMakeSize(40,40)];
[self sizeToCells];
self.target = self;
self.action = #selector(buttonClick:);
self.drawsBackground = FALSE;
self.autoresizingMask = 8;
self.allowsEmptySelection = TRUE;
self.mode = NSHighlightModeMatrix;
self.onCount = 0;
[cv addSubview:self];
return self;
}
return nil;
}
-(IBAction)buttonClick:(NSMatrix *)sender {
NSUInteger onOrOff =[sender.selectedCells.lastObject state];
if (onOrOff) {
self.onCount += 1;
}else{
self.onCount -= 1;
}
NSLog(#"%ld",self.onCount);
if (self.onCount == 5) {
[sender.selectedCells.lastObject setState:0];
self.onCount -= 1;
}
}
When you try to select the 5th button it will flash on, but then go off. This could be a problem depending on how you are using the state of these buttons. I just logged them with this method:
-(IBAction)checkMatrix:(id)sender {
NSIndexSet *indxs = [self.mat.cells indexesOfObjectsPassingTest:^BOOL(NSButtonCell *cell, NSUInteger idx, BOOL *stop) {
return cell.state == NSOnState;
}];
NSLog(#"%#",indxs);
}
After Edit: I didn't like the way my first method flashed the button on briefly before turning it off again when you try to click the 5th button. I found what I think is a better solution that involves overriding mouseDown in the matrix subclass (if you want to try this, you should delete the setAction and setTarget statements and delete the buttonClick method):
-(void)mouseDown:(NSEvent *) event {
NSPoint matPoint = [self convertPoint:event.locationInWindow fromView:nil];
NSInteger row;
NSInteger column;
[self getRow:&row column:&column forPoint:matPoint];
NSButtonCell *cell = [self cellAtRow:row column:column];
if (self.onCount < 4 && cell.state == NSOffState) {
cell.state = NSOnState;
self.onCount += 1;
}else if (cell.state == NSOnState) {
cell.state = NSOffState;
self.onCount -= 1;
}
}
Related
I have a UISearchController just over my UITableView and my table has many recrods. When a user goes to bottom in the table, he has to come back to top to see the search bar. Below you can see how I create the search bar:
- (void) showSearchBar {
_searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
self.searchController.searchResultsUpdater = self;
self.searchController.searchBar.placeholder = nil;
[self.searchController.searchBar sizeToFit];
self.tableView.tableHeaderView = self.searchController.searchBar;
//self.sharedNavigationItem.titleView = _searchController.searchBar;
self.searchController.delegate = self;
self.searchController.dimsBackgroundDuringPresentation = NO; // default is YES
self.searchController.searchBar.delegate = self; // so we can monitor text changes + others
self.definesPresentationContext = YES;
_searchController.hidesNavigationBarDuringPresentation = NO;
}
I was wondering how to show the search bar when I scroll down (go up) in the table and hide it back when I scroll up (go down) in the table even I am at the bottom of the table.
The search bar can be placed arbitrarily in the UI. Create a sibling view to the table view, placed -- for example -- above the table. Give that view a height constraint set initially to 44px and provide outlets to both the view and the constraint...
#property(weak,nonatomic) IBOutlet UIView *searchBarContainerView;
#property(weak,nonatomic) IBOutlet NSLayoutConstraint *searchBarHeightConstraint;
Now, your setup code changes to:
// ...
self.searchBarHeightConstraint.constant = self.searchController.searchBar.bounds.size.height;
[self.searchBarContainerView addSubview:self.searchController.searchBar];
// ...
If you make the header stay at top, then the search field should stay visible
UITableViewStylePlain: A plain table view. Any section headers or footers are displayed as inline separators and float when the table view is scrolled.
UITableViewStyleGrouped: A table view whose sections present distinct groups of rows. The section headers and footers do not float.
I trying to help you out with what I did, hope it helps you.
This is how I added my label in header view of table view, I tried to replace it by your search controller;
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
CGRect frame = CGRectMake(0, 0, tableView.frame.size.width, 40);
UIView *view = [[UIView alloc] initWithFrame:frame];
view.backgroundColor = [UIColor clearColor];
view.autoresizingMask = UIViewAutoresizingFlexibleWidth;
_searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
self.searchController.searchResultsUpdater = self;
self.searchController.searchBar.placeholder = nil;
[self.searchController.searchBar sizeToFit];
[view addSubview:_searchController];
view.tag = 123;
return view;
}
If you wish to hide effect at complete end of dragging move use below method;
-(void)scrollViewWillEndDragging:(UIScrollView *)scrollView
withVelocity:(CGPoint)velocity
targetContentOffset:(inout CGPoint *)targetContentOffset{
if (velocity.y > 0){
NSLog(#"up");
[self.view viewWithTag:123].hidden = true;
}
if (velocity.y < 0){
NSLog(#"down");
[self.view viewWithTag:123].hidden = false;
}
And for immediate changes of scrolling the tableview use below method :
-(void)scrollViewDidScroll:(UIScrollView *)scrollView //working delegate
{
if ([scrollView.panGestureRecognizer translationInView:scrollView].y > 0) {
NSLog(#"down");
[self.view viewWithTag:123].hidden = false;
} else {
NSLog(#"up");
[self.view viewWithTag:123].hidden = true;
}
}
After some searching I thought of some new answer, hope it helps you!
To identify direction of Scroll:
BOOL showSearch;
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if ([scrollView.panGestureRecognizer translationInView:scrollView].y > 0) {
// down
showSearch = true;
} else {
// up
showSearch = false;
}
}
-(void)scrollViewWillEndDragging:(UIScrollView *)scrollView
withVelocity:(CGPoint)velocity
targetContentOffset:(inout CGPoint *)targetContentOffset{
if (showSearch) {
[self addSearch];
}
else {
[self removeSearch];
}
[_tableView reloadData];
}
To add & remove SearchController:
-(void)addSearch {
if (!_searchController){
_searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
_searchController.searchResultsUpdater = self;
[_searchController.searchBar sizeToFit];
_tableView.tableHeaderView = _searchController.searchBar;
_searchController.delegate = self;
_searchController.dimsBackgroundDuringPresentation = NO;
self.definesPresentationContext = YES;
_searchController.active = NO;
_searchController.searchResultsUpdater = self;
_searchController.dimsBackgroundDuringPresentation = NO;
self.definesPresentationContext = YES;
_tableView.tableHeaderView = _searchController.searchBar;
_searchController.searchBar.delegate = self;
}
}
-(void)removeSearch {
_searchController.active = NO;
[_searchController removeFromParentViewController];
_searchController = nil;
_tableView.tableHeaderView = nil;
}
I'm trying to append images onto a view and have them display a thumbnail in a nice neat row. The issue I'm having is that it appears all images simply get added on top on each other in the corner as only the last image in the array is dispayed.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
self.notesField.delegate = self;
NSString *userName = ((ontracAppDelegate*)[UIApplication sharedApplication].delegate).userName;
self.textField.text = [NSString stringWithFormat:#"Date Created: %# \nCreated By: %#",[NSDate date], userName];
if (self.noteText != nil) {
self.notesField.text = self.noteText;
self.notesField.editable = NO;
self.textLabel.hidden = TRUE;
}
[self.view resignFirstResponder];
if ([self.imageArray count] != 0) {
for (UIImage *image in imageArray) {
NSLog(#"Image %#", image);
[self addImageToScreen:image];
}
}
NSLog(#"imageArray %#", imageArray);
NSLog(#"self.textField.text %#", self.textField.text );
NSLog(#"self.notesField.text %#", self.notesField.text);
}
-(void) addImageToScreen:(UIImage*) image;
{
int adjustHeight = 0;
int adjustWidth = 10;
int imagesInARow = 7;
int imageHeight = 75;
int imageWidth = 75;
int count = [self.imageArray count];
self.numberOfPhotosLabel.text = [NSString stringWithFormat:#"%i",count];
if (count > 1 && count < imagesInARow) {
adjustHeight = 0;
adjustWidth = (20 * [self.imageArray indexOfObject:image]) + ([self.imageArray indexOfObject:image] * imageWidth);
}
UIButton* container = [[UIButton alloc] init ];
CGRect frame = CGRectMake(adjustWidth, 5, imageWidth, imageHeight);
[container setTag:[self.imageArray indexOfObject:image]];
[container setImage:image forState:UIControlStateNormal];
[container setFrame:frame];
[container addTarget:self action:#selector(displayFullScreenImage:) forControlEvents:UIControlEventAllTouchEvents];
UIStackView *photosView = [[UIStackView alloc] initWithFrame:frame];
container.frame = photosView.bounds;
[photosView addSubview:container];
[self.view addSubview:photosView];
}
Use addArrangedSubview of UIStackView instead of addSubview.
And you should add all the Buttons to the same UIStackView. So, add a property for the UIStackView to your class, initialize it in viewDidLoad (or in the storyboard) and add the buttons to that stack view in addImageToScreen.
I am trying to make a table view cell that shows ratings for songs in a playlist. I have successfully created the cell so that it shows the current number of stars, and also an indication of how a new setting will be when you hover your mouse cursor over a cell to give a new rating.
The problem is that while mouseEnter, mouseExit and mouseMove works like a charm, I get no messages for mouseDown, which is required to actually change the value of the cell.
I have searched all over the Internet, but I can't find any solution to how to solve this problem anywhere. I have spent so many hours trying to sort this. I hope anyone have any answer or hint what I can do. Thank you.
The full code for the current implementation is as follows:
#import "FavouriteCellView.h"
#implementation FavouriteCellView {
NSTrackingArea *_trackingArea;
int _starsRated; //The current rating value
BOOL _hovering; //YES if the mouse is currently hovering over this cell
int _starsHovering; //The number of stars hovering, if the mouse is hovering over this cell
}
- (void)awakeFromNib {
[super awakeFromNib];
_starsRated = 1;
_hovering = NO;
_starsHovering = 0;
[self createTrackingArea];
}
- (void)createTrackingArea
{
_trackingArea = [[NSTrackingArea alloc] initWithRect:self.bounds options:NSTrackingMouseEnteredAndExited |NSTrackingActiveInActiveApp | NSTrackingMouseMoved owner:self userInfo:nil];
[self addTrackingArea:_trackingArea];
}
- (void)updateTrackingAreas{
[self removeTrackingArea:_trackingArea];
_trackingArea = nil;
[self createTrackingArea];
}
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
// CGFloat middleX = [self bounds].size.width / 2.0f;
CGFloat middleY = [self bounds].size.height / 2.0f;
CGFloat starDivs = [self bounds].size.width / 5.0f;;
NSColor *starSelectedColor = [NSColor colorWithDeviceRed:0.8f green:0.0f blue:0.4f alpha:1.0f];
NSColor *starUnselectedColor = [NSColor colorWithDeviceRed:0.5f green:0.5f blue:0.5f alpha:1.0f];
NSColor *starHoverColor = [NSColor colorWithDeviceRed:1.0f green:0.843f blue:0.0f alpha:1.0f];
NSColor *starHoverColorSelected = [NSColor colorWithDeviceRed:0.9f green:0.843f blue:0.6f alpha:1.0f];
for (int i = 0; i < 5; i++) {
NSColor *useColor = [NSColor redColor];
if (_hovering && (i <= _starsHovering)) {
if (i <= _starsRated) {
useColor = starHoverColorSelected;
} else {
useColor = starHoverColor;
}
} else if (i <= _starsRated) {
useColor = starSelectedColor;
} else {
useColor = starUnselectedColor;
}
[self star:NSMakePoint((starDivs / 2.0f) + starDivs * i, middleY) color:useColor];
}
}
-(void)star:(NSPoint)center color:(NSColor *)color {
[color set];
CGFloat t = (2.0f * M_PI) / 10.0f;
NSBezierPath *path = [[NSBezierPath alloc] init];
CGFloat radii1 = 12.0f;
CGFloat radii2 = 4.0f;
CGFloat rot = M_PI / 2.0f;
BOOL first = YES;
for (int i = 0; i < 10; i++) {
CGFloat pointX = cos(t * i + rot) * radii1 + center.x;
CGFloat pointY = sin(t * i + rot) * radii1 + center.y;
CGFloat tempRadii = radii1;
radii1 = radii2;
radii2 = tempRadii;
if (first) {
first = NO;
[path moveToPoint:NSMakePoint(pointX, pointY)];
}
else {
[path lineToPoint:NSMakePoint(pointX, pointY)];
}
}
[path closePath];
[path fill];
/*
[[NSColor blackColor] set];
[path setLineWidth:0.25f];
[path stroke];
*/
}
-(NSView *)hitTest:(NSPoint)aPoint {
//THIS GETS CALLED
return self;
}
-(BOOL)validateProposedFirstResponder:(NSResponder *)responder forEvent:(NSEvent *)event {
printf("$"); //DOES NOT GET CALLED
return YES;
}
-(BOOL)acceptsFirstResponder {
printf("!"); //DOES NOT GET CALLED
return YES;
}
-(BOOL)acceptsFirstMouse:(NSEvent *)theEvent {
printf("8"); //DOES NOT GET CALLED
return YES;
}
-(void)mouseDown:(NSEvent *)theEvent {
printf("o"); //DOES NOT GET CALLED
_starsRated = _starsHovering;
}
-(void)mouseUp:(NSEvent *)theEvent {
printf("O"); //DOES NOT GET CALLED
}
-(void)mouseEntered:(NSEvent *)theEvent {
//DOES GET CALLED
_hovering = YES;
[self setNeedsDisplay:YES];
}
-(void)mouseExited:(NSEvent *)theEvent {
//DOES GET CALLED
_hovering = NO;
[self setNeedsDisplay:YES];
}
-(void)mouseMoved:(NSEvent *)theEvent {
//DOES GET CALLED
NSPoint mouseLocation = [[self window] mouseLocationOutsideOfEventStream];
mouseLocation = [self convertPoint: mouseLocation
fromView: nil];
int newStarsHoveringValue = mouseLocation.x / ([self bounds].size.width / 5.0f);
if (newStarsHoveringValue != _starsHovering) {
_starsHovering = newStarsHoveringValue;
[self setNeedsDisplay:YES];
}
}
#end
It was a bit fiddly, but I managed to create a solution that works. I subclassed NSTableView, then overrode mouseDown with the following code:
-(void)mouseDown:(NSEvent *)theEvent {
NSPoint globalLocation = [theEvent locationInWindow];
NSPoint localLocation = [self convertPoint:globalLocation fromView:nil];
NSInteger clickedRow = [self rowAtPoint:localLocation];
if (clickedRow != -1) {
NSInteger clickedColumn = [self columnAtPoint:localLocation];
if (clickedColumn != -1) {
if (clickedColumn == 3) {
FavouriteCellView *fv = [self viewAtColumn:clickedColumn row:clickedRow makeIfNecessary:NO];
if (fv != nil) {
[fv mouseDown:theEvent];
}
return;
}
}
}
[super mouseDown:theEvent];
}
Now it works exactly like I wanted.
I have the following class
#import <UIKit/UIKit.h>
#interface UIImageViewInfo : UIImageView
#property(nonatomic,strong) NSString* colorInfo;
#end
when creating an UIImageViewInfo in function1(post below) I get the correct result
"UIImageViewInfo: 0x1d8acd60; baseClass = UIImageView; frame = (0 0;
20 20); opaque = NO; userInteractionEnabled = NO; tag = 2000; layer =
CALayer: 0x1d8a0560>>"
but creating the something in function2(posted below) I get the -(null)
UIImageViewInfo: 0x8372c40; baseClass = UIImageView; frame = (0 0; 20
20); alpha = 0; hidden = YES; opaque = NO; userInteractionEnabled =
NO; tag = 2000; layer = CALayer: 0x8380090>> - (null)
Why is there a - (null) ??
Thanx in advance
P.S> here is more from my code
-(void)function1{
UIImageViewInfo *image;
self.solutionPinSlots = [[NSMutableArray alloc] init];
for (int i=0; i<M; i++) {
image = [[UIImageViewInfo alloc] initWithImage:[UIImage imageNamed:#"solutionPeg#2x.png"]];
image.translatesAutoresizingMaskIntoConstraints=NO;
image.hidden=YES;
image.alpha = 0;
image.colorInfo = #"clear";
image.tag = 2000*(self.brainController.slotsIndex+1) +i;
[self.solutionPinSlots addObject:image];
[self.view addSubview:(UIImageViewInfo *)self.solutionPinSlots[i]];
}
NSLog(#"solutionSlots: %#",self.solutionPinSlots);
__block int counter = 0;
[self.brainController.solution enumerateObjectsUsingBlock:^(NSString *peg, NSUInteger idx, BOOL *stop){
for (int i=0;i<M;i++) {
if ([self.brainController.slots[self.brainController.slotsIndex][i] isEqual:peg]) {
if (i==idx) {
((UIImageViewInfo *) self.solutionPinSlots[counter]).backgroundColor = [UIColor whiteColor];
((UIImageViewInfo *) self.solutionPinSlots[counter]).colorInfo=#"white";
}else{
((UIImageViewInfo *) self.solutionPinSlots[counter]).backgroundColor = [UIColor blackColor];
((UIImageViewInfo *) self.solutionPinSlots[counter]).colorInfo=#"black";}
((UIImageViewInfo *) self.solutionPinSlots[counter]).hidden=NO;
((UIImageViewInfo *) self.solutionPinSlots[counter++]).alpha=1;
}
}
}];
[self.solutionPinSlots shuffle];
[self updateSolutionPinSlots];
}
-(void)function2{
NSString *obj;
for (int idx=0; idx< M;idx++ ) {
UIImageViewInfo *image = [[UIImageViewInfo alloc] initWithImage:[UIImage imageNamed:#"solutionPeg#2x.png"]];
image.translatesAutoresizingMaskIntoConstraints=NO;
obj = (NSString *) [self.solutionPinSlots objectAtIndex:idx];
image.tag=2000*(self.brainController.slotsIndex+1)+idx;
image.hidden=NO;
image.alpha = 1;
if ([obj isEqualToString:#"clear"]) {
image.hidden=YES;
image.alpha = 0;
image.colorInfo=#"clear";
image.backgroundColor=[UIColor clearColor];
}else if ([obj isEqualToString:#"white"]){
image.colorInfo=#"white";
image.backgroundColor=[UIColor whiteColor];
}else if ([obj isEqualToString:#"black"]){
image.colorInfo=#"black";
image.backgroundColor=[UIColor blackColor];
}else{
NSLog(#"Something is Wrong!!!");
}
[self.solutionPinSlots replaceObjectAtIndex:idx withObject:image];
[self.view addSubview:image];
}
}
Never mind. It is coming from the description method of UIView, which is rather complex and dumps a bunch of information about the view. One of the conditionals is being tripped up by your configuration and causing the (null) at the end.
Safe to ignore.
There is no UIImageViewInfo class in UIKit, so the implementation must be in your project. In that implementation, there is likely a description method that is implemented something like:
- (NSString*)description {
....
return [NSString stringWithFormat:#"UIImageViewInfo:%p; %# - %#", self, [super description], someInstanceVariableThatHappensToBeNil]];
}
Only your description is likely more complex due to the sometimes does this sometimes that output.
Not that you should not prefix classes with UI when subclassing the UIKit.
It is because your NSLog call (which you do not show) is asking for a second object, and that second object is null.
I try to subclass UITextField as follows to implement custom rightView as a Clear button:
-(void) drawRect:(CGRect)rect
{
[self.layer setBackgroundColor:[[UIColor colorWithRed:20.0/255.0 green:20.0/255.0 blue:20.0/255.0 alpha:1] CGColor]];
[self.layer setCornerRadius:15.0];
UIImage *imgClear = [UIImage imageNamed:#"btnClear"];
CGSize iSize = [imgClear size];
UIButton *clearButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, iSize.width, iSize.height)];
[clearButton setImage:imgClear forState:UIControlStateNormal];
[clearButton addTarget:self action:#selector(clearText:) forControlEvents:UIControlEventTouchUpInside];
[self setRightViewMode:UITextFieldViewModeWhileEditing];
[self setRightView:clearButton];
[clearButton release];
}
but the Problem is: when the textfield just becomes focus, "clear"-button becomes visible too and after i begin to tap the keyboard it dissapears. Any ideas?
I meet the same problem, too. I guess this is an iOS bug, however, I tried to fix this problem by following implementations and it works fine for me. Hope this will help you.
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
...
[self addTarget:self action:#selector(onEditing:) forControlEvents: UIControlEventEditingChanged]
...
}
-(void) onEditing:(id)sender {
if(![self.text isEqualToString:#""]){
self.rightViewMode = UITextFieldViewModeAlways;
}else{
self.rightViewMode = UITextFieldViewModeNever;
}
}
- (BOOL)becomeFirstResponder{
BOOL ret = YES ;
ret = [super becomeFirstResponder] ;
if( ret & ![self.text isEqualToString:#""]){
self.rightViewMode = UITextFieldViewModeAlways;
}else{
self.rightViewMode = UITextFieldViewModeNever;
}
return ret ;
}
- (BOOL)resignFirstResponder
{
BOOL ret = YES ;
ret = [super resignFirstResponder] ;
if( ret )
self.rightViewMode = UITextFieldViewModeNever;
return ret ;
}
- (void) clearText:(id)sender
{
self.text = #"";
self.rightViewMode = UITextFieldViewModeNever;
}
You shoud use : [self setRightViewMode:UITextFieldViewModeAlways];
Subclass UITextField and override -layoutSubviews.
- (void)layoutSubviews
{
[super layoutSubviews];
// HACK: There is an iOS bug where the right view is not displayed when there is text in the text field. Also, iOS adds and removes the rightView. This code adds the right view and uses hide-unhide instead.
UIView *rightView = [self rightView];
if (rightView != nil && [self clearButtonMode] == UITextFieldViewModeNever) {
BOOL showRightView;
BOOL isFirstResponder = [self isFirstResponder];
switch ([self rightViewMode]) {
case UITextFieldViewModeNever:
showRightView = FALSE;
break;
case UITextFieldViewModeWhileEditing:
showRightView = isFirstResponder;
break;
case UITextFieldViewModeUnlessEditing:
showRightView = !isFirstResponder;
break;
case UITextFieldViewModeAlways:
default:
showRightView = TRUE;
break;
}
showRightView = (showRightView && ![[self text] isEqualToString:#""]);
[rightView setFrame:[self rightViewRectForBounds:[self bounds]]];
[rightView setHidden:!showRightView];
[self addSubview:rightView];
}
}
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
UITextField *searchField = nil;
for (UIView *subview in controller.searchBar.subviews) {
DebugLog(#"%#",[subview description]);
if ([subview isKindOfClass:[UITextField class]]) {
searchField = (UITextField *)subview;
UIImageView *clearIconView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"ClearIcon.png"]];
searchField.rightView = clearIconView;
searchField.rightViewMode = UITextFieldViewModeAlways;
[clearIconView release];
break;
}
}
}
Simple code for solve this problem
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
textField.rightViewMode=UITextFieldViewModeAlways;
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
{
textField.rightViewMode=UITextFieldViewModeNever;
return YES;
}
I have written an open source class, STAResizingTextField, that allows you to specify custom clear text field button images.