Adding Popover to TableViewCell - objective-c

I've been struggling with this for awhile and was hoping anyone could shed some light on why this isn't working.
I'm simply try to implement a Popover on a TableViewCell. Here is the code..
TodoView.m
- (void)tableView:(TUITableView *)tableView didClickRowAtIndexPath:(TUIFastIndexPath *)indexPath withEvent:(NSEvent *)event {
// MyViewController is a TUIViewController with a nib called MyView with just a button in it
MyViewController *t = [[MyViewController alloc] initWithNibName:#"MyView" bundle:nil];
TUIView *theView = [[TUIView alloc] initWithFrame:NSMakeRect(0, 0, 300, 300)];
TUIPopover *myPopover = [[TUIPopover alloc] initWithContentViewController:t];
[myPopover showRelativeToRect:NSMakeRect(0, 0, 300, 300) ofView:theView preferredEdge:NSMaxYEdge];
}
For awhile, nothing would show up. I could tell something was happening though because the window itself would lose focus as if a Popover was there.
Sometimes I see a very small blip– like a small rectangle 2px by 2px. It's hard to see it, looks like dead pixel on the screen, but it appears sometimes when I run this code.
The TUIPopover is from the Twitter UIKit Framework.
Some possibilities...
1) The popover cannot be seen over the CGFillRect?
TodoTableViewCell.m
- (void)drawRect:(CGRect)rect
{
CGRect b = self.bounds;
CGContextRef ctx = TUIGraphicsGetCurrentContext();
CGContextSetRGBFillColor(ctx, 247.0/255, 247.0/255, 247.0/255, 1);
CGContextFillRect(ctx, b);
}
2) The popover doesn't fit inside the TableViewCell and cannot be seen
Anyone have any thoughts?

Really simple answer:
I forgot to set the content size of the popover!
So, for anyone else who is wondering why their popup isn't working, make sure you set the content size!
TUIPopover *p = [[TUIPopover alloc] initWithContentViewController:commentsViewController];
[p setAnimates:TRUE];
[p setContentSize:CGSizeMake(300, 350)];
[p setBehaviour:TUIPopoverViewControllerBehaviourTransient];
[p showRelativeToRect:b.bounds ofView:b preferredEdge:CGRectMinYEdge];

Related

UITapGesture only works after reLoad UIViewController

