Description
I am developing an application, using tableViews and selecting properties by putting a checkmark for each of selected items. It drove me crazy for 2 hours, because the code was correct, but I didn't see checkmark.
Problem
Actually the checkmark was being loaded correctly but I didn't notice, because the background was white and also the checkmark.
What I want to do
I want to change the color of the checkmark (possibly in Interface Builder) without using custom CheckMarks with different images on it.
Is that possible? If not possible why I am having white checkMark while the other one in another tableView is gray?
It's not possible if you are using accessoryType on cell.
If you want to be really flexible better create custom view instead:
UIImageView* tick = (UIImageView*) [cell.contentView viewWithTag:1];
if(tick == nil)
{
tick = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Archive"]];
[cell.contentView addSubview:tick];
tick.tag = 1;
tick.frame = CGRectMake(285.0f, 20.0f, tick.frame.size.width, tick.frame.size.height);
}
With that you can do whatever you like, use custom images, add background etc...
If you want code to look nicer it will be better if you extend UITableViewCell and create custom class with some methods and properties to control that. I just gave you code to a quick way to achieve what you want.
Related
I was going thru the tutorial here: http://pinkstone.co.uk/how-to-build-a-uicollectionview-in-ios-8/
And saw a part that looked great because it makes something simple, use of views to show color changes of selected/unselected items.-
(void)awakeFromNib {
// background color
UIView *bgView = [[UIView alloc]initWithFrame:self.bounds];
self.backgroundView = bgView;
self.backgroundView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"blue"]];
// selected background
UIView *selectedView = [[UIView alloc]initWithFrame:self.bounds];
self.selectedBackgroundView = selectedView;
self.selectedBackgroundView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"pink"]];
}
The author showed that this is a simple approach that eliminates the need to manage the state of the cells.
Q. I want to change the color using this method during the highlight process. However, didHighlightItemAtIndexPath is in the CollectionViewController and I'd like to have it use the same process.
Basically what it does is change from one color to another based on selected/unselected. I'd like to use the add a color to indicate the in between state of being highlighted/unhighlighted.
I checked all the methods that are in cell that use UIView, and there is nothing for highlighted/unhighlighted.
Any ideas on an approach that has the advantages of using cell methods? Can I call a custom method from the viewcontroller method and load a view there?
You might think of this as a "press and hold" that changes the color when it's being held.
A UIView wouldn't know anything about it's selected or unselected state since it's a very elemental component and not specific to controls that allow selection. The UICollectionViewCell does have a selected property though, so that would be the right place to change these characteristics. Looking at the docs it seems like either tapping into setSelected or selectedBackgroundView would give you a good opportunity to customize the L&F of selected cells. There's also a highlighted state in case you might also be looking for that.
I have a UITableViewController where a prototype cell named langCell is defined.
(see figure A)
Its accessory type is set to Checkmark which is supposed to be a blue checkmark appearing on the right side of the cell. (see figure B)
After having set this option, I did not see any "blue" checkmark appearing in the storyboard. I tried to change the background colour of the prototype cell to grey and the checkmark appeared back. (see figure C)
Why the default colour for checkmark is white? It is not visible.
How can I fix it?
You can show checkmark by two ways -
1) Set the cell's tintColor property as-
[cell setTintColor:[UIColor whiteColor]];
2) Set the accesoryView property of the cell to a UIImageView containing a checkmark of the correct color as-
UIImageView *checkMark = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"coloredCheckmark.png"]];
cell.accessoryView = checkMark;
[checkMark release];
I'm using a simple code to add some images to my UIScrollView. Also I've implemented another code to detect touches on each image.
Here is the code:
(void)handleSingleTap:(UIGestureRecognizer *)sender
{
int senderTagIs;
senderTagIs = sender.view.tag;
if (sender.view.layer.borderColor != [UIColor cyanColor].CGColor) {
sender.view.layer.borderColor = [UIColor cyanColor].CGColor;
UIImageView *showFullImage = (UIImageView *)[self.view viewWithTag:sender.view.tag+100];
[showFullImage setTag:sender.view.tag+200];
[self.view addSubview:showFullImage];
showFullImage.hidden = NO;
NSLog(#"Show tag is: %i", sender.view.tag);
}
else
{
sender.view.layer.borderColor = [UIColor whiteColor].CGColor;
UIImageView *hideFullImage = (UIImageView *)[self.view viewWithTag:sender.view.tag+200];
[hideFullImage setTag:sender.view.tag+100];
hideFullImage.hidden = YES;
NSLog(#"Hide tag is: %i", sender.view.tag);
}
}
The above code, sets the border color to cyan and show my small images from UIScrollView, in another UIImageView.
But my problem is, that I can't set the option to hide all images and set border color white for all images when one image is touched.
Ex: If I touch the first image, then the code will work, my big UIImageView will show touched image and touched image from UIScrollView will get the cyan color for border, so far so good.
Now, If I touch third image, my first image is shown, the color border is cyan, and so... I have to touch first image again to disable, but this is not what I want.
So, we've got a few things going on here. First, I'm assuming you're trying to show a collection of images in a scroll view with some custom padding to indicate selection around them. This sounds tailor make for using UICollectionView with a custom cell.
Absent further information, you're not resetting the old color. Either keep a reference to a selected image as a class variable or, assuming your image views are in a collection object like an NSArray, begin your method by iterating through the objects and resetting their view to an unselected state.
If you just need to hack together a solution, the second option should work. I really recommend using UICollectionView. It's a bit more work in the beginning, especially if you're not experienced with it, but it's well worth learning. Here's a good tutorial on UICollectionView.
In short, I need to restore the default backgroundView for a UITableViewStyleGrouped cell.
cell.backgroundView = ??;
The long story:
I have a grouped tableview with some cells. For every cell the user needs to select some value or do some input. After that he can proceed to the next ViewController by touching a "next" button.
Anyway, to indicate to the user that he missed something, I display a nice red border around the cell with the wrong/missing user input. I do that by setting the backgroudView of the cell with a custom image like this:
cell.backgroundView = myErrorIndicatingImageView;
The cell now looks like this (screenshot, ignore the stars and label)
So far so good, this works like a charm. But after the user corrects the input I want to remove my red border background image and just show the original background again. The original background looks like this (screenshot):
And this seems to be a problem.
I tried several things
// try by setting the background to nil
cell.backgroundView = nil;
this removes the background completely and I'm lost with a cell without background.
// try it with addSubview and later remove the subview again
[cell.backgroundView addSubview:myErrorIndicatingImageView];
this does nothing. The myErrorIndicatingImageView is not visible. Even a [cell.backgroundView bringSubviewToFront:myErrorIndicatingImageView] does not help.
Right now the only solution I have is to create a new UITableViewCell for every single call to cellForRowAtIndexPath. This works but is just bad code and ignores completely the technique to reuse cells.
There must be a simpler solution...something like
cell.backgroundView = [self.tableView getDefaultBackgroundView];
what about trying this:
cell.backgroundView = [[UIView alloc] initWithFrame:cell.backgroundView.frame];
Or you can make the background view as a UIImageView and set 2 images in problem and fixed
Assuming you are doing this with a custom table cell class, save the original backgroundView in some ivar, then apply the new background. When you want to reset the background, set the backgroundView back to the original, saved background view.
I'm using the new UIAppearance API in iOS 5 to style a UISegmentedControl with custom graphics. I need to be able to set some segments to be disabled at times during execution, but the UIAppearance methods don't seem to allow me to set a divider image for the UIControlStateDisabled state.
I'm calling:
[[UISegmentedControl appearance] setDividerImage:disabledSelectedImage
forLeftSegmentState:UIControlStateDisabled
rightSegmentState:UIControlStateSelected
barMetrics:UIBarMetricsDefault];
where disabledSelectedImage is a resizable image from this resource:
Yet when I set the left segment to be disabled ([UISegmentedControl setEnabled:forSegmentAtIndex:]), the result is this:
You can clearly see that the UISegmentedControl has defaulted to use the UIControlStateNormal-UIControlStateNormal divider image.
It seems perfectly happy for me to set a background image using UIControlStateDisabled
[[UISegmentedControl appearance] setBackgroundImage:disabledImage
forState:UIControlStateDisabled
barMetrics:UIBarMetricsDefault];
(and respects the image I supply while in the disabled state) but not a divider image. Has anyone come across this or found a solution?
I've decided that this must be an iOS bug and have filed a radar with Apple. My solution to the problem for now is to remove segments, rather than disabling them.
A bit of an ugly workaround but i managed to fix it with the following until apple fixes it itself.
First you need to subclass UISegmentedControl and add the following:
#implementation MJSegmentedControl
- (void)layoutSubviews
{
[super layoutSubviews];
NSInteger cachedIndex = self.selectedSegmentIndex;
self.selectedSegmentIndex = 0;
self.selectedSegmentIndex = cachedIndex;
}
#end
I haven't had a need to use the appearance controls of iOS 5 yet but if all else fails you could add the resizable image as a child of the segmented control to cover up the ugliness. It's a hack, but it may work and will be relatively forwards-compatibile. Just be certain to set the autosizing masks appropriately.
I had the same issue and it really seems to be a bug. However I've found a solution (a workaround).
I've used XIB file with a controller. In XIB file segmented control was just placed and all of the customisations were done in -viewDidLoad method.
Then I've created a UIView subclass which represented entire view in the XIB. It made possible moving all view customisation code to the -awakeFromNib method of this UIView subclass. After moving this code the divider images were set properly.
As suggested by Fernando in this thread:
Customizing UISegmentedControl in iOS 5
You can try to dispatch your UISegmentedControl settings on the main queue via:
dispatch_async(dispatch_get_main_queue(),^{
// disable part of the segmented control
[self.eventScopeSegmentedControl setEnabled:NO forSegmentAtIndex:2];
});
I did this in viewDidLoad and it worked fine for a while but when my app is really busy at startup, this doesn't always work. I'm guessing there's a race condition that may still revert any settings you made when the appearance proxy goes to work.
I added another ugly hack to make this call in viewWillAppear (after the call to super:viewWillAppear) with a flag (set from viewWillLoad) to ensure this only runs once.
There is actually a pretty simple way to get this done. The current behavior is obviously a bug so this is not an ideal solution but simply a workaround that works beautifully. Namely, use an additional UIView as a "disabled visual cue".
The general steps:
Add a UIView as a sibling to the UISegmentedControl. Ensure the UIView is in front of the UISegmentedControl
Apply the desired color and a transparency to the UIView to match your app skin
Move the UIView to be exactly on top of the UISegmentedControl
Shape the UIView to have the exact size top of the UISegmentedControl
Apply a rounded corner to the UIView to mirror the exact shape of the UISegmentedControl
When the UISegmentedControl is supposed to be disabled, simply show the UIView and disable the user interaction on the UISegmentedControl.
When the UISegmentedControl is supposed to be enabled, simply hide the UIView and enable the user interaction on the UISegmentedControl.
In both cases do not change the UISegmentedControl.enabled property.
Note that it seems like a lot of steps but all of this can be coded in so to add support for disabling your custom UISegmentedControl becomes pretty much a 1 liner after you add this to a configure segmented control method.
Here is how my custom segmented control looks when applying this solution:
Enabled Segmented Control
"Disabled" Segmented Control
Here are some code snippets of interest:
Shape the UIView to match the UISegementedControl (load time configuration)
UISegmentedControl* segmentedControl = ...
//Segmented Control disabled visual cue view
UIView* view = ...
//Step #2
view.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.6];
//Step #3 and #4
view.frame = segmentedControl.frame;
//Step #5
view.layer.cornerRadius = 5
view.clipsToBounds = YES;
//Ensure this is disabled by default
view.userInteractionEnabled = NO;
Enable/"Disable" UISegementedControl (runtime state change)
BOOL segmentedControlEnabled = ...
if(segmentedControlEnabled) {
segmentedControl.userInteractionEnabled = YES;
view.hidden = YES;
} else {
segmentedControl.userInteractionEnabled = NO;
view.hidden = NO;
}
That's it.
-