I create a custom view in cocoa touch that is superclassed by UIView and in my main controller I initialize it and then add it as a subview to the main view, but when I add it to the main view it calls my initializer method again and causes an infinite loop. Am I going about creating my custom view wrong?
Here is the mainView
- (void)loadView {
UIImage* tempImage = [UIImage imageNamed: #"image1.jpg"];
CustomImageContainer *testImage = [[CustomImageContainer alloc] initWithImage: tempImage andLabel: #"test image" onTop: true atX: 10 atY: 10];
[self.view addSubview: testImage];
}
and the CustomImageContainer
-(CustomImageContainer *) initWithImage: (UIImage *)imageToAdd andLabel: (NSString *)text onTop: (BOOL) top atX: (int) x_cord atY: (int) y_cord{
UIImageView *imageview_to_add = [[UIImageView alloc] initWithImage: imageToAdd];
imageview_to_add.frame = CGRectMake(0, 0, imageToAdd.size.width, imageToAdd.size.height);
UILabel *label_to_add = [[UILabel alloc] init];
label_to_add.text = text;
label_to_add.alpha = 50;
label_to_add.backgroundColor = [UIColor blackColor];
label_to_add.textColor = [UIColor whiteColor];
[self addSubview: imageview_to_add];
self.frame = CGRectMake(x_cord, y_cord, imageToAdd.size.width, imageToAdd.size.height);
if (top) {
label_to_add.frame = CGRectMake(0, 0, imageview_to_add.frame.size.width, imageview_to_add.frame.size.height);
//[self addSubview: label_to_add];
}
else {
label_to_add.frame = CGRectMake(0,.2 * imageview_to_add.frame.size.height, imageview_to_add.frame.size.width, imageview_to_add.frame.size.height);
}
[self addSubview: label_to_add];
[super init];
return self;
}
Why did you put the [super init] statement at the end of the initializer ? When subclassing, you usually put this statement at the start of method.
For UIView subclasses, the designated initializer when creating views in code is initWithFrame:, so you should call it before adding the label and the image. You can use the image to compute the frame needed by the custom view.
-(CustomImageContainer *) initWithImage: (UIImage *)imageToAdd andLabel: (NSString *)text onTop: (BOOL) top atX: (int) x_cord atY: (int) y_cord{
// The view will gets its frame to the size of the image
UIImageView *imageview_to_add = [[UIImageView alloc] initWithImage: imageToAdd];
// Call the designated initializer
CGRect frame = CGRectMake(x_cord, y_cord, imageToAdd.size.width, imageToAdd.size.height);
self = [super initWithFrame:frame];
[self addSubview: imageview_to_add];
UILabel *label_to_add = [[UILabel alloc] init];
label_to_add.text = text;
label_to_add.alpha = 50;
label_to_add.backgroundColor = [UIColor blackColor];
label_to_add.textColor = [UIColor whiteColor];
if (top) {
label_to_add.frame = CGRectMake(0, 0, imageview_to_add.frame.size.width, imageview_to_add.frame.size.height);
}
else {
label_to_add.frame = CGRectMake(0,.2 * imageview_to_add.frame.size.height, imageview_to_add.frame.size.width, imageview_to_add.frame.size.height);
}
[self addSubview: label_to_add];
return self;
}
If you still have an infinite loop, pause the debugger and search for the recurrent method pattern in the stack trace. This pattern will gives you where the code enters the infinite loop.
Related
How to add CollectionView in NSObject controller?
I have one NSObject controller which i am accessing on each ViewController. I already added some component on it like image view. Now I want to add CollectionView on it. I have written code as follows:
in AboutMe.h file
#interface AboutMe : NSObject<UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout>
-(UIButton *) showAboutMeView:(UIViewController *)id;
#end
and in AboutMe.m file
#import "AboutMe.h"
#implementation AboutMe {
UIView *objMessageView;
UICollectionView *_collectionView
NSMutableArray *arrstrProfileImage;
NSMutableArray *arrstrUsersNameEn;
NSMutableArray *arrstrUsersNameMr;
}
-(UIButton *) showAboutMeView:(UIViewController *)id {
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenX = screenRect.origin.x;
CGFloat screenY = screenRect.origin.y;
CGFloat screenWidth = screenRect.size.width;
CGFloat screenHeight = screenRect.size.height;
arrstrProfileImage = [[NSMutableArray alloc] initWithObjects:#"male.png",#"female.png",nil];
arrstrUsersNameEn = [[NSMutableArray alloc] initWithObjects:#"Mr. (Corporator)",#"Mrs.(Corporator)", nil];
objMessageView = [[UIView alloc] initWithFrame:CGRectMake(screenX, screenY, screenWidth,screenHeight-64)];
objMessageView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:.8f];
[id.view addSubview:objMessageView];
UIImageView *objUIImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 10, screenWidth, 150)];
objUIImageView.image = [UIImage imageNamed:#"abc.png"];
objUIImageView.contentMode = UIViewContentModeScaleAspectFit;
[objMessageView addSubview:objUIImageView];
UIButton *objUIButtonOk = [[UIButton alloc] initWithFrame:CGRectMake(screenX, screenHeight-120, screenWidth, 50)];
[objUIButtonOk setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
objUIButtonOk.titleLabel.font = [UIFont boldSystemFontOfSize:25];
[objUIButtonOk setTitle:#"OK" forState:UIControlStateNormal];
[objMessageView addSubview:objUIButtonOk];
UICollectionViewFlowLayout *layout=[[UICollectionViewFlowLayout alloc] init];
_collectionView=[[UICollectionView alloc] initWithFrame:CGRectMake(objMessageView.frame.origin.x+10, objUIImageView.frame.origin.y+objUIImageView.frame.size.height+5, objMessageView.frame.size.width-20, objUIButtonOk.frame.origin.y-(objUIImageView.frame.origin.y+objUIImageView.frame.size.height+25)) collectionViewLayout:layout];
[_collectionView setDataSource:self];
[_collectionView setDelegate:self];
_collectionView.showsVerticalScrollIndicator = NO;
[_collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"cellIdentifier"];
[_collectionView setBackgroundColor:[UIColor gray]];
[objMessageView addSubview:_collectionView];
return objUIButtonOk;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return arrstrProfileImage.count;
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:#"cellIdentifier" forIndexPath:indexPath];
UIImageView *objUIImageView;
UILabel *objUILabel;
for (UILabel *lbl in cell.contentView.subviews)
{
if ([lbl isKindOfClass:[UILabel class]])
{
[lbl removeFromSuperview];
}
}
for (UIImageView *img in cell.contentView.subviews)
{
if ([img isKindOfClass:[UIImageView class]])
{
[img removeFromSuperview];
}
}
cell.backgroundColor=[UIColor lightGrayColor];
cell.layer.cornerRadius = 3;
cell.layer.masksToBounds = YES;
objUIImageView = [[UIImageView alloc] initWithFrame:CGRectMake(cell.contentView.frame.size.width/2-50, cell.contentView.frame.origin.y+25, 100, 100)];
objUIImageView.image = [UIImage imageNamed:[NSString stringWithFormat:#"%#",[arrstrProfileImage objectAtIndex:indexPath.row]]];
objUIImageView.contentMode = UIViewContentModeScaleAspectFit;
[cell.contentView addSubview:objUIImageView];
objUILabel = [[UILabel alloc] initWithFrame:CGRectMake(cell.contentView.frame.origin.x+5, objUIImageView.frame.size.height+20, cell.contentView.frame.size.width-10, cell.contentView.frame.size.height - (objUIImageView.frame.size.height+20))];
objUILabel.backgroundColor = [UIColor clearColor];
objUILabel.textAlignment = NSTextAlignmentCenter;
objUILabel.numberOfLines = 0;
objUILabel.lineBreakMode = NSLineBreakByWordWrapping;
objUILabel.font = [UIFont boldSystemFontOfSize:16];
objUILabel.textColor = [UIColor blackColor];
if ([[NSString stringWithFormat:#"%#",[UserDefault objectForKey:#"lang"]] isEqualToString:#"M"]) {
objUILabel.text = [arrstrUsersNameMr objectAtIndex:indexPath.row];
}else{
objUILabel.text = [arrstrUsersNameEn objectAtIndex:indexPath.row];
}
[cell.contentView addSubview:objUILabel];
return cell;
}
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return CGSizeMake(objMessageView.frame.size.width/2 -15,objMessageView.frame.size.width/2 -15);
}
#end
I am accessing this in ViewController as:
AboutMe *objAboutMe = [[AboutMe alloc] init];
UIButton *objBtn = [objAboutMe showAboutMeView:self];
[objBtn addTarget:self action:#selector(click:) forControlEvents:UIControlEventTouchUpInside];
A blank white view get loaded.
Here Problem is I am not able to set Delegate to CollectionView.
Please Help me in this.
You're CollectionView delegate won't work unless you change inheritation of your AboutMe class.
So you need to update this line and inherit from UIViewController:
#interface AboutMe : UICollectionViewController <UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout>
Also I would make an additional suggestion. When working with method like this:
-(UIButton *) showAboutMeView:(UIViewController *)id {
Try to mantain only that code, that is related to creation and returning UIButton, so for example instantiation and operations with objMessageView could be placed in another method, etc.
I have this subclass of UITextField and I would like to set a property as background color, border etc of UITextField. I don't know, if I use right method, because when I use this class for a UItextField, the UITextField doesn't change.. In which method I have to declare this properties?
#import "defaultUITextField.h"
#implementation defaultUITextField
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.delegate = self;
[self setBackgroundColor:([UIColor redColor])];
UIColor *borderColor = [UIColor colorWithRed:233.0/255.0 green:233.0/255.0 blue:233.0/255.0 alpha:233.0/255.0];
self.leftView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 5, 20)];
self.leftViewMode = UITextFieldViewModeAlways;
self.layer.borderColor = [borderColor CGColor];
self.layer.borderWidth = 1.0f;
}
return self;
}
#end
your solution seems to be right.
how did you place your suctom TextField on a View?
If you created your TextField in Interface Builder then you overrided the wrong constructor.
- (id)initWithCoder:(NSCoder *)inCoder {
if (self = [super initWithCoder:inCoder]) {
self.delegate = self;
[self setBackgroundColor:([UIColor redColor])];
UIColor *borderColor = [UIColor colorWithRed:233.0/255.0 green:233.0/255.0 blue:233.0/255.0 alpha:233.0/255.0];
self.leftView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 5, 20)];
self.leftViewMode = UITextFieldViewModeAlways;
self.layer.borderColor = [borderColor CGColor];
self.layer.borderWidth = 1.0f;
}
return self;
}
this constructor is called when you create UITextField in IB and change its class to UItextField.
Basically, it's a very simple demand, but I've tried several methods and none of them works as expected. The closest functioning snippet is:
#import "ViewController.h"
#implementation ViewController
- (void)dealloc
{
[scrollView release];
scrollView = nil;
[super dealloc];
}
- (id)init
{
if (self = [super init])
{
self.title = #"Pictures";
scrollView = [[UIScrollView alloc] init];
scrollView.delegate = self;
scrollView.frame = CGRectMake(0.0f, 0.0f, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);
scrollView.contentSize = CGSizeMake([UIScreen mainScreen].bounds.size.width * 10, scrollView.bounds.size.height);
scrollView.showsVerticalScrollIndicator = NO;
scrollView.showsHorizontalScrollIndicator = NO;
scrollView.pagingEnabled = YES;
scrollView.userInteractionEnabled = YES;
scrollView.backgroundColor = [UIColor blackColor];
self.wantsFullScreenLayout = YES;
self.automaticallyAdjustsScrollViewInsets = NO;
isHidden = NO;
}
return self;
}
- (void)viewDidLoad
{
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tap:)];
[scrollView addGestureRecognizer:tapGesture];
[tapGesture setNumberOfTapsRequired:1];
[tapGesture release];
for (int i = 0; i < 10; i++)
{
UIImage *image = [[UIImage alloc] initWithContentsOfFile:[NSString stringWithFormat:#"/path/to/%d.png", i + 1]];
UIImageView *imageView= [[UIImageView alloc] initWithFrame:CGRectMake([UIScreen mainScreen].bounds.size.width * i, 0.0f, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)];
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.image = image;
[scrollView addSubview:imageView];
[image release];
[imageView release];
}
[self.view addSubview:scrollView];
}
- (void)tap:(UITapGestureRecognizer *)gesture
{
[UINavigationBar setAnimationDuration:1.0];
[UINavigationBar beginAnimations:#"HideTopBars" context:nil];
isHidden = !isHidden;
// [self setNeedsStatusBarAppearanceUpdate];
self.navigationController.navigationBar.alpha = isHidden ? 0.0f : 1.0f;
[UINavigationBar commitAnimations];
}
- (void)scrollViewDidScroll:(UIScrollView *)view
{
// further operation
}
- (BOOL)prefersStatusBarHidden
{
return isHidden;
}
#end
Without "[self setNeedsStatusBarAppearanceUpdate]", navigation bar does fade as expected, but texts on status bar remain visible, which I guess is because status bar takes navigation bar as it's background image and status bar itself doesn't fade; With "[self setNeedsStatusBarAppearanceUpdate]", the texts also fade, but navigation bar's animation becomes sliding in/out from the top of the screen along with fade effect. I've also tried to move "[self setNeedsStatusBarAppearanceUpdate]" into prefersStatusBarHidden, but that just made navigation bar visible forever. I believe this is not an odd demand, so I bet there're better and simpler solutions. Any idea?
I'm trying to connect a gesture to a UIView so I can tap on the object, but it is not working. What am I doing wrong?
Shape.h
#import <UIKit/UIKit.h>
#interface Shape : UIView;
- (id) initWithX: (int)xVal andY: (int)yVal;
#end
Shape.m
#import "Shape.h"
#implementation Shape
- (id) initWithX:(int )xVal andY:(int)yVal {
self = [super init];
UIView *shape = [[UIView alloc] initWithFrame:CGRectMake(xVal, yVal, 10, 10)];
shape.backgroundColor = [UIColor redColor];
shape.userInteractionEnabled = YES;
[self addSubview:shape];
return self;
}
#end
MODIFIED CODE: The following code is in the main ViewController. I have removed the UITapGestureRecognizer from the Shape class. The code works if I make the following change, but then it is 'box' that responds to the tap gesture, not 'shape':
[shape addGestureRecognizer:tap];
to
[box addGestureRecognizer:tap];
- (void)handlerTap:(UITapGestureRecognizer *)recognizer {
//CGPoint location = [recognizer locationInView:[recognizer.view superview]];
NSLog(#"Success");
}
-(void)drawShapes{
NSLog(#"Draw");
if(!box){
box = [[UIView alloc] initWithFrame:CGRectMake(0, 0, screenWidth, screenHeight-100)];
box.backgroundColor = [UIColor colorWithRed: 0.8 green: 0.8 blue: 0.0 alpha:0.2];
[self.view addSubview:box];
}
for (int i = 0; i<5; i++) {
int x = arc4random() % screenWidth;
int y = arc4random() % screenHeight;
Shape * shape =[[Shape alloc] initWithX:x andY:y ];
[box addSubview:shape];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] init];
[tap setNumberOfTapsRequired:1];
[tap addTarget:self action:#selector(handlerTap:)];
[box addGestureRecognizer:tap];
}
}
SOLUTION: I have learned that
self = [super init];
needs to be changed to include a CGRECT that defines the boundaries of the view that *shape is placed into.
self = [super initWithFrame:CGRectMake(xVal, yVal, 10, 10)];
Also, *shape needs to be placed at 0,0 to ensure its correct placement within its parent.
UIView *shape = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
#import "Shape.h"
#implementation Shape
- (id) initWithX:(int )xVal andY:(int)yVal {
self = [super initWithFrame:CGRectMake(xVal, yVal, 10, 10)];
UIView *shape = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
shape.backgroundColor = [UIColor redColor];
shape.userInteractionEnabled = YES;
[self addSubview:shape];
return self;
}
#end
You should set the target of the gesture recognizer to self, not the view, because you implemented the handlerTap: method in the Shape class.
I am building an application (without interface builder!) which 'lives' in the NSStatusBar; when you click on an icon in the StatusBar a NSWindow with a NSScrollView appears. The window appears but it seems that something is preventing user interaction with the ScrollView
To find out where the problem comes from I also added my view to the main windows contentView in the AppDelegate, strange thing is that the scrollview is interactive in the MainWindow... Anyone knows why it doesn't work in my new Window?
This is the code I use to create the new TTDropDownWindow:
- (void)openWindow {
// Dropdown
if (self.dropDownWindow == nil) {
self.dropDownWindow = [[TTDropDownWindow alloc] init];
self.dropDownWindow.releasedWhenClosed = NO;
self.dropDownWindow.contentView = self.view;
self.dropDownWindow.backgroundColor = [NSColor clearColor];
self.dropDownWindow.delegate = self;
self.dropDownWindow.alphaValue = 1;
self.dropDownWindow.hasShadow = NO;
self.dropDownWindow.opaque = NO;
}
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
NSRect statusBarContentRect = self.statusBarItemView.window.frame;
NSPoint statusBarOriginPoint = NSMakePoint(NSMidX(statusBarContentRect), NSMinY(statusBarContentRect));
NSRect screenFrame = self.dropDownWindow.screen.frame;
NSRect dropDownContentRect = NSZeroRect;
dropDownContentRect.size.width = DROP_DOWN_WIDTH;
dropDownContentRect.size.height = DROP_DOWN_HEIGHT;
dropDownContentRect.origin.x = statusBarOriginPoint.x - DROP_DOWN_WIDTH / 2;
dropDownContentRect.origin.y = screenFrame.size.height - DROP_DOWN_HEIGHT - NSStatusBar.systemStatusBar.thickness;
[self.dropDownWindow setFrame:dropDownContentRect display:YES];
[self.dropDownWindow makeKeyAndOrderFront:nil];
}
This is the implementation of TTDropDownWindow:
#import "TTDropDownWindow.h"
#import "WFConstants.h"
#implementation TTDropDownWindow
- (id) init
{
self = [super initWithContentRect:NSMakeRect(0, 0, DROP_DOWN_WIDTH, DROP_DOWN_HEIGHT) styleMask:NSBorderlessWindowMask backing:NSBackingStoreRetained defer:NO];
return self;
}
- (BOOL)canBecomeMainWindow {
return YES;
}
- (BOOL)canBecomeKeyWindow {
return YES;
}
#end
And this is the code that creates the View and the ScrollView
#import "TTStatusBarDropDownView.h"
#import "TTTestView.h"
#implementation TTStatusBarDropDownView
#synthesize dropDownTableViewData = dropDownTableViewData_;
- (id)initWithFrame:(NSRect)frameRect {
self = [super initWithFrame:frameRect];
if (self) {
NSImageView *imageView = [[NSImageView alloc] initWithFrame:frameRect];
imageView.image = [NSImage imageNamed:#"background-dropdown"];
[self addSubview:imageView];
// first create a view to put in a ScrollView
NSView *scrollViewHolder = [[TTTestView alloc] initWithFrame:NSMakeRect(19, 98, 414, 543) andColor:[NSColor yellowColor]];
[self addSubview:scrollViewHolder];
// create the scrollView
NSScrollView *scrollView = [[NSScrollView alloc] initWithFrame:NSMakeRect(0, 0, 414, 543)];
scrollView.hasVerticalRuler = YES;
scrollView.hasVerticalScroller = YES;
[scrollViewHolder addSubview:scrollView];
// TTTestView is just a NSView with a background drawing
TTTestView *theViewThatScrolls = [[TTTestView alloc] initWithFrame:NSMakeRect(0, 0, 200, 10000) andColor:[NSColor blueColor]];
[theViewThatScrolls addSubview:[[TTTestView alloc] initWithFrame:NSMakeRect(10, 10, 100, 8000) andColor:[NSColor grayColor]]];
[scrollView setDocumentView:theViewThatScrolls];
}
return self;
}
#end
You might change NSBackingStoreRetained to NSBackingStoreBuffered as stated over here:
NSScrollView in a NSWindow