I have 1 year works with Objective-C and is my first question that I make because I always found the answer in this site, but this situation is completely insane and did not found anything similar.
I have a custom class (called BallClass from UIView). The UIView have an UIImageView inside on it and a UITapGesture to make an action.
So when I create the object in a UIViewController, does not works the tapAction when press in the object, but if I change to other screen and return it, the tapGesture works perfect.
I tried many options, but I cant makes work in the first load.
I work with ARC, Xcode (4.6.3) and OSX (10.8.4) and IB but this objects was created with no IB .
Thanks in advance.
Here is the class BallClass.m
- (void)tapGesture:(UIGestureRecognizer *)tapGesture {
NSLog(#"hola");
}
- (id)initBall:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
// Initialization code
// Recibir las variables iniciales para el control del timer
ball = [[Ball alloc] init];
// Agregar la imagen de la pelota en el view
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, self.frame.size.height)];
[imageView setCenter:CGPointMake(CGRectGetMidX([self bounds]), CGRectGetMidY([self bounds]))];
[imageView setContentMode:UIViewContentModeScaleAspectFit];
[imageView setImage:[UIImage imageNamed:#"pelota.png"]];
[imageView setTag:100];
[imageView setNeedsDisplay];
// Add TAP
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapGesture:)];
// Tap Properties
[tapGesture setDelaysTouchesBegan:YES];
[tapGesture setNumberOfTapsRequired:1];
[tapGesture setDelegate:(id)self];
[imageView addGestureRecognizer:tapGesture];
[self addSubview:imageView];
[self setNeedsDisplay];
// Propiedades del View
[self setUserInteractionEnabled:YES];
self.backgroundColor = [UIColor clearColor];
[self setTag:100];
// BALL BOUNCE
[NSTimer scheduledTimerWithTimeInterval:1.0 / 30.0 target:self selector:#selector(onTimer:) userInfo:nil repeats:YES];
}
return self;
}
- (void)onTimer:(NSTimer *)timerLocal {
// Do something
}
... // more methods
Here is the instantiate:
ballView00 = [[BallView alloc] initBall:CGRectMake(10, 10, 40, 40)];
The UiView show perfect, and the animation works fine, but the UITapGesture just works, as mentioned early, after reLoad the ViewController.
Here is the link to image the Ball and UIView (#kBall). Sorry, about image, but I cant load until I have 10 points :(
This might be an issue with the superview's frame. What view is holding ballView00? Does ballView lie entirely within it's superview's bounds?
Usually when you encounter problem where you're expecting a touch but don't get it it's because the view set to receive the touch is outside one of its parents' bounds.
So if the superview bounds are 100x100 and the ball is at x=125 y=125 it will not receive a touch.
A lot of magic happens when your views get laid out, it's not surprising to sometimes find one with 0x0 dimensions because of some incorrect constraints.
You can easily check the bounds of all your views by giving them a background color.
I found the solution.
The ball make a spin with this:
[UIView animateWithDuration: 0.5f
delay: 0.0f
options: UIViewAnimationOptionCurveEaseIn
animations: ^{
self.transform = CGAffineTransformRotate(self.transform, M_PI / 2);
}
completion: ^(BOOL finished) {
if (finished) {
if (animating) {
// if flag still set, keep spinning with constant speed
[self spinWithOptions: UIViewAnimationOptionCurveLinear];
}
}
}];
And generate conflict with the main timer. I change the spin action with simple add self.transform = CGAffineTransformRotate(self.transform, M_PI / 2); inside drawRect method in the class.
Apparently, I can't nested two timers, because "disable" the tapGesture, so when I change of the screen and return, the spin was stopped and this help to found this situation.
Thanks for your help.

Subclass of UIPageControl refresh only after uiscrollview move, not before

the problem I've met today is with my subclass of UIPageControl. When I initialize it, the frame (specifically the origin) and image of dots stays default, which is the problem, since I want it to change right after initialization. However, when I move with scrollView (as in "touch and move") after initialization, they (the dots) somehow jump to the right position with correct images.
What could be the problem?
Code:
CustomPageControl.m
- (id) initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
activeImage = [UIImage imageNamed:#"doton.png"];
inactiveImage = [UIImage imageNamed:#"dotoff.png"];
return self;
}
- (void) updateDots
{
for (int i = 0; i < [self.subviews count]; i++)
{
UIImageView *dot = [self.subviews objectAtIndex:i];
if (i == self.currentPage) dot.image = activeImage;
else dot.image = inactiveImage;
[dot setFrame:CGRectMake(i * 13.5, 1.5, 17, 17)];
}
}
- (void)setCurrentPage:(NSInteger)currentPage
{
[super setCurrentPage:currentPage];
[self updateDots];
}
#end
ChoosingView.m - init part
scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 160, 300)];
[scrollView setBackgroundColor:[UIColor clearColor]];
[scrollView setDelaysContentTouches:NO];
[scrollView setCanCancelContentTouches:YES];
[scrollView setClipsToBounds:NO];
[scrollView setScrollEnabled:YES];
[scrollView setPagingEnabled:YES];
[scrollView setShowsHorizontalScrollIndicator:NO];
[scrollView setShowsVerticalScrollIndicator:NO];
pageControl = [[CustomPageControl alloc] initWithFrame:CGRectMake(200, 300, 80, 20)];
[pageControl setBackgroundColor:[UIColor clearColor]];
pageControl.numberOfPages = 6;
[pageControl setCurrentPage:0];
the last line is when I would expect the UIPageControl to refresh, however that does not happen.
Does this happen with the standard UIPageControl implementation?
Your problem states that your objects subViews (eg the UIImageViews) rects/size are not initialising to your desired size/position.
I implemented this code in my project with a nib rather than programmatically and I needed to call -(void)updateDots to set it as its initial condition was the standard dots..
I dont see how the UIScrollView has any bearing impact on this unless somehow its linked to your -(void)updateDots function (E.g. your setting the currentIndex of your custom page control). You state, "However, when I move with scrollView (as in "touch and move") after initialization, they (the dots) somehow jump to the right position with correct images."
Because they "jump to the right position with correct images" it means that your -(void)updateDots function must be getting called. I dont see any other explanation.
Also your iteration loop assumes that all the UIViews in your .subViews array are UIImageViews, although fairly safe to assume this, I would check to see if the UIView is a UIImageView with reflection.

iOS Horizontal Scrolling Calendar

