how can I add a UISwitch to a specific UIScrollView? As I guess it can be done with a tag, but I am having difficulties.
EDIT: The problem was solved in the usual way, lol
My example code with UIScrollView and UISwitch:
#implementation NSPage {
UIScrollView *scrolled;
UISwitch *switchPage;
NSInteger *keyS;
}
NSPage *page = [[NSPage alloc]init];
Here i am creating a UIScrollView and UISwitch:
-(id)initPage:(NSString *)titleScroll keyScroll:(NSInteger)keyScroll_ {
keyS = keyScroll_;
scrolled = [[UIScrollView alloc]initWithFrame:CGRectMake(0, 0, 180, 110)];
scrolled.tag = keyS;
scrolled.backgroundColor = [UIColor grayColor];
[window addSubview:scrolled];
}
//get scroll tag
-(NSInteger)getScrollKey {
return scrolled.tag = keyS;
}
//UISwitch
-(id)initSwitch:(NSString *)title_ keySwitch:(NSInteger)keySwitch_ {
scrollSwitch += 40;
switch_ = [[UISwitch alloc]initWithFrame:CGRectMake(15, scrollSwitch - 40, 40, 40)];
switch_.tag = keySwitch_;
if([self getScrollKey] == switch_.tag) {
[scrolled addSubview:switch_];
}
}
#end
Everything seemed to be fine, but when I add a scrolls and switches, then my UISwitch is not displayed:
page = [[NSPage alloc]initPage:#"test page" keyScroll:256];
page = [[NSPage alloc]initSwitch:#"test" keySwitch:256];
What could be my mistake, how can I add a UISwitch to a specific UIScrollView? I'm a beginner, Thanks for the help anyway
if([self getScrollKey] == switch_.tag) {
This line does nothing take it out
I add a UITexfield programatically on my view. When I use keyboard and hit return button texfield cleared automatically and I don't want this.
Here is my code;
UITextField * eventListSeractTextField = [[UITextField alloc]initWithFrame:CGRectMake(headerView.frame.size.width-112,4, 110, 20)];
eventListSeractTextField.backgroundColor=[UIColor whiteColor];
eventListSeractTextField.layer.cornerRadius=3.0f;
eventListSeractTextField.tag=101;
eventListSeractTextField.delegate=self;
eventListSeractTextField.autocapitalizationType=UITextAutocapitalizationTypeNone;
eventListSeractTextField.autocorrectionType=UITextAutocorrectionTypeNo;
eventListSeractTextField.spellCheckingType=UITextSpellCheckingTypeNo;
eventListSeractTextField.clearButtonMode = UITextFieldViewModeAlways;
eventListSeractTextField.returnKeyType = UIReturnKeySearch;
eventListSeractTextField.placeholder=#"Search";
eventListSeractTextField.clearsOnBeginEditing=false;
[eventListSeractTextField setClearsOnBeginEditing:false];
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
switch (textField.tag) {
case 101:
[textField resignFirstResponder];
return false;
break;
default:
return YES;
}
return YES;
}
How can I avoid this?
My guess is that you are recreating the textview each time since you did it in code. Check where you are calling this line of code:
UITextField * eventListSeractTextField = [[UITextField alloc]initWithFrame:CGRectMake(headerView.frame.size.width-112,4, 110, 20)];
You should only need to create the textView once in viewDidLoad. The easier way would be to do it in storyboard if you are familiar with storyboard
UPDATE:
Even UIBarButtonItems do not respond to state change, visually.
The scenario:
I have a UIButton of type UIButtonTypeSystem initialized as below:
sendButton = [UIButton buttonWithType:UIButtonTypeSystem];
sendButton.backgroundColor = [UIColor clearColor];
[sendButton setTintColor:UIColorFromRGB(SEND_BUTTON_COLOR)];
sendButton.opaque = YES;
sendButton.clearsContextBeforeDrawing = NO;
sendButton.frame = CGRectMake(275, 6, 50, 35);
UIImage* sendImage = [UIImage imageNamed:#"toilet_paper"];
[sendButton setImage:[UIImage imageWithCGImage:sendImage.CGImage scale:sendImage.scale orientation:UIImageOrientationLeft]
forState:UIControlStateNormal];
sendButton.enabled = NO;
[sendButton addTarget:self action:#selector(post) forControlEvents:UIControlEventTouchUpInside];
The Purpose:
It is associated with a UITextView such that it is set to enabled if there is some text in the textView AND my host is available (checked through Reachability) and it's enabled property is changed in textViewDidChange: delegate method with the following:
sendButton.enabled = [APP_DELEGATE hostAvailable] && [myTextView.text stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#" \n"]].length > 0;
According to this enabled state, the button must toggle between SEND_BUTTON_COLOR (enabled = YES) and grayColor (enabled = NO).
The Problem:
Up until now, the code used to work fine. It was gray when there was no text in the textView and it became SEND_BUTTON_COLOR as soon as there was some text in the textView. However, out of the blue, it has stopped this behaviour. What happens is, it stays gray all the time irrespective of the content of the textView. Once it is pressed, it becomes SEND_BUTTON_COLOR and stays that way, again irrespective of the textView text.
How do I regain the behaviour of the button I used to have on my UIButton?
You have to set your button's tint color again in the textViewDidChange delegate method.
In your delegate where you are setting the enabled state:
sendButton.enabled = [APP_DELEGATE hostAvailable] && [myTextView.text stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#" \n"]].length > 0;
if(sendButton.enabled){
[sendButton setTintColor:UIColorFromRGB(SEND_BUTTON_COLOR)];
}
else{
//Set Another Color For Disabled State
}
As it appears, the problem was on my part. I had subclassed UIButton in the .m file of a different VC (not imported by the VC in question, or any other VCs it had imported):
#implementation UIButton (Border)
- (void) setEnabled:(BOOL)enabled {
if (enabled) {
self.layer.borderColor = UIColorFromRGB(0x888888).CGColor;
} else {
self.layer.borderColor = UIColorFromRGB(0xdddddd).CGColor;
}
[super setEnabled:enabled];
[self setNeedsDisplay];
}
#end
Somehow, this interfered with my button. After weeks of further subclassing, changing images, changing titles, etc, I was able to diagnose the issue (accidentally) by jumping to definition (CMD + Click) of the enabled method, and it took me straight to the source of the issue (the subclass code). Commented it out, and voila. Things were back to normal.
I hope this helps someone in the future who faces the same issue (or makes the same mistake I did).
So I have an app that behaves like a photo gallery and I'm implementing the ability for the user to delete the images. Here is the setup: I have 9 UIImageViews, imageView, imageView2, etc. I also have an "Edit" button, and a tapGesture action method. I dragged a Tap Gesture Recognizer over onto my view in IB, and attached it to each one of the UIImageViews. I also attached the tapGesture action method to each of the UIImageViews. Ideally, I would like the method to only become active when the "Edit" button is pressed. When the user taps Edit, then taps on the picture they want to delete, I would like a UIAlertView to appear, asking if they are sure they want to delete it. Here is the code I'm using:
- (IBAction)editButtonPressed:(id)sender {
editButton.hidden = YES;
backToGalleryButton.hidden = NO;
tapToDeleteLabel.hidden = NO;
}
- (IBAction)tapGesture:(UITapGestureRecognizer*)gesture
{
UIAlertView *deleteAlertView = [[UIAlertView alloc] initWithTitle:#"Delete"
message:#"Are you sure you want to delete this photo?"
delegate:self
cancelButtonTitle:#"No"
otherButtonTitles:#"Yes", nil];
[deleteAlertView show];
if (buttonIndex != [alertView cancelButtonIndex]) {
UIImageView *view = [self.UIImageView];
if (view) {
[self.array removeObject:view];
}
CGPoint tapLocation = [gesture locationInView: self.view];
for (UIImageView *imageView in self.view.subviews) {
if (CGRectContainsPoint(self.UIImageView.frame, tapLocation)) {
((UIImageView *)[self.view]).image =nil;
}
}
[self.user setObject:self.array forKey:#"images"];
}
}
This code is obviously riddled with errors:
"Use of undeclared identifier button index" on this line: if (buttonIndex != [alertView cancelButtonIndex])
"Property UIImageView not found on object of type PhotoViewController" on this line UIImageView *view = [self.UIImageView];
And "Expected identifier" on this line ((UIImageView *)[self.view]).image =nil;
I'm very new to programming, and I'm surprised that I even made it this far. So, I'm just trying to figure out how I need to edit my code so that the errors go away, and that it can be used whenever one of the 9 image views is tapped, and also so that this method only fires when the Edit button is pushed first. I was using tags earlier, and it worked great, but I save the images via NSData, so I can't use tags anymore. Any help is much appreciated, thanks!
First, you don't want to attach the tap gesture to the image views. Also, if you are going to have more than 9 images, you may want a scroll view, or handle scrolling separately. First, remove that gesture recognizer and all its connections.
Next, determine what type of view you will use as your gallery canvas. A simple View, or a ScrollView, or whatever... it doesn't really matter right now, just to get it working. You want to ctrl-drag that view into your interface definition, so it drops an IBOutlet for the view (that way you can reference it in code).
You will place your ImageViews onto the view I just mentioned.
You can have an internal flag for the gesture recognizer, but it also has a property that use can enable/disable it whenever you want. Thus, you can have it active/inactive fairly easily.
All you want to do is drop a single tap-gesture-recognizer onto your controller, and connect it to the implementation section of the controller. It will generate a stub for handling the recognizer. It will interpret taps "generally" for the controller, and call your code whenever a tap is made on the view.
Some more code...
Creates a frame for the "new" image in the scroll view.
- (CGRect)frameForData:(MyData*)data atIndex:(NSUInteger)idx
{
CGPoint topLeft;
int row = idx / 4;
int col = idx % 4;
topLeft.x = (col+1)*HORIZ_SPACING + THUMBNAIL_WIDTH * (col);
topLeft.y = (row+1)*VERT_SPACING + THUMBNAIL_HEIGHT * (row);
return CGRectMake(topLeft.x, topLeft.y, THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT);
}
Creates an image view for each piece of metadata, and a small border.
- (UIImageView*)createImageViewFor:(MetaData*)metadata
{
UIImageView *imageView = [[UIImageView alloc] initWithImage:metadata.lastImage];
imageView.frame = CGRectMake(0, 0, THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT);;
imageView.layer.borderColor = [[UIColor blackColor] CGColor];
imageView.layer.borderWidth = 2.0;
imageView.userInteractionEnabled = YES;
return imageView;
}
This is where the views are created and added to the parent...
imageView = [self createImageViewFor:metadata];
//[data.imageView sizeToFit];
// Make sure the scrollView contentSize represents the data
CGRect lastFrame = [self frameForData:data atIndex:self.data.count-1];
CGFloat newHeight = lastFrame.origin.y + lastFrame.size.height;
if (self.bookshelfScrollView.contentSize.height < newHeight) {
CGSize newSize = self.bookshelfScrollView.contentSize;
newSize.height = newHeight;
self.bookshelfScrollView.contentSize = newSize;
}
[self.bookshelfScrollView addSubview:data.imageView];
So, you just create each frame, add them to the view, and the only thing you have to do is enable user interaction on them, because otherwise the scroll view does not allow the gesture through.
OK... Looking at the code you posted... since you didn't say what was wrong with it... hard to say... The below is your code... My comments are, well, Comments...
- (IBAction)editButtonPressed:(id)sender {
editButton.hidden = YES;
backToGalleryButton.hidden = NO;
tapToDeleteLabel.hidden = NO;
}
- (IBAction)tapGesture:(UITapGestureRecognizer*)gesture
{
// I don't think I'd do this here, but it shouldn't cause "problems."
UIAlertView *deleteAlertView = [[UIAlertView alloc] initWithTitle:#"Delete"
message:#"Are you sure you want to delete this photo?"
delegate:self
cancelButtonTitle:#"No"
otherButtonTitles:#"Yes", nil];
[deleteAlertView show];
// In your controller, you have the main view, which is the view
// on which you added your UIViews. You need that view. Add it as an IBOutlet
// You should know how to do that... ctrl-drag to the class INTERFACE source.
// Assuming you name it "galleryView"
// Take the tap location from the gesture, and make sure it is in the
// coordinate space of the view. Loop through all the imageViews and
// find the one that contains the point where the finger was taped.
// Then, "remove" that one from its superview...
CGPoint tapLocation = [gesture locationInView: self.galleryView];
for (UIImageView *imageView in self.galleryView.subviews) {
if (CGRectContainsPoint(imageView.frame, tapLocation)) {
[imageView removeFromSuperview];
}
}
}
Personally, in my little photo gallery, I bypassed all of the gesture recognizer stuff by replacing the UIImageView controls with UIButton controls, setting the image property for the button like you would for the UIImageView. It looks identical, but then you get the functionality of tapping on a thumbnail for free, with no gestures needed at all.
So, my view just has a UIScrollView, which which I programmatically add my images as buttons with the image set for the button control, e.g.:
- (void)loadImages
{
listOfImages = [ImageData newArrayOfImagesForGallery:nil];
// some variables to control where I put my thumbnails (which happen to be 76 x 76px)
int const imageWidth = 76;
int const imageHeight = imageWidth;
NSInteger imagesPerRow;
NSInteger imagePadding;
NSInteger cellWidth;
NSInteger cellHeight;
// some variables to keep track of where I am as I load in my images
int row = 0;
int column = 0;
int index = 0;
// add images to navigation bar
for (ImageData *item in listOfImages)
{
// figure out what row and column I'm on
imagesPerRow = self.view.frame.size.width / (imageWidth + 2);
imagePadding = (self.view.frame.size.width - imageWidth*imagesPerRow) / (imagesPerRow + 1);
cellWidth = imageWidth + imagePadding;
cellHeight = imageHeight + imagePadding;
// this is how I happen to grab my UIImage ... this will vary by implementation
UIImage *thumb = [item imageThumbnail];
// assuming I found it...
if (thumb)
{
// create my button and put my thumbnail image in it
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(column * cellWidth + imagePadding,
row * cellHeight + imagePadding,
imageWidth,
imageHeight);
[button setImage:thumb forState:UIControlStateNormal];
[button addTarget:self
action:#selector(buttonClicked:)
forControlEvents:UIControlEventTouchUpInside];
button.tag = index++;
[[button imageView] setContentMode:UIViewContentModeScaleAspectFit];
// add it to my view
[scrollView addSubview:button];
// increment my column (and if necessary row) counters, making my scrollview larger if I need to)
if (++column == imagesPerRow)
{
column = 0;
row++;
[scrollView setContentSize:CGSizeMake(self.view.frame.size.width, (row+1) * cellHeight + imagePadding)];
}
}
}
}
// I also have this in case the user changes orientation, so I'll move my images around if I need to
- (void)rearrangeImages
{
if (!listOfImages)
{
[self loadImages];
return;
}
// a few varibles to keep track of where I am
int const imageWidth = 76;
int const imagesPerRow = self.view.frame.size.width / (imageWidth + 2);
int const imageHeight = imageWidth;
int const imagePadding = (self.view.frame.size.width - imageWidth*imagesPerRow) / (imagesPerRow + 1);
int const cellWidth = imageWidth + imagePadding;
int const cellHeight = imageHeight + imagePadding;
NSArray *buttons = [[NSArray alloc] initWithArray:[scrollView subviews]];
int row;
int column;
int index;
CGRect newFrame;
// iterate through the buttons
for (UIView *button in buttons)
{
index = [button tag];
if ([button isKindOfClass:[UIButton class]] && index < [listOfImages count])
{
// figure out where the button should go
row = floor(index / imagesPerRow);
column = index % imagesPerRow;
newFrame = CGRectMake(column * cellWidth + imagePadding,
row * cellHeight + imagePadding,
imageWidth,
imageHeight);
// if we need to move it, then animation the moving
if (button.frame.origin.x != newFrame.origin.x || button.frame.origin.y != newFrame.origin.y)
{
[UIView animateWithDuration:0.33 animations:^{
[button setFrame:newFrame];
}];
}
}
}
NSInteger numberOfRows = floor(([listOfImages count] - 1) / imagesPerRow) + 1;
[scrollView setContentSize:CGSizeMake(self.view.frame.size.width, numberOfRows * cellHeight + imagePadding)];
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
[self rearrangeImages];
}
Hopefully this gives you an idea of how you can programmatically add a UIButton to act as an image in a gallery. I've tried to edit this on the fly, so I apologize in advance if I introduced any errors in the process, but it should give you a sense of what you could conceivably do ... I removed my code to do this in a separate GCD queue (which I do because I have close to 100 images, and doing this on the main queue is too slow.)
Anyway, you can then create your buttonClicked method to do your display of your UIAlertView.
- (void)buttonClicked:(UIButton *)sender
{
if (inEditMode)
{
// create your UIAlterView using [sender tag] to know which image you tapped on
}
}
Finally, you have two buttons on your UIAlertView, but you don't seem to check to see what button the user clicked on. Your view controller should be a UIAlterViewDelegate, in which you have defined your alertView:clickedButtonAtIndex which will do your actual edit steps.
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
// ok, will do what I need to do with whatever the user tapped in my alertview
}
The easiest thing I can think of off the top of my head is to have the gesture disabled by default, and then have the gesture enabled once the edit button is hit. This way, the picture will only respond to the tap gesture recognizer if it is in "Edit" mode.
I have a view where I am showing image and image name in a grid view. As shown in the image.
Now for the same I am taking one UIButton with image as background and UILabel and positioning it accordingly on the screen. Now when I press on the UIButton, it shows the UIActionSheet with option to delete, view and cancel. Now problem comes here. When I press Delete for only one record, the record gets deleted, but if more that one records are there, then gives issues in deleting that it shows the deleted record.
To Add UIButton and UILabel:
-(void)showImageFrame
{
int FrameWidth = 190;
int Frameheight = 196;
int FrameX;
int FrameY;
int lblWidth = 190;
int lblHeight = 40;
int lblX,lblY;
settButton = [UIButton buttonWithType:UIButtonTypeCustom];
[settButton setImage:[UIImage imageNamed:#"Picture frame.png"] forState:UIControlStateNormal];
[settButton addTarget:self action:#selector(pressSelectedImage:) forControlEvents:UIControlEventTouchDown];
btnInnerImg = [UIButton buttonWithType:UIButtonTypeCustom];
[btnInnerImg addTarget:self action:#selector(pressSelectedImage:) forControlEvents:UIControlEventTouchDown];
lblImgName = [[UILabel alloc]init];
lblImgName.font = [UIFont boldSystemFontOfSize:30];
lblImgName.textAlignment = UITextAlignmentCenter;
lblImgName.textColor = [UIColor whiteColor];
lblImgName.backgroundColor = [UIColor clearColor];
for(int i = 0;i<cnt1;i++)
{
[settButton setTag:i];
img = [[appDelegate.DataArray objectAtIndex:i]valueForKey:#"ProfileImage"];
[btnInnerImg setImage:img forState:UIControlStateNormal];
[btnInnerImg setTag:i];
lblImgName.text = [[appDelegate.DataArray objectAtIndex:i]valueForKey:#"strNameImg"];
[lblImgName setTag:i];
if(i==0)
{
FrameX = 35;FrameY = 119;btnX = 49;btnY=134;lblX = 35;lblY=337;
}
if(i==1)
{
FrameX = 289;FrameY = 119;btnX = 303;btnY=134;lblX = 289;lblY=337;
}
if(i==2)
{
FrameX = 545;FrameY = 119;lblX = 545;lblY=337;btnX = 558;btnY=134;
}
if(i==3)
{
FrameX = 802;FrameY = 119;lblX = 802;lblY=337;btnX = 816;btnY=134;
}
if(i==4)
{
FrameX = 35;FrameY = 411;lblX = 35;lblY=629;btnX = 49;btnY=426;
}
if(i==5)
{
FrameX = 289;FrameY = 411;lblX = 289;lblY=629;btnX = 303;btnY=426;
}
if(i==6)
{
FrameX = 545;FrameY = 411;lblX = 545;lblY=629;btnX = 558;btnY=426;
}
if(i==7)
{
FrameX = 802;FrameY = 411;lblX = 802;lblY=629;btnX = 816;btnY=426;
}
[settButton setFrame:CGRectMake(FrameX,FrameY,FrameWidth,Frameheight)];
[lblImgName setFrame:CGRectMake(lblX,lblY,lblWidth,lblHeight)];
[btnInnerImg setFrame:CGRectMake(btnX,btnY,btnWidth,btnHeight)];
[newButtonArray addObject:settButton];
[self.view addSubview: settButton];
[self.view addSubview: lblImgName];
[self.view addSubview: btnInnerImg];
}
}
To remove the UIButton and UILabel:
-(void)removeImageFrame
{
[settButton removeFromSuperview];
[btnInnerImg removeFromSuperview];
[lblImgName removeFromSuperview];
settButton = nil;
btnInnerImg = nil;
lblImgName = nil;
}
I don't want to use UITableviewCell for the grid view. Also what I am doing is that on deleting 1 record, I am removing all the records and reload them again as per record counter. I know I am doing some mistake in removeImageFrame method, but not able to find it. How can I remove the single UIButton with different Tags?
It would be nice to see a bit more context (the action method and how you get from pressing the button to deleting the button), but here is some advice:
Remove all objects from your button array at the start of showImageFrame
Create new buttons (with locally declared variables, not an ivar) inside the loop.
Don't use a tag of 0, that is the default tag that all views have
When a button is tapped, try to pass this as an argument to the removeImageFrame method - that's what sender is for.
You could also look at background images and foreground images for a single button instead of having what appears to be one button for the frame and one for a picture
(unrelated to your problem) try to think of a better way to display a grid than hard coding coordinates. What it the device is rotated?