Several TableView questions - objective-c

I am looking to create a similar interface to the iTunes iPhone app search interface. I have a few questions I can't seem to find an answer for:
Here is an image of the iTunes iPhone app search interface in question:
How do I create the tableView section subtitle, e.g. the Tap to Preview, Double-Tap to View info under the Top Hits section title.
How is the price button created to float right? Is this done natively or using a custom UIView?
Finally how would I differentiate between a single tap and double tap on any of the table view cells?

You will need to create a Custom UITableViewCell, here's a tutorial. for the price button and other visuals of the cell.
As for the Tap to Preview subtitle, you can create a custom header view, see:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
Most likely, you would need to create 2 UILabels for this view, and obviously you would want to match the fonts used here.
An Example
- (UIView *) tableview:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UIView *headerView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.bounds.size.width, 30)] autorelease];
UILabel * label = [[UILabel alloc] initWithFrame:CGRectZero];
label.text = #"Top Hits";
label.backgroundColor = [UIColor clearColor];
label.font = [UIFont boldSystemFontOfSize:17];
[headerView addSubview:label];
UILabel * label2 = [[UILabel alloc] initWithFrame:CGRectZero];
label2.text = #"Tap to Preview, Blah blah blah";
label2.backgroundColor = [UIColor clearColor];
label2.font = [UIFont fontWithName:#"Apple's Default Font?" size:17];
[headerView addSubview:label2];
/* something like this */
return headerView;
}
- (CGFloat) tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 50.0f;
}

Most of your questions are address well in Apple's Table View Programming Guide for iOS. Here are some short answers:
You can make a header for a section be a UIView, in which case you can use multiple UILabels to create titles with subtitles and the like.
This is probably set as the accessoryView of the UITableViewCell, or it may be an entirely custom subclass of UITableViewCell.
For this, you'll need to implement the UITableViewDelegate method - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath. For more on customizing this method (e.g. to differentiate between single and mutliple taps), check out the Managing Selections section of the above tutorial.

1-For the Custom header
you can use the table view datasource method
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section;
and then you can either create the view programmtically with all the labels
or you can make an seperate view in the xib ,create its instance in your viewcontroller and return that instance in the above datasource method- this approach would be much easier and simpler.
2- You can implement the price button by using a uibutton and setting it an background image
in a custom table view cell. you can hide/unhide this button as per your functionality.
3- I would suggest you to disable the tableview selection and add tap gesture recognizers to the custom table view cell. this would give you more flexibility
Hope this could help you

Related

Drawing + UITableViewCell + UIScrollView subclass?

My (rather complicated) situation is as follows:
TestView is a subclass of UIScrollView which implements -drawRect:, but at some point inside -drawRect: it'll call a method, let's say -drawAnotherPartWithRect:context:. This method is implemented by subclasses of TestView to draw individually a certain part of the context.
There are two subclasses of TestView which implement -drawAnotherPartWithRect:context:, which currently do the same thing inside it: Subclass1 and Subclass2.
As of now, frame size is the only different between the two during initialization.
An instance of Subclass1 is used as a table view's section header, and it works perfectly, yet if Subclass2 is used as a subview of the cell's content view, it'll display, yet not scroll. Its initialization is as follows:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"PortoAppSubjectViewTableViewCell"];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"PortoAppSubjectViewTableViewCell"] autorelease];
Subclass2 *contentView = [[[Subclass2 alloc] initWithFrame:CGRectMake(0.f, 0.f, [tableView bounds].size.width, 32.f)] autorelease];
[contentView setContentSize:CGSizeMake(tableView.bounds.size.width * 3, 32.f)];
[contentView setTag:55];
[[cell contentView] addSubview:contentView];
}
[(SubjectTableViewCellContentView *)[[cell contentView] viewWithTag:55] setContainer:[[[[$container subGradeContainers] objectAtIndex:[indexPath section]] subGradeContainers] objectAtIndex:[indexPath row]]];
return cell;
}
The interesting thing is, the horizontal scroll indicator shows up and shows me that it's scrolling finely, yet the text (drawn with CoreText) doesn't move left/right along with it. That works out-of-the-box with Subclass1. Additionally, if Subclass2 is used instead as the view class of the section header view, it'll work finely.
So, what's up with horizontal scroll views and table view cells? I've checked out other related questions on SO but haven't been able to find any solution.
I solved the issue by instead of drawing directly to a UIScrollView subclass, drawing to a UIView subclass added as a subview of UIScrollView.
I'd still like some follow-ups, therefore leaving the question unanswered – why did it work with the header view and not with the table view cell then?

Customization tableView

How I can add a bar with 3 UIButtons above a UITableView? Please, I need examples. I want to make it like this.
You can create a cell in your storyboard that contains a segment controller on it.
Now in the
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
You can dequeue that cell for the first on in the table.
In your viewDidLoad, create a UIView with a clear background colour.
Then, create a UISegmentedControl and add that as a subview to the clear view.
Finally, set your clear view as the table header view:
self.tableView.tableHeaderView = myClearView;
Bar is called as segmented control in iPhone.
To create it sub class UIViewControl class and add segmented control on top and then add UITableView below that better you can use Xib or you can find Coordinates and add both controls programatically.
refer to this link
you can do by implementing Header View Section delegate methods for your UITableView in your ViewController
In the following delegate method, give the size of your view you want to implement
-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return 60.0f;
}
Implement UISegmentedControl to get your three buttons and implement that in your viewForHeaderInSection method
-(UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UISegmentedControl *segmentedControl = [[UISegmentedControl alloc]initWithItems:segments] autorelease];
segmentedControl.frame = GRectMake(60, 10, 200, 40);
........
// Do other Stuffs of Segmented Control
........
return segmentedControl;
}