Some background. I'm helping a group of students at my son's school and they want to write a simple tracking app that managers student observations that will be used on iPod Touch.
I've only done very basic iOS development using the standard widgets, but I'm keen to help.
We worked through and designed the functionality and interface of the app and are now starting to program. Where I am out of my depth is that they want to have a strip running along the bottom of the screen with each day as a little block displaying the date and date and an indicator to show if there was an observation for that day.
I was hoping that you guys might be able to point me in the right direction, either an existing widget or explain in detail how to achieve this. I've tried a few approaches with no luck.
I'd appreciate any assistance with this as I know this must be a common requirement, but I'm struggling to get through this.
I thought I'd post my final solution in case others find it useful.
In view root view controller I added a custom UITableViewController which basically rotates the table 90 degrees and then rotates each table cell -90 degrees. It does what I want is was pretty straight forward.
Code for root view controller. This sets the size and position of the table :
scrollingDateViewController=[[ScrollingDateViewController alloc] initWithNibName:#"ScrollingDateView" bundle:[NSBundle mainBundle]];
CGRect rect=CGRectMake(0,330,320,100);
scrollingDateViewController.view.frame=rect;
scrollingDateViewController.view.backgroundColor=[UIColor clearColor];
scrollingDateViewController.delegate = self;
[self.view addSubview:scrollingDateViewController.view];
Key Code for ScrollingDateViewController. This rotates the table 90 degrees and the each cell -90 degress :
- (void)viewDidLoad {
today = [[NSDate alloc] init];
CGRect rect=self.view.frame;
myTableView.frame=rect;
myTableView.layer.transform = CATransform3DRotate(CATransform3DIdentity,1.57079633,0,0,1);
myTableView.backgroundColor=[UIColor clearColor];
myTableView.separatorColor=[UIColor clearColor];
myTableView.frame=rect;
myTableView.rowHeight=44; // cellWidth
myTableView.showsHorizontalScrollIndicator=NO;
myTableView.showsVerticalScrollIndicator=NO;
myTableView.separatorColor=nil;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:#"tableCell"];
if(!cell){
cell=[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"tableCell"];
cell.contentView.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:#"cell_back.png"]];
cell.contentView.transform = CGAffineTransformMakeRotation(-1.57079633);
cell.selectionStyle=UITableViewCellSelectionStyleGray;
// Add background image view
CGRect rect=CGRectZero;
UIImageView *imgView=[[UIImageView alloc] initWithFrame:rect];
imgView.contentMode=UIViewContentModeScaleToFill;
imgView.layer.transform = CATransform3DRotate(CATransform3DIdentity,-1.57079633,0,0,1);
imgView.tag=101;
[cell addSubview:imgView];
rect.origin.x=0;
rect.origin.y=0;
rect.size.height=80;
rect.size.width=44;
imgView.frame=rect;
[imgView release];
// Add Day Label
UILabel *dayLabel=[[UILabel alloc] initWithFrame:rect];
dayLabel.layer.transform = CATransform3DRotate(CATransform3DIdentity,-1.57079633,0,0,1);
dayLabel.tag=102;
dayLabel.font = [UIFont fontWithName:#"Geogrotesque-Medium" size:14.0];
dayLabel.textAlignment=UITextAlignmentCenter;
dayLabel.backgroundColor=[UIColor clearColor];
dayLabel.textColor=[UIColor darkGrayColor];
[cell addSubview:dayLabel];
rect.origin.x=40;
rect.origin.y=0;
rect.size.height=44;
rect.size.width=20;
dayLabel.frame=rect;
[dayLabel release];
// Add Date Label
UILabel *dateLabel=[[UILabel alloc] initWithFrame:rect];
dateLabel.layer.transform = CATransform3DRotate(CATransform3DIdentity,-1.57079633,0,0,1);
dateLabel.tag=103;
dateLabel.font = [UIFont fontWithName:#"Geogrotesque-Bold" size:18.0 ];
dateLabel.textAlignment=UITextAlignmentCenter;
dateLabel.backgroundColor=[UIColor clearColor];
dateLabel.textColor=[UIColor darkGrayColor];
[cell addSubview:dateLabel];
rect.origin.x=55;
rect.origin.y=0;
rect.size.height=44;
rect.size.width=20;
dateLabel.frame=rect;
[dateLabel release];
}
UILabel *label=(UILabel*)[cell viewWithTag:102];
label.text= [self getDayString:displayDate];
label=(UILabel*)[cell viewWithTag:103];
label.text= [self getDateString:displayDate];
return cell;
}
IMHO, you should create a view which you want to be shown for each date. Create something like
#interface DayView : UIView {
You can implement it with nib or make everything programmatically in drawRect method.
After it go to your Xcode documentation and search for UIScrollView. Xcode will provide your with code samples, use project "Scrolling" to find out how to use scrollView. In this sample they scroll pics, and you replace them with our custom DayViews.
Good luck!

Position of UIScrollView after change in orientation

I have a UIScrollView with an image inside it. This is the code:
- (void)viewDidLoad {
[super viewDidLoad];
UIImageView *imView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:imageName]];
UIScrollView *imScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 320, 96)];
[imScrollView addSubview:imView];
[imScrollView setContentSize:CGSizeMake(530, 96)];
[[self view] addSubview:imScrollView];
[imView release];
[imScrollView release];
}
This is what it looks like in portrait mode:
I want to know
1. How can I position the image exactly in the middle of the screen (horizontally).
2. How can I make sure this is going to be the same if the orientation switches to landscape. This is what currently the landscape looks like :
Thanks.
Try setting the autoresizingMask property of your imView just after you create it:
imView.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin;
The UIView class reference contains more info.

