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.
Related
I would like to implement IOS Weather APP like transition, ListView, tap on list item it expands to detail view, or pinch to list also expands to detail view.
Slide left and right transitions. Please let me know how can I implement that.
Thanks in Advance.
Here is some post on a blog I found that explains Apple new Transitioning API on iOS 7, go through it, read it.
In short lines, here are the steps
1 - Set a transition delegate on a controller
There are 3 types of transitions you might want to customise :
UINavigationController push & pop transitions
UItabBarController tab changed transitions
any modal presentation with presentViewController:animated
Each of these 3 cases offers its own 'transition delegate' protocol :
UINavigationControllerDelegate
UITabBarControllerDelegate
UIViewControllerTransitioningDelegate
When, from somewhere in your code, you use the methods for presentation :
pushViewController:animated: or popViewControllerAnimated:
setViewControllers:animated:
presentViewController:animated
Then, these delegates asks for what I call an 'animator' if an animation is required.
What I'm calling an 'animator' is an object conforming to protocol <UIViewControllerAnimatedTransitioning> (or <UIViewControllerInteractiveTransitioning> in case of interactive transition, like gesture driven interactions). This decouples the animation from your UIViewControllers (which might already have plenty of code inside)
2 - Write the 'animator'
This is the object responsible for animating transition. This can be a viewController, or a completely new NSObject.
In case of a UINavigationController, you could define different animators for push and pop operation.
3 - add the properties you need for your animation into your animator, and code the animation
The 'animator' might implement different protocols, depending on which transition you're trying to customise.
In case of non interactive animations, these are the methods :
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext : define the duration of animation
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext this is where the beef goes. See the example code in link above,
- (void)animationEnded:(BOOL)transitionCompleted for any clean-up after your animation was played.
In your case, you might want to add some 'origin' and 'target' UIView properties in your animator class (as weak properties of course !)
Then, when you detect 'which' view was tapped by user. (in your UITableVIewDelegate or UICollectionViewDelegate didSelect methods), you tell your animator so that it can animate with THAT specific frame, then call the 'push', 'pop' or 'presentViewController' , depending on your navigation logic.
You can definitely pull this off with the transitioning api.
Check out this project, I think it will help:
https://github.com/chefnobody/Colors
I was able to do it using this example from Ash Furrow # Teehan + Lax: http://www.teehanlax.com/blog/custom-uiviewcontroller-transitions/ with some modifications:
To augment this example to get the pinch/pull table view cell separation animation you would need to identify the table view cell that was selected (or "selected" relative to the pinch gesture"), then in -animateTransition: you animate the actual table view cells above and below the selected cell out of view, revealing your details view controller. Remember, also to animate back to the table view from the details you need to (during the "pop") know which cell would be selected (scrolling it back into view if it's not already in view) then animate the cells surrounding it from off screen, back into view.
As for the swipe interaction between the different cities you would implement a different InteractionController that handles the transitions there. Again, you can probably follow Furrow's example and figure out how to pull it off.
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.
So I'm curious. I was looking into a way to create a categories selector similar to the one located at the top of this application: http://itunes.apple.com/us/app/xfeed-rss-reader/id313206921?mt=8 ... 06921?mt=8. Would I tackle this using a Toolbar and elongating it to where the user can 'scroll' side to side for categories? Or a ScrollView with a Tabbar in it? I want to do this the 'proper' way per say and I've seen flags raised about a Tabbar being in a ScrollView.
If I were implementing this, I would create it with a UIScrollView containing UIButtons. UITabBars have some nice integration with UIViewControllers and UINavigationControllers, but the benefits quickly drop off when you need more customizable behavior (left to right scrolling, for instance.). I would normally just put them all in a xib and connect the outlets appropriately, unless it was important that they be dynamic.
You mentioned correctness, so an even more "correct" way is to create a UIControl similar to a UISegmentedControl that handles the creation of properly sized labels, deals with touches appropriately, etc. If you are setting categories dynamically you'll want to override sizeThatFits: and call sizeToFit so you can properly size the content area of your scrollview.
Lets say I have a scene which includes a UIView container on the top half of the screen, and a UIView container on the bottom half of the screen and a few buttons at the very bottom of the screen.
Basically the bottom container will always display static text while the buttons across the bottom will change the content of the top container which may include an image, more buttons, or more text depending on what button is pressed on the bottom. Also each time a bottom button is pressed the top container is transitioned to the new view with a flip from bottom transition.
I have achieved this purely programmatically, but decided to convert my app to a storyboard file since it makes producing the rest of my app much faster and simpler, plus makes the code not look like a crazy mess.
My limited understanding of storyboards seems to deduce that I would need a separate story board scene for every UIView change, and Apple's coding conventions with storyboards seem to imply that we should use a new ViewController every time you create a new scene. All this adds up to an even bigger mess than I currently have.
Is there a better way of doing this? Am I misunderstanding something? If I am not confused, is there some way to make all these scene and view controller duplication cleaner?
The storyboard editor makes it difficult to do what you're describing, because it doesn't let you edit freestanding views associated with a scene.
I suggest you just create a separate nib (not storyboard) for each of the top-half views. These can exist separate from your storyboard. Your view controller (which is instantiated from the storyboard) can then load whichever nib it needs when a button is pressed, and put the view from the nib into its (the view controller's) top-level view.
There must be a way!
I accidentally opened one one day (see attached image). Although I have no idea how I did it and really really want to know, I cannot reproduce it, nor close it. The UIView opened when I was dragging my connection for the table header view from the Connections Inspector to the list of controls on the left side of the screen (not to the actual UIViewController).
I too am reworking a project with storyboards and have a similar problem with multiple views per UIViewController.
In this case it is a table header. I have other UIViewControllers in the project with the same configuration but I cannot get them to pop up either.
What I need may be pretty basic, but I'm definitely not sure as to how to proceed (I've done that before but none of my choices seem that Cocoa-friendly).
Ok, let's say we've got 2 NSViews - one next to the other:
The one on the left serves as a menu.
The one on the right will show a NSView (from a different XIB perhaps?) depending on the selection on the menu.
My questions :
How should I go about loading the different NSViews into the rightmost NSView?
How do I make sure that the subview (the one currently active) is properly resized when the window is resized?
rdelmar's solution should work, but another approach, which may be simpler, is to use an NSTabView to handle switching between the content views. You can hide NSTabView's tabs using the settings pane in interface builder, or by calling [self.tabView setTabViewType:NSNoTabsNoBorder]. I'd probably use a table view for the left side. When the user selects a row, you do something like:
-(void)tableViewSelectionDidChange:(NSNotification *)notification
{
[self.tabView selectTabViewItemAtIndex:[self.menuTableView selectedRow]];
}
The NSTabView can/will take care of properly resizing its content views as long as you've set up its and its content views' autoresizing masks (springs and struts) properly.
You should be able to create a custom view in IB that looks like your yellow view, and set its resizing behavior to expand in both directions with window resizing. Then, when you get your new view (by just referencing one you already have or loading a new xib), add it as a subview of the custom view, and set its frame to that of the custom view. I think that views resize their subviews by default, so it should resize correctly with the custom view.