Removing objects from superview by clicking on subviews - objective-c

I have a UIViewController which places it's view on the screen and when it loads it creates an array of CGRects. It then adds those CGRects onto its view as subviews by filling them with a UIView.
I then create another CGRect and place it within one of these subviews and fill it with a UIImageView. It's set up to use CGRectContainsPoint and if the point is within one of the UIView CGRects it passes data to that object saying that it is there.
I can then click the UIView and it will use handleTap: to remove the origin point of the UIImageView rect from the super view.
Now the problem, I recently implemented a NSTimer and have it dropping new UIImageViews in at certain times. I also used the CGRectContainsPoint for loop to iterate through the array of UIView rectangles to check for UIImageView rectangles within them every one second.
When I run the program, I can click to remove the initial one, but when I click another it may or may not remove itself, I don't know why. However, sometimes when I click the first ones blank square it will remove one of the other ones and vice versa.

Im not so sure about your problem. But i guess that you want to creat a view and when u click it ,it will be disappeared itself? And u try to add many of this views but it doesnt work directly u think.
See if i can help. you can creat a news class extends to UIView and add an tapGesture to it, which will refer to a method -(void)removeItSelf:(id)sender;
-(void)removeItself:(id)sender
{
[self removeFromSuperView];
}
and create any instance of this view, it will be removed no metter how many u create.

Related

NSStackView only shows newest custom view