Customizing a UITableView with Searchbar

I have a TableView with a search bar. But I want to add another view (lets say a label) in to the TableView (so it scrolls with the tableview) . For an example, if you open iPhones Phone Contacts application, under All Numbers, you can see a lable called "My Number:". Which must be at the same hierarchical level as the searchbar. I tried to add a new label just above the search bar, but storyboards don't allow me to do that.
In here if I drag and drop a UILabel to this hierarchy it either replaces the searchbar at the top , or the label drops inside of the prototype cell. There is no other way of showing searchbar and Label both at once.
Is there any way of doing this?
Create a separate view outside the view controller's view (or inside, it doesn't matter. you can even create this programmatically) and link it to an IBOutlet myCustomView.
Create an IBOutlet searchBar and link your UISearchBar
in viewDidLoad; you can use
[searchBar addSubView:myCustomView];
and add your custom view above the search bar.
you can show/hide (myCustomView.hidden = YES / NO) the custom view or add and remove it from superview whenever you need.
ex.
- (IBAction)didTapShowCustomHeaderButton {
myCustomView.hidden = NO;
}
- (IBAction)didTapHideCustomHeaderButton {
myCustomView.hidden = YES;
}
add the below two delegates in the code
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UILabel *label = [[[UILabel alloc] initWithFrame:CGRectMake(10, 10, 100, 30)] autorelease];
label.text = #"My Label";
label.backgroundColor = [UIColor clearColor];
return label;
}
-(CGFloat)tableView:(UITableView*)tableView heightForHeaderInSection:(NSInteger)section{
return 30 // this height should be equivalent to the myLabel height u declared in headerView above
}

UITableView custom section header disappear

I have a view that I'm trying to use as a header section of my UITableView.
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UILabel *name= (UILabel *)[myView viewWithTag:200];
name.text = #"title";
myView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"row-bg-red.png"]];
return myView;
}
It loads ok, but when I scroll down and the next header appears, the previous does the opposite: it disappears.
Any suggestion?
I guess you reuse the one view. This is not possible. Each view (UIView subclass) can be in the view hierarchy exactly once. So what probably happens in your case is that when you set the second section view, it gets removed from its original place where you put it last time for the first section.
You can create every time a new section header view directly in - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section method.

adding subviews to UITableViewCell's content view makes cell unselectable

I want to add some static text to a UITableViewCell in a UITextView.
UITextView *addressField = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, 300, 75)];
[addressField setBackgroundColor:[UIColor clearColor]];
[addressField setFont:[UIFont fontWithName:#"HelveticaNeue" size:14]];
[addressField setContentInset:UIEdgeInsetsMake(0, 20, 0, 0)];
[addressField setEditable:NO];
[addressField setScrollEnabled:NO];
// change me later
[addressField setText:#"John Doe\n555 Some Street\nSan Francisco, CA, 00000"];
[cell.contentView addSubview:addressField];
[addressField release];
This works great but I this code makes the cell unselectable probably because the UITextView is covering the entire cell.
How can I work around this so that I can have both the UITextView and selectable cells?
btw, I could make the UITextView size a bit smaller but users would still not be able to select the cell if they touch the UITextView.
I think a slightly better way to do it is to create a tap gesture recognizer on the entire table. (For example in your viewDidLoad)
// gesture recognizer to make the entire cell a touch target
UITapGestureRecognizer* tap = [[UITapGestureRecognizer alloc]
initWithTarget:self action:#selector(changeFocus:)];
[tableView addGestureRecognizer:tap];
[tap release];
Then you create a selector (changeFocus: in this case) to do the actual selecting.
- (void)changeFocus:(UITapGestureRecognizer *)tap
{
if (tap.state == UIGestureRecognizerStateEnded)
{
CGPoint tapLocation = [tap locationInView:self.tableView];
NSIndexPath* path = [self.tableView indexPathForRowAtPoint:tapLocation];
[self tableView:self.tableView didSelectRowAtIndexPath:path];
}
}
You can make your changeFocus method more elaborate to prevent selections or give focus to specific subviews of the selected indexPath.
I would adopt the following approach in order to keep interaction enabled with both the UITextView and the UITableViewCell.
Declare your controller class (a UITableViewController I guess ?) as UITexView delegate.
When you declare your UITextView, set the table view controller as it's delegate.
Implement one of the UITextViewDelegate methods (ex : - (void)textViewDidChangeSelection:(UITextView *)textView) in your table view controller .m file.
From within this method you can manipulate the targeted cell either with a custom code or by triggering the tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *) delegate method through selectRowAtIndexPath:animated:scrollPosition:.
Your code might then look like :
In the table view controller .h file :
#interface MyTableViewController : UITableViewController <UITextViewDelegate> { ...
...
}
In the table view controller .m file :
UITextView *addressField = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, 300, 75)];
[addressField setDelegate:self];
...
Then implement this function for example (or any other suitable UITextViewDelegate function) :
- (void)textViewDidChangeSelection:(UITextView *)textView {
// Determine which text view triggered this method in order to target the right cell
...
// You should have obtained an indexPath here
...
// Call the following function to trigger the row selection table view delegate method
[self.tableView selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionNone]
}
Note that there are other alternatives like subclassing UITextView and deal with it's touch methods. I would recommend to use the possibilites offered by its delegate protocol though.
Note also that it might be handy to have your UITextView declared or at least referenced as an instance variable of the table view controller class. This will help you easily keep track of which addressField was hit and get the right indexPath.
[addressField setUserInteractionEnabled:NO];
I hope this helps you a bit:
[self.view insertSubview:TextView aboveSubview:TableView];
Or vice-versa based on your requirements.