UITextView highlightedTextColor or similar option? - iphone

I have a custom UITableViewCell with a UILabel and a UITextView in it.
I want the text for both of these to appear white when the user highlights the UITableViewCell. It's obviously very simple to set the highlightedTextColor of the UILabel, but the UITextView doesn't seem to have any similar type of property. Am I going to have to manually change the color of the UITextView whenever the cell becomes highlighted/unhighlighted or is there an easier way of accomplishing this?
Thanks!

Found it and it was a lot easier than I thought. Just need to use the UITableViewCell setHighlighted method.
- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated {
[super setHighlighted:highlighted animated:animated];
if (highlighted) {
[self.myTextView setTextColor:[UIColor whiteColor]];
} else {
[self.myTextView setTextColor:[UIColor blackColor]];
}
}

The solution posted by the author is half right for my situation. Need to keep in mind that the following events happen:
press down --> setHighlighted:YES animated: is called
press up --> setHighlighted:NO animated is called
set selection --> setSelected:YES animated is called
Knowing this, and depending on how you want the TableCell to look when highighted vs when selected will determine if you need to implement setHighlighted:animated:, setSelected:animated: or both methods.
For the look I want, I need to implement both methods.

Related

UIImageView still visible after hiding/removing from superview

i hope you will find a solution for my problem, cause i don't have any ideas anymore.
I have a tableview, which has several cells. some cells have another view as subview on their contentView.
This additional view has 2 subviews: 1 UIImageView and 1 UILabel.
Now when i tap an UIButton the UIImageView should be hidden/removed and the UILabel changes it's textColor to white(black before).
The UILabel changes it's textColor but the UIImageView is still visible, even after removing the UIImageView from it's superview.
The Code looks like this.
_adsc_dot_view is the UIImageView
_adsc_text_label is the UILabel
- (void)mc_set_selected:(BOOL)selected {
if (selected) {
_adsc_dot_view.hidden = YES;
_adsc_text_label.textColor = [UIColor whiteColor];
}
else {
_adsc_dot_view.hidden = NO;
_adsc_text_label.textColor = [UIColor blackColor];
}
}
Some check you might find useful for this issue:
1) make sure you create once your UIImageView which referenced as _adsc_dot_view
2) do a debug, mark mc_set_selected with a breakpoint and in the log check the view hierarchy, whether you have the needed number of UIImageView and not more
po [[UIWindow keyWindow] recursiveDescription]
or check this advanced SO answer: I need to inspect the view hierarchy on an iPhone program
3) if you use Interface Builder make sure you have proper type (and not UIImage) and proper reference
You are using UITableView and you add UIImageView and UILabel as a subview in UITableViewCell. So, I think you should reload UITabeView using [self.tableView reloadData]; or [YourTableName reloadData]; after your hide and show UIImageView method. Otherwise you should hide and show UIImageView using UIImageView tag or using UITableViewCell index path.
is the target device on iOS 7? If yes then do try to layoutsubviews of the cell. I had a similar issue where the cell wasn't refreshing on ios 7.
Just reload table view cell after Remove/Hide ImageView.

Change background Color of custom UITableViewCell once clicked not working well

I want to update the background color of a cell in my tableview once the user clicks it.
The thing is if i disable the selection style by calling:
[code]
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
[/code]
The color changes as i want but there is no visual feedback to the user of the selection before the color change, which is not desirable for my application.
When i remove that line and change the color like this only in an IBAction function:
[code]
[cell setBackgroundColor:[UIColor lightGrayColor]];
[/code]
I end up with having a squared rectangle in the middle of the cell with the original colour before selection, and borders of the cell with the color i want to set. If i call my IBAction function twice the background color is set properly.
I am not sure whats the cause or how to resolve it.
Please bare in mind that i do all my cell setup (setting text, background color, text shadow, etc) in cellForRowAtIndexPath. I tried the other way of doing it in willDisplayCell but still with no luck.
Hope some one can spot some light on the matter :)
Cheers
AF
I managed to find a partial solution to my problem and here it is in case others stumble over the same issue:
// My cell disabling function (i use the cell as a button hence the postfix Btn)
-(void) disableLoginBtn
{
loginBtnPtr.userInteractionEnabled = NO;
[loginBtnPtr setBackgroundColor:[UIColor lightGrayColor]];
[loginBtnPtr.textLabel setShadowColor: [UIColor whiteColor]];
}
-(void) someFunction
{
...
// loginBtnPtr a pointer to the cell in my table i want to change its background color.
// NOTE: If i include this setSelectionStyle function inside my disableBtn function the highlighting will be disabled all together and you wont get the effect you may be after.
[loginBtnPtr setSelectionStyle:UITableViewCellSelectionStyleNone];
[self disableLoginBtn];
}
-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath
{
...
[tableView deselectRowAtIndexPath:indexPath animated:YES];
// Make sure you reset the selection color to the one you are using, in my case blue. Otherwise the highlighting will be disabled for that cell through out the application
[loginBtnPtr setSelectionStyle:UITableViewCellSelectionStyleBlue];
}
Hope it helps
AF

