moving UIImageView form first tapped UIControl to second tapped UIControl - iphone

I have 25 UIControls and 10 UIImageView. It looks like this:
Now the images are the UIImageVIews and the grids are the UIControls. What I want is when the user taps at a image and then taps at any of the grids (any blank grids of-course) the UIImageView is then removed from the current superView and added as the subView of the blank grid tapped. For example, if the user taps at the A1 grid first and then in the B2 grid, two actions occur,
UIImageView from A1 grid is removed,
UIImageView is added to B2 grid
This means when the user taps at the image at A1 grid and then taps at the B2 grid, the output window looks like this:
EDIT
So, at a time I need to have track for two UIControls:
1.which one is pressed first, and
2.which one is pressed second. And then remove the UIImageView from the first UIControl and add it to the second UIControl. I have tried giving the UIControls a tag like,
//....
A1.tag = 1;
//...
-(void)a1ViewTapped:(id)sender
{
int i = A1.tag;
[self switch:i];
}
//...
-(void)switch:(int)_tag
{
//....
UIView *view = (UIView*)[self.view viewWithTag:_tag];
[view removeFromSuperview];
//...
}
By this I can track a single UIControl, but need to track two of them.
How can I accomplish this, can anyone help?

UIControl inherits from UIView, so you can add a subview to your UIControl by calling addSubview:.
You can remove your UIImageView from the previous control by calling removeFromSuperview on the UIImageView
edit:
A very simple implementation would be to create a property that holds a reference to the selected UIControl. When the property is nil, then you are in selection mode. Touching up inside a control puts a reference to the control into the property. When the property is not nil, you are looking for a grid control in which to place the image.
You'll also need a way to keep track of whether your UIControl has one of the UIImageView instances as a subview. There are a number of ways to do that. One way would be to subclass UIControl to add a property to it that points to the UIImage it contains. Another way might be to simply examine the subviews of the UIControl to see if it contains one of the images in question. Another way would be to create some data structure to keep track of the positions of the images. How you do it is up to you, and the best way depends on the specifics of your implementation.
Just for the sake of discourse, let's assume you set up an NSMutableDictionary called imageMap that uses the tags of your UIControls as keys and sets references to the images as values. Then you could do something like:
-(void)selectGridControl:(UIView*)view
{
if (selectedControl == nil) // In this case nothing is selected
{
selectedControl = view;
}
else // In this case we are moving the image to the new view
{
UIImageView *selectedImage = [imageMap objectForKey:selectedControl.tag];
if (selectedImage != nil)
{
[selectedImage removeFromSuperview];
[view addSubview:selectedImage];
[imageMap removeObjectForKey:selectedControl.tag];
[imageMap addObject:selectedImage forKey:view.tag];
selectedControl = nil;
}
}
Initializing imageMap and handling cases when the destination control already has an image are left as exercises for the reader.

Related

Button On-Click Event in Xcode 4.2.1

I have a static background image (map) that loads in my ImageView. I have a couple of transparent text images (labels for cities on the map, for example) that I would like to overlay on the map upon the click of a button. re-clicking the button would unload the layer so that the user could have any combination of the layers selected depending upon what they would like to see. I might have a total of 5 layers connected to 5 buttons.
I know it is simple, but I need some help with the button code. If I have a button called 'cities' and a layer called 'cities.png' I would like to load and display over my main ImageView map, could someone please please please show me some code that would allow the button click to cycle my cities.png layer on and off?
many thanks
Make a property of ImageView and synthesize it
Add a gesture recognizer to your view(Google it);
Add a tap count of 1 to fire function
In function
check
if(self.imageView.image != nil)
{
self.ImageView.image = [UIImage imageNamed:#YourImage"]; //load the image view
}
else
{
self.imageView.image = nil; //image already dispelled..remove it.
self.imageview.center = //touch location center //
}
This will work if you want to load one image at a time

How to change the style of an UIView when it's tapped?

I'm making different UIView's tappable (they're not inheriting from UIControl) using the following code:
UITapGestureRecognizer* gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(userTappedOnLink:)];
[labelView setUserInteractionEnabled:YES];
[labelView addGestureRecognizer:gesture];
but I'd also like to change the style when they're highlighted. How do I do that?
Attach UILongPressGestureRecognizer instead of UITapGestureRecognizer to parent view and set it's properties to your liking. The way to track and respond to selection is to implement userTappedOnLink method in appropriate way. This method will be called lots of times in short amount of time when gesture recognizer is activated and you know what's happening by tracking recognizer states.
Implement UIView subclass and create methods, like select and deselect, and customize view properties for each. Then it's only matter of finding which UIView subclass to select or deselect and that's easily done with UIGestureRecognizer method returning point in parent view and iterating trough it's subviews while checking if touch point is inside of particular subview frame.
- (IBAction)userTappedOnLink:(UIGestureRecognizer*)sender
{
switch (sender.state)
{
case UIGestureRecognizerStateBegan:
{
CGPoint touchPoint = [sender locationInView:self.parentView];
for (UIView *subView in [self.parentView subViews)
{
if (CGRectContainsPoint(subView.frame, tapPoint))
{
self.activeSubView = self.subview;
break;
}
}
[self.activeSubView select];
case UIGestureRecognizerStateChanged:[self.activeSubView doNothing];; break;
case UIGestureRecognizerStateEnded:[self.activeSubView deSelect]; self.activeSubView = nil; break;
}
}
There are two ways of handling events in iOS. The first one is to use UIView subclassing and override the methods that are inherited by UIView from UIResponder class (i.e. touchesBegan:withEvent, touchesMoved:withEvent, touchesEnded:withEvent, touchesCancelled:withEvent).
The second way is to create new instance of gesture recognizer class and add it to your UIView object (just like you did) and then create a handler.
- (IBAction)userTappedOnLink:(UIGestureRecognizer *)sender {
// Changing view properties.
}
In both cases you can change the UIView properties. You can find some useful information in "Event handling guide" by Apple. There is a lot of reading but you can have a look only at the "related sample code" (Touches and SimpleGestureRecognizers).
The way you change the style properties of the interface elements in your application depends on what those properties are. Sometimes they can be animated sometimes they're not. Usually the code that changes view properties is placed inside the touchesBegin function or gesture recognizer handler. MoveMe sample code shows how to change views properties and animate them. In the Gesture recognizers chapter of the "Event handling guide" frame properties are changed.
I managed to solve this by adding an UIControl as a subview in the UIView. The UIControl is the same size has a transparent background that changes when it's highlighted. Works like a charm!
well, I have not tested it, just a suggestion, please handle touchesbegin for this view,and call [labelView addGestureRecognizer:gesture]; function.
maybe you should use another function, - (void)removeGestureRecognizer:(UIGestureRecognizer*)gestureRecognizer .

Positioning A Button

How can I position a button on my view dynamically?
Try this code
for(UIView * view in self.view.subviews)
{
if([view isKindOfClass:[UIButton class]])
{
// view is button
}
}
You can also use tags
Set the tag property of the UIButton (e.g. in interface builder, or programatically). Then you can walk the children of the owning view:
for (UIView *view in myView.subviews) {
if (view.tag == 101 /*or whatever you set it to*/) {
// things...
}
}
Ok, now we understand the question better...
You can place a button/UIComponent at runtime by settings its frame. This will place it at a given coordinate within the view containing the button.
myButton.frame = CGRectMake(newX, newY, myButton.frame.width, myButton.frame.height);
If you wish to do a linear style animation (no curves), look up CATransitions, see iPhone UIView Animation Best Practice. If you need to support pre-iOS4 devices, you can't use CATransitions, and have to do it the old way using UIView animations.
To do more complex animations, you might have to mess around with timers, which can slightly juddery effects if you're trying to do complicated animation paths.
Get a array of all the subviews of a view using:
[myView subviews]
iterate through that array and check for your butotn by some unique characteristic. (You can set the button's tag attribute to some unique value and check for that value)

UITableViewCell custom reorder control

Is there any way to change the image of the reorder control that is displayed when the UITableView is in edit mode? I have a UIImage that I’d like to display instead of the usual grey bars.
Do I have to subclass UITableViewCell to accomplish this?
I guess you're a long way past this by now, but this has come up in a new question.
See my answer here:
Change default icon for moving cells in UITableView
I recently ran across the need to change the image for the reorder control, because I subclassed UITableViewCell to provide my own custom table cell. As part of this effort, I changed the background of the cell to something other than the default color.
Everything works correctly, but when I put the UITableView into editing mode, the reorder control would appear, with a white background - instead of the background color I was using for the cell. This didn't look good, and I wanted the background to match.
During the course of various versions of iOS, the hierarchy of views in a UITableViewCell has changed. I've taken an approach that will traverse the entire set of views until it finds the UITableViewCellReorderControl private class. I believe this will work for iOS 5 and all subsequent iOS versions at the time of this answer. Please note that while the UITableViewCellReorderControl class itself is private, I am not using any private API's to find it.
First, here's the code to scan for the reorder control; I'm assuming that the text "Reorder" will be in the class name - which Apple could change in the future:
-(UIView *) findReorderView:(UIView *) view
{
UIView *reorderView = nil;
for (UIView *subview in view.subviews)
{
if ([[[subview class] description] rangeOfString:#"Reorder"].location != NSNotFound)
{
reorderView = subview;
break;
}
else
{
reorderView = [self findReorderView:subview];
if (reorderView != nil)
{
break;
}
}
}
return reorderView;
}
In your custom UITableViewCell subclass, you will override -(void) setEditing:animated: and find the reorder control here. If you try to find this control when the table is not in editing mode, the reorder control will not be in the view hierarchy for the cell:
-(void) setEditing:(BOOL)editing animated:(BOOL)animated
{
[super setEditing:editing animated:animated];
if (editing)
{
// find the reorder view here
// place the previous method either directly in your
// subclassed UITableViewCell, or in a category
// defined on UIView
UIView *reorderView = [self findReorderView:self];
if (reorderView)
{
// here, I am changing the background color to match my custom cell
// you may not want or need to do this
reorderView.backgroundColor = self.contentView.backgroundColor;
// now scan the reorder control's subviews for the reorder image
for (UIView *sv in reorderView.subviews)
{
if ([sv isKindOfClass:[UIImageView class]])
{
// and replace the image with one that you want
((UIImageView *)sv).image = [UIImage imageNamed:#"yourImage.png"];
// it may be necessary to properly size the image's frame
// for your new image - in my experience, this was necessary
// the upper left position of the UIImageView's frame
// does not seem to matter - the parent reorder control
// will center it properly for you
sv.frame = CGRectMake(0, 0, 48.0, 48.0);
}
}
}
}
}
Your mileage may vary; I hope this works for you.
Here is my Swift solution based on Rick Morgan's answer:
func adjustSize() {
// we're trying to leverage the existing reordering controls, however that means the table must be kept in editing mode,
// which shrinks the content area to less than full width to make room for editing controls
let cellBounds = bounds
let contentFrame = contentView.convert(contentView.bounds, to: self)
let leftPadding = contentFrame.minX - cellBounds.minX
let rightPadding = cellBounds.maxX - contentFrame.maxX
// adjust actual content so that it still covers the full length of the cell
contentLeadingEdge.constant = -leftPadding
// this should pull our custom reorder button in line with the system button
contentTrailingEdge.constant = -rightPadding
// make sure we can still see and interact with the content that overhangs
contentView.clipsToBounds = false
// recursive search of the view tree for a reorder control
func findReorderControl(_ view: UIView) -> UIView? {
// this is depending on a private API, retest on every new iPad OS version
if String(describing: type(of: view)).contains("Reorder") {
return view
}
for subview in view.subviews {
if let v = findReorderControl(subview) {
return v
}
}
return nil
}
// hunt down the system reorder button and make it invisible but still operable
findReorderControl(self)?.alpha = 0.05 // don't go too close to alpha 0, or it will be considered hidden
}
This worked pretty well. contentLeadingEdge and contentTrailingEdge are layout constraints I set up in Interface Builder between the contentView and the actual content. My code calls this adjustSize method from the tableView(_:, willDisplay:, forRowAt:) delegate method.
Ultimately, however, I went with Clifton's suggestion of just covering the reorder control. I added a UIImageView directly to the cell (not contentView) in awakeFromNib, positioned it, and when adjustSize is called I simply bring the image view to the front, and it covers the reorder control without having to depend on any private APIs.
I put a little work into this recently, but came up short. I tried setting my own editingAccesoryView but couldn't get the reorder control to change. Odd.
My guess is that it has something to do with the following comment in the UITableviewCell docs re: showsReorderControl:
If the value is YES , the reordering
control temporarily replaces any
accessory view.
In other words, the editingAccessoryView is being replaced by the reordering control view, which might be why we cannot override the reordering control. Hoping someone can find a workaround.
You set the cell's editingAccessoryView property to an image view containing the image you want.
As an aside, I would caution you to be careful when doing this. When you substitute a custom graphic for a system standard such as the reorder graphic, you run a serious risk of confusing the user. The standard UI grammar has told them to expect the standard graphic when reordering and they may not understand the significance of your custom graphic.
Maybe we're all overthinking this. :)
Just put a custom UIImageView over the top of the default move accessory so it covers it up. Done.

How to update a label of a custom view within a scroll view using a timer

Please help!
I define a custom UIControl with three labels, then on the viewDidLoad function of the main view controller, I repeatedly add multiple instances of that UIControl into the scroll view.
I need one of the label within the UIControl to be updated with new value each second. I have a question, how to clear the previously drawn custom view? Or what is the method for updating that label with best drawing performance?
- (void) updateMinuteLabel{
CustomIconControl *control = nil;
for (control in scrollView.subviews){
if ([view isKindOfClass:[CustomIconControl class]] && control.tag >0){
CustomIconControl *item = (CustomIconControl *) control;
item.intMinute += 1;
[item setNeedsDisplay];
}
}
}
In the drawRect: function of the CustomIconControl, I use the
[minuteString drawInRect: minuteRect withFont: [UIFont systemFontOfSize:10];
With this code, it continues to draw without clearing out the previously drawn controls.
Can someone help? Please tell me if you need more information, of course I have the code for custom drawing part of the CustomIconControl, the initialization of the timer, viewDidLoad etc.
You say your UIControl has three labels, do you mean you are adding three UILabel's as subviews of the UIControl? If so, you can just the text' property of the label to the value and it will automatically redraw itself - no need to [minuteString drawInRet...
Otherwise, if you're drawing the three "labels" in drawRect:, calling setNeedsDisplay: after intMinute is updated should cause drawRect: to be called, thus drawing the updated text.
Also, I recommend your CustomIconControl be responsible for calling setNeedsDisplay on itself when intMinute is updated.
Andrew