I have a custom view controller class. I want to instantiate multiple custom view controllers and add their views to my NSStackView. I add a new view to the stack view by clicking a button. The button calls this method:
[stackView insertView:myCustomViewController.view atIndex:0 inGravity:NSStackViewGravityBottom];
However, when a new view is added, it's added stackView.spacing below where the previous view was, but that previous view is no longer visible, however it is still listed as a view in my bottom gravity as evidenced when I call
NSLog(#"%lu",(unsigned long)[stackView viewsInGravity:NSStackViewGravityBottom].count);
I don't have this problem if I try adding NSButtons, so it's something to do with my custom view but I can't figure out what.
Please help. Thanks!
You should check that your custom view has constraints (or an intrinsic content size) that completely define the height of the view. If they don't, these views are collapsing down to 0 heights (this same thing has happened to me before).
You can check if this is happening by:
[stackView insertView:myCustomViewController.view atIndex:0 inGravity:NSStackViewGravityBottom];
[stackView layoutSubtreeIfNeeded];
NSLog(#"%f - %d", NSHeight(myCustomViewController.view.frame), [myCustomViewController.view hasAmbiguousLayout]);
With StackView, you'll see that the later ones print "0 - 1". The heights are 0, and they're ambiguous.
Vertical NSStackView's will only position views vertically, but won't give specific heights. (Same for horizontal stack views and widths).

How to add UITableView to one of several subviews using storyboard

I have one UIViewController with two UIViews on it. In the Navigation bar, when one button is pushed one of the UIViews is displayed and when the other button is pushed the other UIView is displayed. I want to put a UITableView on one of the views. However, the UITableView requires the UIViewController to use the UITableViewDelegate and UITableViewDataSource. Having implemented this for my UIView (subview) containing the UTTableView, when I click on the button for the other view, which does not contain a table, I get errors and the application croaks.
I am assuming (possibly incorrectly) that my issue is that I am trying to use the same UIViewController for both subviews, but only one contains a table.
Question 1) Is it possible to do what I described above? Meaning, if I had a problem then something was not connected up correctly.
So, I went down a path of creating two separate UIViewControllers; one for each view. Not sure this is the smart approach. Now I am just looking for advice on the best way to do this. Thank you in advance for your help.
To be more clear about what I am trying to do. I want the blue view to be put where the pink view is when the first button on the bar is clicked and I want the yellow view to be put where the pink view is when the second button is clicked. Essentially the pink view will never be displayed and may not even need to be on the UtilityViewController.
Having each as a UIViewController (or a subclass thereof) is the way to go about what you are trying to do. The UITabBarController does this already: https://developer.apple.com/library/ios/documentation/uikit/reference/UITabBarController_Class/Reference/Reference.html

Button is disabled when using UITableViewCell instance as if it was a UIView instance

There is a custom view that I extend from UITableViewCell.
In CustomTableViewCell, I implement init method so that it loads a corresponding .xib which contains button.
However, I want to reuse it as if it's a normal UIView instance. For instance, I want add it as a child of my view controller
// in view controller
CustomTableViewCell* customTableViewCell = [[CustomTableViewCell alloc] init];
[self.view addSubview:customTableViewCell];
The problem is, the custom table view cell can be added, but the button that it holds can not be pressed. Meanwhile, the button of the custom table view cell that is populated by table view is working fine.
https://www.evernote.com/shard/s27/sh/59f7b828-f65a-41dc-9156-40a985fceac8/9edb04b8e5c821ad7a46eb714cc776dc
In the screenshot above, the button with the yellow highlight can not be pressed, while the blue can.
Anyone has the idea why it's not working?
It's a guess, but you create the cell with a CGRectZero frame. It doesn't clip it's subviews so they can still be seen, but it's subviews won't get touches outside of the superview's bounds (which are zero). Try alloc initWithFrame:CGRect(/* some reasonable values */).
Once you get that working, you can try with some layout constraints.
May be you need pass fileowner in 'init' method, if you have assigned button's actions to fileowner in xib-file.

Getting around Subclassing UIView and Using Pictures in Storyboard

I'm trying to write my first iPhone app, and I'm running into a sort of design struggle. What I want to do is have a grid of icons and when you touch one, all the icons above and to the left will "activate" and all the ones below and to the right will "deactivate." If an icon is activated it shows one picture, and if it's not activated it shows another.
The problem I have is that I want to assign a gesture recognizer to each one of these individual icons, and when that icon is tapped, it needs to call a function that updates my grid of icons. But in order to properly update, the function needs to pass as arguments the location of the image in the grid and there's no way to call a function with arguments as part of a gesture recognizer.
So really all I need to do is extend UIImageView to hold two extra integers and the grid it's contained in, and then I could have the following code:
imageView.userInteractionEnabled = YES;
UITapGestureRecognizer *tapgr = [[UITapGestureRecognizer alloc] initWithTarget:
self action:#selector(handleTap)];
[imageView addGestureRecognizer:tapgr];
:
:
- (void)handleTap
{
[self.grid updateTableFromRow:self.row andCol:self.col
}
So I suppose this is one way of doing it, but I'm told that I'm not supposed to extend classes in Objective-C, that I should build them from the ground up. In this case, I would just make a custom view with all the properties and/or instance variables I need and I would just fill this custom view with the UIImageView.
This is mostly fine, except when it comes to building my Storyboard. I put all the code that manages and creates this table of icons (programmatically) in another custom view, GridOfIconsView. So on the Storyboard I drag out a custom view and set to be a GridOfIconsView, but then I just see a big white rectangle, and I really want to be able to visualize my app in Storyboard. I know that I can drag out actual image files that I use for the icons onto Storyboard and set them to be a custom view, but then how does that work? Is that image just a background to the custom view? Would I be able to change it programmatically? So if the activated image was a green square, but the deactivated was a red one and I initially dragged out red squares to the Storyboard, would I have access to that red square image?
And a more concerning issue is that I want to manage all these icons in a data structure, either as a 2d array (id icons[][]) or a NS(Mutable?)Array of NS(Mutable?)Arrays. Either way, how could I initialize the data structure to contain links to all these? The grid will be probably 8x8 or 10x10, and there's no way I'm going to have 64-100 #propertys connecting these icons. I'm thinking the only way to sensible organize this is programmatically, but then still, how can I visualize it in Storyboard?
First, it's completely fine to extend classes in Objective-C, and it's done all the time. UIView, UIViewController, UIComponent, etc., were all designed specifically to be subclassed and extended.
However, there are two ways you can do this that are much simpler than extending the class. First, you can have your grid as you already do, where each view has a gesture recognizer attached that calls back to a method on the view controller. Then, you can set a tag on each view (or even just use the view's frame for identification), and read that from the callback method (the gesture recognizer is passed back to the callback method). For example, let's say you had a grid of 4x4 views and you simply numbered them starting in the top-left, advancing each column to the right and then each row, from 0 to 11, you could easily identify the view as such:
// The system automatically passes the gesture recognizer as the only parameter
- (void)handleTap:(UIGestureRecognizer)gestureRecognizer
{
NSInteger viewNumber = [[gestureRecognizer view] tag];
// do something with this view
}
The other way you can do it is to have a single gesture recognizer on the parent view, and then in your -handleTap: callback, you'd query the position of the tap in the view. If the position is within the frame of any of your views, you'd know which one and what to do with it. If not, you could ignore it. This solution requires slightly more math, but also requires far less maintenance and far fewer gesture recognizer that need to be wired up. I would recommend this solution over tagging your views.

Objective C: Can I set a subview to be firstResponder?

I have a situation whereby I am adding a view from another viewcontroller to an existing viewcontroller. For example:
//set up loading page
self.myLoadingPage = [[LoadingPageViewController alloc]init ];
self.myLoadingPage.view.frame = self.view.bounds;
self.myLoadingPage.view.hidden = YES;
[self.view addSubview:self.myLoadingPage.view];
Is it possible to set 'self.myLoadingPage' to be the first responder? This is the case whereby the loadingpage view size does not cover the entire size of the existing view and users can still interact with the superview (which is not the desired behaviour). I want to just enable the subview in this case.
When I had a similar problem, I made an invisible UIView that covered the entire screen, I added the large invisible UIView on top of the main view and made the loading view a subview of the invisible UIView.
The simplest solution is to override hitTest method in your loading view to return TRUE. This top view is first in the responder chain, the hitTest method gets called which NORMALLY returns TRUE if the point is within the view and will therefore be handled, returning TRUE regardless means you get the touch event and effectively block the message being resent to the next responder.
Interesting question. I found a similar post with a quote from the Apple Developer Forums on this issue:
To truly make this view the only thing
on screen that can receive touches
you'd need to either add another view
over top of everything else to catch
the rest of the touches, or subclass a
view somewhere in your hierarchy (or
your UIWindow itself) and override
hitTest:withEvent: to always return
your text view when it's visible, or
to return nil for touches not in your
text view.
This would seem to indicate there isn't a terribly straightforward solution (unless there was an API change regarding this made after October, 2010.)
Alternatively, I suppose you could go through all the other subviews in your superview and individually set their userInteractionEnabled properties to NO (but that would probably prove more cumbersome than the quoted solutions).
I would love to see other ways to allow this.