Touch event in UIImageView

How can I determine what UIImageView I touch in the screen? Like for example, I added 10x10 tiled UIImageView in a UIView. Now in touchesBegan, how can I know the image I touch in screen? Should I use hitTest method in this implementation?
Thanks.
I generally find the easiest way is to subclass UIImageView and add my own touch event handlers.
In fact what I have often done is create one subclass of UIImageView who's sole purpose is to allow another class to act as next responder. That way I don't have to subclass it for every situation. That's only worth doing if you need a number of these views and you weren't subclassing them anyway.
this question was asked many times here. try to use search next time. I usually use UIButtons with custom style to do what you want. such a variant gives you standard methods to catch touches without subclassing.
To follow up on the UIButton suggestion, here's a snippet of what I have done for a UIButton that is rendered with a UIImage.
This was for tracking the specific UIButton image type that got touched within a UITableViewCell, and it passes along the row and section in which this UIButton was placed:
UIButton *_infoButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 30, 30)];
[_infoButton setImage:[UIImage imageNamed:#"Info.png"] forState:UIControlStateNormal];
[_infoButton setTitle:[NSString stringWithFormat:#"%d:%d", indexPath.section, indexPath.row] forState:UIControlStateReserved];
[_infoButton addTarget:self action:#selector(touchedDetailedInfoButton:) forControlEvents:UIControlEventTouchDown];
// ...
[ _infoButton release];
And here's the associated method for recovering the title and doing something interesting with it:
- (void) touchedDetailedInfoButton:(NSString *)title {
unsigned int _section, _row;
const char * _indexPathCharPtr = [title cStringUsingEncoding:NSUTF8StringEncoding];
sscanf(_indexPathCharPtr, "%d:%d", &_section, &_row);
NSUInteger _path[2] = {_section, _row};
NSIndexPath *_touchedIndexPath = [[NSIndexPath alloc] initWithIndexes:_path length:2];
[self doSomethingInterestingWithIndexPath:_touchedIndexPath];
[_touchedIndexPath release];
}
There's probably an easier way to go about this, so hopefully someone else comes along and offers an alternative (other than subclassing UIImageView, which is a perfectly valid option, as well).

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)];

How do I change the color of the side Alphabet in an indexed UITableView?

I have a table view with an alphabetical index and am using the side alphabet to get through the list quickly. For those not familiar, that uses this:
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
My problem is that my application has just been skinned black. And so now it's hard to see the alphabet letters on the side.
I can't figure out how to change the color of the alphabet. I'd like it to be 'white' if at all possible.
if your minimum iOS version is newer than 6.0, you can use sectionIndexColor property of UITableView.
The color to use for the table view’s index text.
#property(nonatomic, retain) UIColor *sectionIndexColor
Discussion:
Table views can display an index along the side of the view, making it
easier for users to navigate the contents of the table quickly. This
property specifies the color to use for text displayed in this region.
Update date 2014.1.13
I find an open source third party library:GDIIndexBar to help custom the index appearance.
From what I can tell unfortunately it is not possible to customize the color of the text displayed in the index, the closest I've been able to come is being able to modify the background color and the font of the index.
There is some code in the iPhone Developers cookbook by Erica Sadun which shows how to access the UITableViewIndex view (an undocumented class). You can find the reference to it on page 175 of the book if you have it. Which gives access to the background color and the font. You can see an unofficial document related to this class here.
WARNING This is undocumented use of an undocumented class so you need to be cautious about using it.
Here is a code snippet from the cookbook with minor modifications:
- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath {
for(UIView *view in [tv subviews])
{
if([[[view class] description] isEqualToString:#"UITableViewIndex"])
{
[view setBackgroundColor:[UIColor whiteColor]];
[view setFont:[UIFont systemFontOfSize:14]];
}
}
//rest of cellForRow handling...
}
This illustrates how you can access and the UITableViewIndex view and modify it in some aspects. It looks like the view doesn't have any subviews so it is likely doing some custom drawing with the array of index titles.
It's not perfect but hopefully it helps a little.
Paul
This can be easily changed in the interface builder for the UITableView - No need to use undocumented classes?
See screenshot below, as you can see the font colour and the background colour can be changed too. Job's a good'n!
For iOS7 or Higher:
self.tableView.sectionIndexColor = [UIColor whiteColor];
self.tableView.sectionIndexBackgroundColor = [UIColor clearColor];
I was having the same problem and just found out a way of doing this, though this is using undocumented classes and methods so think one extra time before trying to upload it to the App Store.
I should say that i've only tried this with iOS5 so I don't know if it will work for previous versions.
I borrowed and modified the Erica Saunders cookbook example so that it now changes the text color to red:
- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath {
for(UIView *view in [tv subviews])
{
if([[[view class] description] isEqualToString:#"UITableViewIndex"])
{
[view performSelector:#selector(setIndexColor:) withObject:[UIColor redColor]];
}
}
//rest of cellForRow handling...
}
We have successfully used the following code:
for(UIView *view in [tableView subviews]) {
if([view respondsToSelector:#selector(setIndexColor:)]) {
[view performSelector:#selector(setIndexColor:) withObject:[UIColor whiteColor]];
}
}
which works fine - it's very similar to Mooglas answer - but refrains from using the word "UITableViewIndex".
You can set the tint color for the tableView.
[[UITableView appearance] setTintColor:[UIColor purpleColor]];
Swift 5:
tableView.sectionIndexColor = .red
tableView.sectionIndexBackgroundColor = .clear
There is a way to change the color of the index Alphabet.
In your header file, declare your UITableView as a property:
#property (weak, nonatomic) IBOutlet UITableView *mainTable;
Then in your implementation file's viewDidAppear, use the following line:
//Change the color of the UITableView index color
_mainTable.sectionIndexColor = [UIColor blackColor];
Here's the best solution I've found to adjust the background colour of the index bar on the side. It works in iOS7 and probably iOS6.
Add this to your viewDidLoad
if ([_tableView respondsToSelector:#selector(setSectionIndexColor:)]) {
_tableView.sectionIndexBackgroundColor = [UIColor clearColor];
_tableView.sectionIndexTrackingBackgroundColor = [UIColor whiteColor];
}
The first one is the default colour, the second is the background colour when you are scrolling.
Make a mutable array to contain the alternate title label
In
-(NSArray * )sectionIndexTitlesForTableView:(UITableView * )tableView
return an array of #" " where the number of spaces between the quotes determines the width of the hi-lighted scroller.
Have "sectionIndexTitlesForTableView" call an update label function.
In that function remove all the labels in the array you created earlier from their superviews Then create and add however many labels are needed. Then add them to the table's superview.
These are the lines required to place the labels in the right place.
rect.origin.x = table.frame.origin.x+table.frame.size.width-rect.size.width-2;
rect.origin.y = 5+table.frame.origin.y+counter *(280-rect.size.height-([customIndexLabels count]-1))/([customIndexLabels count]-1);
if ([customIndexLabels lastObject]==thisLabel)
{
rect.origin.y-=10;
}
Hope that helps. It's not perfect I just don't care enough to fix it myself
The main problem is that the spacing of the last label is not uniform.
Swift edition for undocumented font change:
extension NSObject {
class func objectClassName() -> String {
let classLongName = reflect(self.self).summary;
let tokens = classLongName.componentsSeparatedByString(".")
if let typeName = tokens.last {
return typeName
}
return NSStringFromClass(self.dynamicType)
}
}
func changeSectionIndexFont(tableView: UITableView) -> Void {
let realSubviews = tableView.subviews as! [UIView]
for subview in realSubviews {
if subview.dynamicType.objectClassName() == "UITableViewIndex" {
subview.setValue(UIFont(name: "OpenSans", size: 10), forKey: "font")
}
}
}