I've been searching all over the net for an answer to this one! Hoping one of you can help me.
So far I have a button that produces a random nr between 1 and 6 in a label.
Then I want a picture to appear depending on what nr is in the label.
For example: If the number 1 is generated, I want img1.png to appear in a UIImageView.(?)
I'm thinking maybe a if function to pick the picture?
Sorry for bad formating.
Here is the .h file:
#import <UIKit/UIKit.h>
#interface xxxViewController : UIViewController
{
IBOutlet UILabel *label;
int randomNumber;
}
-(IBAction)randomize;
#end
...and here is the .m file:
#import "xxxViewController.h"
#implementation xxxViewController
-(IBAction)randomize
{
int randomNumber = 1+ arc4random() %(6);
label .text = [NSString stringWithFormat:#"%d",randomNumber];
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
int randomNumber = 1+ arc4random() %(6);
label .text = [NSString stringWithFormat:#"%d",randomNumber];
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[super dealloc];
}
#end
You can use the number to create the file name, for instance [NSString stringWithFormat:#"image%d.png", number];. It's probably a better practice (though not necessary for what you're doing) to create a list of file names, and associate them with numbers in an NSDictionary so you're always dealing with known image names.
Related
I am trying to make a custom Xcode UIPicker with only numbers 1-10. Is there any simple way to do this with an Identity Inspector or if not, what is the best way to go about making this simple UIPicker?
Thanks in advance!
No, you can't create a picker using only Inerface Builder. There is no equivalent to UITableView Static cells for UIPicker. You need a view controller but it's not that complicated. The view controller need to implement the UIPickerViewDataSource, UIPickerViewDelegate delegates. Here is the basics for a single column picker with the values 1 to 10.
#import "ViewController.h"
#interface ViewController () <UIPickerViewDataSource, UIPickerViewDelegate>
#property (weak, nonatomic) IBOutlet UIPickerView *pickerView;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.pickerView.delegate = self;
self.pickerView.dataSource = self;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - UIPickerView Data Source & Delegate
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
return 10;
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
return [NSString stringWithFormat:#"%d", row + 1 ];
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
// TODO do something with the selection
}
#end
To create a minimal iOS app with a picker. Create a new Project select single window application. Replace the code in ViewController.m with above. Edit the story board and add a picker. Important You need to connect the picker view in the storyboard to the IBOutlet in the code.
Not Connected
To connect the outlet you should be editing the storyboard in assistant editor mode. The assisted editor will display the code and the IBOutlet property. Now "Control Click the picker view in the storyboard and drag to the line of code declaring the IBOutlet. The connection is made when the circle is black in the gutter on the line declaring the IBOutlet property.
Connected
Xcode Editing Storyboard in Assistant Editor Mode
FYI: By far the best and fastest moving way to learn iOS is the Stanford iTunes U Course:
Developing iOS 7 Apps for iPhone and iPad
https://itunes.apple.com/us/course/developing-ios-7-apps-for/id733644550
You will need to watch a few of the demos to grok how to make connections Interface Builder (IB). The first thing you need to understand is the IB does not create resource or configuration files. The storyboard files contain serialized interface objects. Almost identical to the objects you can create in code.
Changing the size of the picker text
You need to replace the implementation of pickerView:titleForRow:forComponent: with your own pickerView:rowHeightForComponent: and pickerView:viewForRow:forComponent:reusingView:
- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component
{
return 60; // Row height in points, Note this should match the height of the UILabel Rect.
}
// FYI points are not pixels on non retina screens 1 point = 1 pixel but on retina screens 1 point = 2 pixels
- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view
{
if (view) {
UILabel *reuseLabel = (UILabel *)view;
reuseLabel.text = [NSString stringWithFormat:#"%ld", row + 1 ];
return reuseLabel;
}
UILabel *newLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 300, 60)];
newLabel.text = [NSString stringWithFormat:#"%ld", row + 1 ];
newLabel.font = [UIFont systemFontOfSize:42];
newLabel.textAlignment = NSTextAlignmentCenter;
return newLabel;
}
I have a dynamic NSTableView which can add a number of columns depending on the data provided. For each column I have set the header cell to be a NSPopUpButtonCell. (Side-note: I've had to use a custom subclass class for NSTableHeaderView otherwise the menu doesn't pop-up). All works well, apart from a duplicate or extra header button cell on the top right. It mirrors perfectly the previous column selection as shown in screenshots. My question is how do I stop the NSTableView from recycling the previous popup header cell? (By the way I have tried the setCornerView method but that only effects the header area above the vertical scrollbar.)
I came across the same problem this week. I went with the quick fix,
[_tableView sizeLastColumnToFit];
(However, after discussion with OP this requires that you use a subclass of NSPopUpButtonCell in the header and also NSTableHeaderView. I attach my solution below)
You can to this by combining the approaches outlined here,
PopUpTableHeaderCell
DataTableHeaderView
Here is a simplified snippet,
// PopUpTableHeaderCell.h
#import <Cocoa/Cocoa.h>
/* Credit: http://www.cocoabuilder.com/archive/cocoa/133285-placing-controls-inside-table-header-view-solution.html#133285 */
#interface PopUpTableHeaderCell : NSPopUpButtonCell
#property (strong) NSTableHeaderCell *tableHeaderCell; // Just used for drawing the background
#end
// PopUpTableHeaderCell.m
#implementation PopUpTableHeaderCell
- (id)init {
if (self = [super init]){
// Init our table header cell and set a blank title, ready for drawing
_tableHeaderCell = [[NSTableHeaderCell alloc] init];
[_tableHeaderCell setTitle:#""];
// Set up the popup cell attributes
[self setControlSize:NSMiniControlSize];
[self setArrowPosition:NSPopUpNoArrow];
[self setBordered:NO];
[self setBezeled:NO];
[self setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
}
return self;
}
// We do all drawing ourselves to make our popup cell look like a header cell
- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView{
[_tableHeaderCell drawWithFrame:cellFrame inView:controlView];
// Now draw the text and image over the top
[self drawInteriorWithFrame:cellFrame inView:controlView];
}
#end
Now for the NSTableViewHeader subclass.
//DataTableHeaderView.h
#import <Cocoa/Cocoa.h>
/* Credit: http://forums.macnn.com/79/developer-center/304072/problem-of-nspopupbuttoncell-within-nstableheaderview/ */
#interface DataTableHeaderView : NSTableHeaderView
#end
//DataTableHeaderView.m
#import "DataTableHeaderView.h"
/* Credit: http://forums.macnn.com/79/developer-center/304072/problem-of-nspopupbuttoncell-within-nstableheaderview/ */
#implementation DataTableHeaderView
- (id)initWithFrame:(NSRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Initialization code here.
}
return self;
}
- (void)mouseDown:(NSEvent *)theEvent {
// Figure which column, if any, was clicked
NSPoint clickedPoint = [self convertPoint:theEvent.locationInWindow fromView:nil];
NSInteger columnIndex = [self columnAtPoint:clickedPoint];
if (columnIndex < 0) {
return [super mouseDown:theEvent];
}
NSRect columnRect = [self headerRectOfColumn:columnIndex];
// I want to preserve column resizing. If you do not, remove this
if (![self mouse:clickedPoint inRect:NSInsetRect(columnRect, 3, 0)]) {
return [super mouseDown:theEvent];
}
// Now, pop the cell's menu
[[[self.tableView.tableColumns objectAtIndex:columnIndex] headerCell] performClickWithFrame:columnRect inView:self];
[self setNeedsDisplay:YES];
}
- (BOOL)isOpaque {
return NO;
}
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
// Drawing code here.
}
#end
You can tie everything together in the AppDelegate -awakeFromNib or similar,
-(void) awakeFromNib {
/* NB the NSTableHeaderView class is changed to be an DataTableHeaderView in IB! */
NSUInteger numberOfColumnsWanted = 5;
for (NSUInteger i=0; i<numberOfColumnsWanted; i++) {
PopUpTableHeaderCell *headerCell;
headerCell = [[PopUpTableHeaderCell alloc] init];
[headerCell addItemWithTitle:#"item 1"];
[headerCell addItemWithTitle:#"item 2"];
[headerCell addItemWithTitle:#"item 3"];
NSTableColumn *column;
[column setHeaderCell:headerCell];
[column sizeToFit];
[_tableView addTableColumn:column];
}
/* If we don't do this we get a final (space filling) column with an unclickable (dummy) header */
[_tableView sizeLastColumnToFit];
}
Other than that I haven't figured out how to properly correct the drawing in that region.
It seems like it's the image of the last cell that is being duplicated. So I slightly more hack-ish approach would be to add a extra column to your table view with a blank name and which intentionally ignores the mouse clicks. Hopefully by setting the display properties of the last column you can make it look the way you want.
I couldn't find any NSTableView or NSTableViewDelegate method that allow control of this region, so may any other solution would be very complicated. I would be interested in a nice solution too, but I hope this gets you started!
I have this issue and i don't use NSPopUpButtonCell at all.
I just want to tell about other method how to hide this odd header. This methods will not remove an odd table column, i.e. if you have 2 'legal' columns and hide this extra 3rd column header, you will still be able to move separator between 2nd and 3rd column. But in this case you won't see redundant header even if you want to resize any column.
I still need solution how to completely remove the redundant column, and why this is happening. (and why Apple won't fix this bug?)
So... you can just calculate index of column which this header belongs to and according to this draw your header or don't. First, subclass NSTableHeaderCell and set it as a cell class for columns. Let assume your subclass named TableHeaderCell:
for column in self.tableView.tableColumns {
let col:NSTableColumn = column as! NSTableColumn
//you can operate with header cells even for view-based tableView's
//although the documentation says otherwise.
col.headerCell = TableHeaderCell(textCell: col.title)
//or what initialiser you will have
}
Then in TableHeaderCell's drawWithFrame method you should have:
override func drawWithFrame(cellFrame: NSRect, inView controlView: NSView) {
let headerView = controlView as! HashTableHeaderView
let columnIndex = headerView.columnAtPoint(cellFrame.origin)
if columnIndex == -1 {
return
}
//parent's drawWithFrame or your own draw logic:
super.drawWithFrame(cellFrame, inView: controlView)
}
After this you won't have redundant header drawn because it not belongs to any column and columnAtPoint method will return -1.
Hey I just had a question regarding XCode's behavior with multiple views implementing the same UIView class of my own creation. I am working with a tabbed application and controller, and I have multiple views on the storyboard, all of which implement a class that I created. On one of the views, I have a text field and a button, and on another, I have a text view with a startup text reading "Waiting...". As you can probably guess, I want to enter text into the text field on the first view, press the button, then display the proper output text in the textview on the other view.
My question is: is there a problem with implementing the same class between multiple views?
I have researched numerous discussions on the TextView method of setting text inside of it, but all of the suggestions between the forums say something different, and none of the methods seem to work appropriately.
[textView setText string] doesn't want to work when I switch to the other tab,
textView.text = #"Message here" doesn't work either
I'd appreciate your help, and I've attached my code for reference.
#import "MasterController.h"
#interface MasterController ()
#end
#implementation MasterController
#synthesize input;
#synthesize output;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)viewDidUnload
{
[self setInput:nil];
[self setOutput:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (IBAction)generate:(id)sender
{
[output setText:input.text];
}
- (IBAction)textFieldReturn:(id)sender
{
[sender resignFirstResponder];
}
- (void)dealloc
{
[input release];
[output release];
[super dealloc];
}
#end
//MasterController.h
#import <UIKit/UIKit.h>
#interface MasterController : UIViewController
- (IBAction)generate:(id)sender;
- (IBAction)textFieldReturn:(id)sender;
#property (retain, nonatomic) IBOutlet UITextField *input;
#property (retain, nonatomic) IBOutlet UITextView *output;
#end
If you have several views that are controlled by the same view controller, they will not communicate with each other in the way that you are trying to make them. When you call [output setText:input.text] , you are saying: set the text for the output text field for the view that you are currently on.
One somewhat hacky way of getting around this is to create a second view controller and have it inherit from your "Master." Variables are set as protected as default and will retain their information when subclassed.
If you want to communicate between the different view controllers properly, however, you should look into state injection in this question: What's the best way to communicate between view controllers? Or use a communication system such as NSNotification center. Or you could use NSCoding, all of which are fairly easy to implement.
I've made an application where you shake the phone to open a new view. All together three views, and when you shake the phone on the last view you go back to the first screen. This works fine when I'm creating new subclass controls view with their own .xib. But I would like to use this in a storyboard project, what do I need to change?
Thanks a lot on beforehand!
HERE IS THE CODE IN .H:
#import <UIKit/UIKit.h>
#import "FirstScreenViewController.h"
#import "SecondScreenViewController.h"
#interface ViewController : UIViewController
{
NSInteger currentScreen;
UIViewController* currentController;
}
#end
AND HERE IN THE .M:
#import "ViewController.h"
#implementation ViewController
-(void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark shake
-(BOOL)canBecomeFirstResponder
{
return true;
}
-(void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
if(motion == UIEventSubtypeMotionShake)
{
if (currentController)
{
[currentController.view removeFromSuperview];
currentController=nil;
}
switch (currentScreen)
{
case 0:
currentController = [[FirstScreenViewController alloc] initWithNibName:#"FirstScreenViewController" bundle:nil];
break;
case 1:
currentController = [[SecondScreenViewController alloc] initWithNibName:#"SecondScreenViewController" bundle:nil];
}
if(currentController)
{
[currentController.view setFrame:self.view.bounds];
[self.view addSubview:currentController.view];
}
currentScreen++;
if(currentScreen >2)
currentScreen=0;
}
}
#pragma mark - View lifecycle
-(void)viewDidLoad
{
[super viewDidLoad];
currentScreen = 0;
}
-(void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
#end
You need to add all three view controllers to the storyboard, and have segues between them (including one back to the first from the third) and a shake gesture recogniser attached to each scene.
The action method for each gesture recogniser tells the view controller to performSegue: with the appropriate segue identifier.
Hey everyone, I'm a newbie and I have what I anticipate will be a pretty easy question to answer. In order to learn a bit about event handling and drawing, I'm attempting to write a program that draws a black rectangle that increases in length every time the user hits the 'c' key. So far it just draws a black rectangle on a blue background without responding to keystrokes. Here is what I have so far:
Input.h
#import <Cocoa/Cocoa.h>
#interface Input : NSView {
int length;
}
- (void)keyDown:(NSEvent *)theEvent;
#end
Input.m
#import "Input.h"
#implementation Input
- (id)initWithFrame:(NSRect)frame {
self = [super initWithFrame:frame];
length = 10;
if (self) {
// Initialization code here.
}
return self;
}
- (void)drawRect:(NSRect)dirtyRect {
//set variables
NSRect r1;
NSBezierPath *bp;
// set background color
[[NSColor blueColor] set];
NSRectFill(dirtyRect);
//set color to black & draw r1
[[NSColor blackColor] set];
r1 = NSMakeRect(1, 1, length, 10);
bp = [NSBezierPath bezierPathWithRect:r1];
[bp fill];
}
- (void)keyDown:(NSEvent *)theEvent
{
NSString *key = [theEvent characters];
if ( [key isEqualToString:#"c"] ) {
length += 10;
}
}
#end
I copied the keyDown method from Cocoa in a Nutshell, by the way. Needless to say, I don't really understand it. Do I have to make connections in IB in order to get the program to recognize keystrokes? Basically, I would love it if somebody could help me to get this program to work, because as of yet I have not gotten anything to respond to keystrokes.
And here's Cocoa in a Nutshell
IIRC, to receive keystrokes your view needs to become first responder. It should work if you add something like these methods:
- (BOOL) acceptsFirstResponder
{
return YES;
}
- (BOOL) resignFirstResponder
{
return YES;
}
- (BOOL) becomeFirstResponder
{
return YES;
}
(You can do other stuff in them too, of course, if appropriate.)
Update: You also need to mark your view as needing to be redrawn. Add:
[self setNeedsDisplay:YES];
To your event handler. And it's probably a good idea to add a log message at the beginning as well, so that you can see whether the method is getting called:
NSLog(#"keyDown [%#]", [theEvent characters]);