What's wrong with my Checkbox drawing? - iphone

I built a UIButton subclass that is a very basic checkbox. Everything is working (e.g. I'm getting the events I expect, the drawRect method is called when I expect, etc), but my image isn't drawing. I've checked that my image is not nil and that my images are different.
Code:
-(void)awakeFromNib {
[super awakeFromNib];
[self addTarget:self action:#selector(buttonClick) forControlEvents:UIControlEventTouchUpInside];
self.state=YES;
}
-(void) buttonClick {
self.state = !self.state;
[self setNeedsDisplay];
}
-(void)drawRect:(CGRect)rect {
UIImage *img = nil;
if (self.state) {
img = [self backgroundImageForState:UIControlStateSelected];
}
else {
img = [self backgroundImageForState:UIControlStateNormal];
}
[img drawInRect:rect];
}
Checking the value of 'img' before it is drawn:
Printing description of img:
<UIImage: 0x52a710>
(gdb) continue
Printing description of img:
<UIImage: 0x52a5d0>
The background images are being set in the NIB. If I change the selected state in IB, I see the proper image show up. I'm also getting a valid image back from the call (which I don't if I try to get imageForState, which is not set in the NIB).
The reason for the subclass is that I need a checkbox. UIButton doesn't do that and UISwitch is hideously ugly for all but the most utilitarian views.
Thoughts?
Thanks.
tj
Edit: Added all the code for the subclass

Where are you setting backgroundImageForState? Are you sure it's the correct image? iPhone OS might be giving you a transparent (blank) image as a default.
Second, I wouldn't use the passed-in "rect" param to draw the image. That's just telling you the area it wants you to redraw, not necessarily anything else. Instead use
CGRectMake(0, 0, img.size.width, img.size.height)
or something similar.
Finally, why are you doing custom drawing? I've done something very similar, and you absolutely don't need to subclass and implement drawRect. UIButton has an extremely rich set of options built in for images, including "highlighted" and "selected" images that will draw automatically with user interaction. Let us know what you need to accomplish.

Just because the UIImage isn't nil doesn't mean it contains image data.
Check the case of your file name.
I've done this several times:
#"CheckBox.png" and #"checkbox.png" are 2 different names to the iPhone.
It seems you may be doing a little premature optimizing as well.
I wouldn't dive into drawRect: for my first option.
Use a UIButton subclass (you only need to subclass to track state). Set the button up in IB and position it where you want it. Connect the button to the method below and simply swap the images on the click:
- (IBAction)toggle:(id)sender{
MyButtonSubClass *aButton = (MyButtonSubClass*)sender;
[aButton toggleChecked];
if(aButton.checked)
[aButton setImage:checkedImage forState:UIControlStateNormal];
else
[aButton setImage:uncheckedImage forState:UIControlStateNormal];
}
optionally you can not subclass UIButton and track state in the controller

Related

Image in reused cell in a TableView not being cleared from ImageVIew

I have a Tableview containing cells with images, however the cells that are reused still contain the image from the previous cell that is being reused until the new image is downloaded and set.
I have tried setting the image to nil. (imageV is a subclass of HJManagedImageV, source can be found here: HJManagedImageV
[cell.imageV setImage:nil];
the setter
-(void)setImage:(UIImage *)theImage{
if (theImage==image) {
//when the same image is on the screen multiple times, an image that is alredy set might be set again with the same image.
return;
}
[theImage retain];
[image release];
image = theImage;
[imageView removeFromSuperview];
self.imageView = [[[UIImageView alloc] initWithImage:theImage] autorelease];
[self addSubview:imageView];
[imageView setNeedsLayout];
[self setNeedsLayout];
[loadingWheel stopAnimating];
[loadingWheel removeFromSuperview];
self.loadingWheel = nil;
self.hidden=NO;
if (image!=nil) {
[callbackOnSetImage managedImageSet:self];
}
}
I have a workaround for by setting imageV to hidden but then I lose the loading spinner and I'd really like to know why setting it to nil isn't working.
Anyone have any ideas, cause I'm all out of them. Or am I missing a step somewhere.
Are the cells a subclass of UITableViewCell? If yes, I would try to implement the method prepareForReuse and see if can solve the problem there.
Hope this helps =)
Don't set it to nil, nor hide it.
We use a similar class and what we do for such cases is to set a start image to be displayed until the new image loads.
So in your case you could simply set the image as a blank jpg/png inside your bundle instead of nil

how to add subviews from array to a uiview?

i have my subviews stored in an array...what i want is to place these subviews to my main view from array....
for(int i=0;i<[imageViewArray count];i++)
{
NSLog(#" image array count is %d",[imageViewArray count]);
// countlayers= countlayers+1;
// [canvasView insertSubview:[imageViewArray objectAtIndex:i] atIndex:countlayers];
[canvasView addSubview:[imageViewArray objectAtIndex:i]];
}
can you tell me what i am doing wrong
If imageViewArray really contains initialized views, and if those views already have correct frame attributes, you're doing nothing wrong (even though your code could be more elegant).
Also, of course, we have to make sure that canvasView is indeed initialized and visible on the screen. Try setting its backgroundColor to something noticeable:
canvasView.backgroundColor = [UIColor greenColor];
Once you are sure the canvasView is actually being displayed, I would suggest using fast enumeration, which makes going through the array nicer, and logging your new subviews to make sure their frames are like you want them.
for (UIView *imageView in imageViewArray) //this is fast enumeration. You can get it through code completion by typing forin
{
NSLog(#"%#", imageView); //let's take a look at the imageView. What is its frame?
[canvasView addSubview:imageView];
}
Used enumeration to add images on your canvas View using imageViewArray and probably you are also missing with the setting frame of the images.
for (UIImageView *imageView in imageViewArray) //enumeration.
{
//let's set frame for image view before adding to canvasView
[imageView setFrame:CGRectMake(x,y,w,h)];
//Also make sure imageView has image or not
if(imageView.image)
[canvasView addSubview:imageView];
}

UIButton only responds in a small area

I'm trying to add a UIButton to a UIView, but am having some trouble with getting it to respond to touches.
I have a method which returns UIButtons after I provide it with a tag:
- (UIButton*)niceSizeButtonWithTag:(int)tag {
UIButton * aButton = [UIButton buttonWithType:UIButtonTypeCustom];
[aButton setTag:tag];
[aButton addTarget:self action:#selector(buttonWasTapped:) forControlEvents:UIControlEventTouchUpInside];
CGRect newFrame = aButton.frame;
newFrame.size.width = 44;
newFrame.size.height = 44;
[aButton setFrame:newFrame];
return aButton;
}
As you can see I'm creating a new button and increasing the size.
I use this in the following way:
UIButton * anotherButton = [self niceSizeButtonWithTag:1];
[anotherButton setImage:[UIImage imageNamed:#"image" withExtension:#"png"] forState:UIControlStateNormal];
[anotherButton setCenter:CGPointMake(middleOfView)];
[aView addSubview:anotherButton];
I create a lot of buttons like this, hence the reason for the method.
The buttons are always created and added to the subview perfectly. I can see the image and they're in the correct position. The problem is that they only respond to touches in a tiny strip.
In this attached image,
alt text http://web1.twitpic.com/img/107755085-5bffdcb66beb6674d01bb951094b0e55.4c017948-full.png
The yellow shows the whole frame of the button,
The red shows the area that will respond to touches.
The grey shows a section of the view the button is added to.
If anyone could shed some light on why this is happening, it would be really useful.
UPDATE:
I should probably mention I'm trying to add this button to a UIView which is a subview of a UITableViewCell.
UPDATE 2:
Adding it directly to the UITableViewCell works, adding it to the UIView on the UITableViewCell is causing the error.
FINAL UPDATE
The problem turned out to be that I was sending the view containing the button to the back of the subviews on the UITableViewCell. Getting rid of the sendSubviewToBack: call fixed it.
Do you have any other views added to this containing view after you add the button? try setting some of your view's background color to blueColor, redColor and other colors to better see what the stack of views in your app is like. Then you should be easily able to see if there is some sort of view blocking the button.

How to Customize UISlider?

I understand how you can have a minimum track and maximum track image, and how it can be stretchable. However, for my needs, that might not be enough control.
I have a situation where on the left hand side (minimum track) I need to display two different colors, based on data. The left hand side actually represents two pieces of data, but yet there still exists only a single thumb between minimum and maximum.
so how can i do this???
Any sample code??
i actually want like this
photo link
On left hand side it is of grinish color but when it exceeds the thumb image it becomes red..
In your .h file
IBOutlet UISlider *slide;
in your .m file
UIImage *minImage = [UIImage imageNamed:#"unselected.png"];
UIImage *maxImage = [UIImage imageNamed:#"selected.png"];
UIImage *tumbImage= [UIImage imageNamed:#"thumb.png"];
minImage=[minImage stretchableImageWithLeftCapWidth:10.0 topCapHeight:0.0];
maxImage=[maxImage stretchableImageWithLeftCapWidth:10.0 topCapHeight:0.0];
[slide setMinimumTrackImage:minImage forState:UIControlStateNormal];
unselected.png and selected.png are the images that act as bar and thumb.png which slide over the bar.
Put your image swapping code in your slider value-reading method, which is usually:
-(IBAction)sliderChanged:(id)sender; {}
Swap your custom green image with a custom red image whenever your slider value reaches some predefined value. See example below.
// Switches the -thumbImage between an ivar named highImage and lowImage
// when the slider passes the halfway point
if (sliderValue > 0.5) {
[self updateSliderThumbWithImage:self.highImage];
} else {
[self updateSliderThumbWithImage:self.lowImage];
}
define the slider image update method like this:
-(void)updateSliderThumbWithImage:(UIImage *)image;
{
[self.slider setThumbImage:image forState:UIControlStateNormal];
[self.slider setThumbImage:image forState:UIControlStateHighlighted];
}
// You have to set thumb images for both states
// or your image will vanish when user slides it.
// Not sure if you have to do the same with the track image, though.
Hope this helps somebody.
I'm not sure if I can visualize what you need (any chance you can post a sketch?), but do a search for UISlider and you can find some pretty creative uses. Otherwise you can create your own custom UIControl.
(source: texlege.com)

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).