Programmatically creating an NSTableView (trouble getting the NSHeaderView to show up)(cocoa osx)

I am making an NSTableView programmatically but for some reason no matter what I do, I cannot make the darn headerView show up. It is imperative that I do this programmatically and not use the IB because I am actually developing this widget in an IDE called clozure cl which is a lisp ide that includes a cocoa bridge. Originally I thought this problem might have been caused by my development environement but I just created an example in Xcode using only objective C and it seems that the problem persists. What I do is pretty straightforward:
I make a window in the IB and in its awkefromnib methods I create and setup a table-view here is the code:
- (void)awakeFromNib {
mydatasource *data = [[mydatasource alloc] init];
NSTableColumn *column = [[NSTableColumn alloc] initWithIdentifier:#"id"];
NSTableView *table = [[NSTableView alloc] initWithFrame: [[self
contentView]frame]];
[table setDataSource:data];
[table addTableColumn:column];
[table addTableColumn:column];
[[self contentView] addSubview:table];
}
Here is the code for my data source object:
- (int)numberOfRowsInTableView:(NSTableView *)aTableView
{
printf("NUM ROwS");
return 4;
}
- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
{
printf("THE OTHER ONE");
return #"OKAY";
}
With this code I get a window with two colums and four rows and each cell displaying the string "OKAY", this is all fine and good except the table has no header. This might make sense except when I look at the tables header method, it has an initialized header with a frame whose values make sense. I am just wondering why I do not see it. Is there some special kind of magic I need to do so the header will display? I cannot seem to find any clues in the documentation. Once again it is imperative for the lisp ide that this be done programmatically so it would not be helpful no suggest using the IB which I know will have a working headerView. Thanks a lot.
Here is some code to programmatically create a table view with a scroll bar, and multiple columns.
// create a table view and a scroll view
NSScrollView * tableContainer = [[NSScrollView alloc] initWithFrame:NSMakeRect(10, 10, 380, 200)];
NSTableView * tableView = [[NSTableView alloc] initWithFrame:NSMakeRect(0, 0, 364, 200)];
// create columns for our table
NSTableColumn * column1 = [[NSTableColumn alloc] initWithIdentifier:#"Col1"];
NSTableColumn * column2 = [[NSTableColumn alloc] initWithIdentifier:#"Col2"];
[column1 setWidth:252];
[column2 setWidth:198];
// generally you want to add at least one column to the table view.
[tableView addTableColumn:column1];
[tableView addTableColumn:column2];
[tableView setDelegate:self];
[tableView setDataSource:self];
[tableView reloadData];
// embed the table view in the scroll view, and add the scroll view
// to our window.
[tableContainer setDocumentView:tableView];
[tableContainer setHasVerticalScroller:YES];
[[self contentView] addSubview:tableContainer];
[tableContainer release];
[tableView release];
[column1 release];
[column2 release];
Just thought I would post this for anyone still looking for a straight forward answer. :)
I wrote this Swift version of #Alex Nichol's answer:
let tableContainer = NSScrollView(frame:NSMakeRect(10, 10, 380, 200))
let tableView = NSTableView(frame:NSMakeRect(0, 0, 364, 200))
let column1 = NSTableColumn(identifier: "Col1")
let column2 = NSTableColumn(identifier: "Col2")
column1.width = 252
column2.width = 198
tableView.addTableColumn(column1)
tableView.addTableColumn(column2)
tableView.setDelegate(self)
tableView.setDataSource(self)
tableView.reloadData()
tableContainer.documentView = tableView
tableContainer.hasVerticalScroller = true
window.contentView.addSubview(tableContainer)
It worked.
Well I answered my own question and I thought this might be helpful to someone else, it seems that that the headerView will only show up if you add the tableview to a scrollview.