UIView on top of a UITableView when cell is clicked? - ios

What I am trying to do is display a smaller view on top of a UITableView when a UITableViewCell is clicked. I don't want to transition to another UIViewController but "popup" a view on top of the UITableView that will house more information about the UITableViewCell clicked.
I don't think I am looking for a UIAlertView, but I am looking for a UIView that I can put labels, buttons, pictures, etc. on.
I hope my terminology is correct. I am still a newb :)
Leon
p.s. All my searching just came up with UIAlertView stuff.

Try using didSelectRowAtIndexPath delegate function of the UITableView, the code is untested to give you an idea:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Assuming view is at zero index of XIB file.
// this view will contain all lable and other controls
UIView *customView = (UIView *)[[NSBundle mainBundle] loadNibNamed:#"NameOfCustomViewXIBFile" owner:nil options:nil] objectAtIndex:0];
customView.transform = CGAffineTransformMakeScale(0.0f, 0.0f);
[self.view addSubView:customView];
[UIView animateWithDuration:0.5
animations:
^{
customView.transform = CGAffineTransformMakeScale(1.0f, 1.0f);
}
];
}
Hope it helps!
EDIT:
Animation to remove this popup:
customView.transform = CGAffineTransformMakeScale(1.0f, 1.0f);
[UIView animateWithDuration:0.5
animations:
^{
customView.transform = CGAffineTransformMakeScale(0.0f, 0.0f);
}
];
[customView removeFromSuperView];

The problem with the existing answer is that if the user scrolls the table so that the cell goes offscreen and back on, the view that you popped up is likely to be gone due to cell re-use. To avoid this, you must store something in the cell's "model" so that every time cellForRowAtIndexPath: is called, you re-generate the cell with its popup view if it is supposed to be there. Just displaying from didSelectRowAtIndexPath: may be insufficient.
The approach I'd prefer for this if I were coding it is to make all the cells your own subclass of UITableViewCell. This subclass includes an extra BOOL showPopup. In your setter setShowPopup: you set the value, and also create & show or destroy/remove/hide the "popup" subview for that cell. (You could make the subview a class member that's always around, allocate and assign it when needed, and keep a reference, just showing/hiding as needed; that's a size/space performance trade-off.)
-(void) setShowPopup:(BOOL show) {
showPopup = show;
if(show) {
// create subview, and add to view
} else {
// remove and destroy subview
}
}
And in UITableView delegate/datasource:
-(UITableViewCell) UITableView:(UITableView *table) cellForRowAtIndexPath:(NSIndexPath *ip) {
// usual stuff to get a reusable cell or allocate a new one, and prepare it for display
// then
if(showPopup) {
// create subview and add to view
} else {
// remove and destroy subview
}
}

I used a UIButton for something similar in a GLKViewController so this might work for a UITableViewController. I just disabled the button and added a rounded border so it looked like a custom popup. When the user clicked on something interesting, I changed the hidden flag on the button to show or hide it.
Something like this to make it look pop-up-y
In viewDidLoad:
// make info "popup"
_infoBtn = [UIButton buttonWithType:UIButtonTypeCustom];
_infoBtn.bounds = CGRectMake( 0, 0, kRightButtonBarDim, kRightButtonBarDim);
_infoBtn.backgroundColor = [UIColor colorWithWhite:1 alpha:0.75];
_infoBtn.selected = NO;
_infoBtn.titleLabel.font = [UIFont boldSystemFontOfSize:kTableCellFontSize];
_infoBtn.titleLabel.lineBreakMode = NSLineBreakByCharWrapping;
[_infoBtn setTitleColor:[UIColor colorWithWhite:.3 alpha:1] forState:UIControlStateDisabled];
// border
_infoBtn.layer.cornerRadius = 5; // rounded corners
// drop shadow
_infoBtn.layer.masksToBounds = NO;
_infoBtn.layer.shadowColor = [UIColor blackColor].CGColor;
_infoBtn.layer.shadowOpacity = 0.8;
_infoBtn.layer.shadowRadius = 12;
_infoBtn.layer.shadowOffset = CGSizeMake(12.0f, 12.0f);
_infoBtn.enabled = NO;
_infoBtn.hidden = YES;
[self.view addSubview:_infoBtn];
Then in tableView's didSelectRowAtIndexPath update any information needed in the button and set hidden to NO. You should be able to add any necessary subviews to this UIButton.
_infoBtn.frame = CGRectMake(20, 20, 20, 20); // set this wherever you like
[_infoBtn setTitle:#"text" forState:UIControlStateDisabled];
_infoBtn.hidden = NO;
I just tested this for a UIViewController that has a UITableView as a subview and it looked the same. Scrolling did not affect it (i.e., the button did not move with scrolling, almost like a HUD) because the button was added to the top-level UIView. Dunno if this is what you need, but hopefully it will give you some ideas.

Related

UIButton not working in UITableview

Have UITableviewcell --> inside which i have 4 different UIView and 3 of the views has UIButtons. I want to make UIButton clickable. For the first time the buttons are clickable but when i go to next screen and come back, the buttons don't work. Please let me know how to implement this? Thanks!
PHMyTripView *tripsView=[[PHMyTripView alloc] initWithFrame:CGRectMake(10, 5, self.frame.size.width-20, cell.frame.size.height)];
tripsView.onBaggageClick = ^{
[weakSelf handleBaggagePurchaseTapped];
};
if ([data count]>0) {
[tripsView fillTripData:[data firstObject]];
[tripsView showAncillaries:self.predictiveManager.upcomingCDAirBookingInfo];
}
[cell bringSubviewToFront:tripsView.bagsButton];
[cell.viewPlaceHolder addSubview:tripsView];
This happens because the cells are reusable and if you go to another screen the button may kinda mess round into different cell in UI or functionally.
The way to solve this is to add tag. You can define cell.tag = indexPath.row * 10 or so.
Then when draw the button, you check the condition, if cell.tag == ?, then add your button.
Thank you everyone for your response but they din't work in my case.
Here is the answer. Since the UITableview was reloading when it comes back to the screen.The frames were mis placed and Hence the button was not able to click.
Used this one line code which worked fine.
self.tripsView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
You should turn off delaysContentTouches on each UITableView subview, which is an instance of UIScrollView class.
Subclass UITableView and override initWithFrame method:
.h file
#interface NoDelaysOnTouchTableView : UITableView
#end
And .m file
#import "NoDelaysOnTouchTableView.h"
#implementation NoDelaysOnTouchTableView
- (id) initWithFrame: (CGRect) frame
{
self = [super initWithFrame: frame];
if (self) {
for (id view in self.subviews) {
if ([NSStringFromClass([view class]) isEqualToString: #"UITableViewWrapperView"]) {
if ([view isKindOfClass: [UIScrollView class]]) {
// turn OFF delaysContentTouches in the hidden subview
UIScrollView* scroll = (UIScrollView*)view;
scroll.delaysContentTouches = NO;
}
break;
}
}
}
return self;
}
#end
Next - use this subclass (create an instance of NoDelaysOnTouchTableView) to be able to press UIButton immediately.
I think that the causes would be multiples.
You can try:
check the constraints for each button in your cell
in cellForRow you can do addTarget: for each button with relative #selector and in this method check the object (datasource) associated to button.
do not use addSubView in your cell, instead use a Xib (or define your cell in a storyboard within tableView) so you can set the constraints.
I Hope, i've helped you.
Not specifically about this issue, but for some people it may be the case.Try to add subviews in contentView of the cell.
Instead of addSubview(textField) use contentView.addSubview(textField)

How to keep the UI-Searchbar visible when user slide upward in tableview

In my app when the user slide down the UI-searchbar become disappear, which I want but when the user slide up I want UI-Search bar become visible at once.
I want to have code that tell me when the user had slide upward in tableview cell and enable the uisearch-bar.
You can use tableHeaderView for this type of work.
In your viewDidLoad write below code.
- (void)viewDidLoad
{
**// Take one view and subview that view in the tableview.**
UIView *viewsearch=[[UIView alloc]initWithFrame:CGRectMake(0,-10, 320,83)];
[self.Yourtablename addSubview:viewsearch];
**//Now take any controls which you want to show in your header. e.x label,button,searchbar**
UILabel *lbl1 = [[UILabel alloc] init];
[lbl1 setFrame:CGRectMake(0,5,100,20)];
lbl1.backgroundColor=[UIColor clearColor];
lbl1.textColor=[UIColor whiteColor];
lbl1.userInteractionEnabled=YES;
[viewsearch addSubview:lbl1];
lbl1.text= #"BUY THE NEW APPLE TV FROM THE APPSTORE";
**//Here is the code.With the help of this code when you scroll UP the headerview hide.**
self.Yourtablename.tableHeaderView = viewsearch;
self.Yourtablename.contentOffset = CGPointMake(0, CGRectGetHeight(viewsearch.frame));
}
May be it will help you.

display the view behind tableView (or scrollView)

For example:
there is a tableView, when it is pulled down, the back view display. the effect is like this:
I tried like this but not working:
[self.view addSubview:logoView];
[self.view addSubview:tableView];
You have to
add your logo image view below the table view in xib.
set table view background color to clear color
Set logo image hidden.
in - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate or check for your self which delegate is best suited. set the logo image hidden to NO
You set the tableView background as your logoview. Keep your UITableviewCell as what color you want.
I'm not sure if i recognize your problem but i think you want something like this:
you'll have to use:
[self.view insertSubview:aboveSubview: ];
[self.view insertSubview:belowSubview: ];
not
[self.view addSubview: ];
You can achieve the same as the example image above by adding the view with a negative y offset.
UIView *header = [[UIView alloc] initWithFrame: CGRectMake(0.0f, 0.0f - self.view.bounds.size.height, self.view.bounds.size.width, self.view.bounds.size.height)];
header.backgroundColor = [UIColor lightGrayColor];
[self.tableView addSubview:header];
However if you have content in this view, such as a logo, it will appear to be pulled down from the top, rather than behind the table, I don't know if this is the effect you want or not.

UITextView can't dismiss the keyboard in programmatically-created UITableView

There seems to be lots on this subject. But I couldn't get any of the solutions to work.
My code creates a tableView full of cells with varying contents (based on a JSON), the user should enter the info in each cell. The problem I am having is, when the user taps somewhere outside the cell (i.e. on the tableView background) I want the keyboard to dismiss.
didSelectRowAtIndexPath: method is not good.
touchesBegan: does not fire at all (tableView has user interaction enabled, but I assume there is some other reason).
I have added a gesture to the tableView, but then I cannot start editing.
I know the resignFirstResponder. But I don't know which field is being edited. so I think, I need to go with the endEditing: method. But I just couldn't get it called, when user touches outside of a cell.
Any help would appreciated.
If that is a textField as #JFS said, you can set the delegate and resign it in this below method.
- (BOOL)textFieldShouldReturn:(UITextField *)textField
Else If that is a textView, You can add a toolbar with done button as inputAccessoryView to your textView and resign your textView.
I am having two more ideas
Bad Idea:
Try to make an invisible button in the cell background and add an action method to resign it. But this will get confused, when you are using didSelectRowAtIndexPath: method of your UITableView.
Good Idea:(Good one)
UITableView surely will have UIScrollview. So in the scrollViewDidScroll: method, set [self endEditing:YES] will surely work.
Good Idea 2
Create a new View or Button and place it on top of the all views, when a textView is in editing and call the endEditing: method when user touches the view or button.
TO GET A TOUCH DETECTION IN TABLEVIEW:
Some of these Q&A will help you.
https://stackoverflow.com/a/8787019/1083859
Why does my UITableView not respond to touchesBegan?
https://stackoverflow.com/a/8786706/1083859
Okay after lots of playing around a managed to figure (something) out, it is not great but works.
Most of the gaps around the table is taken up by section headers (a small amount by the cell walls). To get these areas to call a method I added a gesture to the section header like this;
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
NSString *sectionTitle = [self tableView:tableView titleForHeaderInSection:section];
if (sectionTitle == nil)
{
return nil;
}
UILabel *label = [[UILabel alloc] init];
label.frame = CGRectMake(20, 8, 320, 20);
label.backgroundColor = [UIColor clearColor];
label.textColor = [UIColor colorWithRed:76/255.0 green:86/255.0 blue:108/255.0 alpha:255/255.0];
label.shadowColor = [UIColor grayColor];
label.shadowOffset = CGSizeMake(-0.0, 0.0);
label.font = [UIFont boldSystemFontOfSize:16];
label.text = sectionTitle;
UIView *view = [[UIView alloc] init];
[view addSubview:label];
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(eventMenuTap)];
[view addGestureRecognizer:singleTap];
return view;
}
This also enabled me to customize the label for each section. The net reseult is now I have the keyboard closing when the table is scrolled and if (nearly) anywhere is clicked outside of a cell (i.e. a header) then the eventMenuTap is called.
-(void)eventMenuTap
{
NSLog(#"Tap has begun...");
[self.view endEditing:YES];
}
Thanks for all the ideas and help with this.
For any passersby, the simplest and most effective solution I have found requires 2 things:
1: Subclass your table view and add the following to its .m:
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// send your own dismiss message; you can use self.delegate to refer to TV's TVC...
[((SearchVC *)((UITableViewController *)self.delegate).parentViewController).searchBar resignFirstResponder];
// crucial!
[super touchesBegan:touches withEvent:event];
}
2: Add the following to your TVC:
- (void) scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
// send your own dismiss message...
[((SearchVC *)self.parentViewController).searchBar resignFirstResponder];
}
This works beautifully for me. I initially tried adding touchesBegan to my subclassed cell, but found that was insufficient and, after adding these two things, superfluous.

iOS - Custom UITableViewCell subviews within selectedBackgroundView

I have set up a custom UITableViewCell with multiple labels and an image, and I've (finally) got it to look how I want it to look.
I can't seem to figure out how to get the selection to look how I want it to look, however. I have implemented the setSelected method, which allows me to change the background color just fine, but what I would really like is to set the background color to black and display a colored rectangle on the left-hand side of the selected cell (10 pixels wide and the height of the cell).
The colored box would be a color set programmatically, so although I could easily set the selectedBackgroundView to be a UIImageView, this will not work in this case.
The following code will not display the selectedViewColor UIView at all when the cell is selected:
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
UIView *selectedView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.selectedBackgroundView.bounds.size.width, self.selectedBackgroundView.bounds.size.height)];
[selectedView setBackgroundColor:[UIColor blackColor]];
UIView *selectedView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, self.selectedBackgroundView.bounds.size.height)];
[selectedViewColor setBackgroundColor:[UIColor redColor]];
[selectedView addSubview:selectedViewColor];
self.selectedBackgroundView = selectedView;
[super setSelected:selected animated:animated];
}
This code seems pretty basic, so I assume there is an issue with displaying any type of subview within the selectedBackgroundView.
Any alternatives or advice would be greatly appreciated.
There's a few things that could be done better with this code. Reinitialising two views in the setSelected method is pretty inefficient. You're actually blanking out everything in the cell when you select it with this code (which I'm guessing is not what you want). And finally, you're treating selectedBackgroundView as if it's the only view that gets displayed when you select the cell (according to Apple's documentation, it is displayed over the backgroundView).
Try the following (Edited) -
Put this code where you create the cell (presumably, cellForRowAtIndexPath:)
UIView* container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, cell.backgroundView.bounds.size.width, cell.backgroundView.bounds.size.height)]; // we need this because in cells, the background views always take up the maximum width, regardless of their frames.
container.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0]; // make it transparent - we only want the square subview to be seen.
UIView *selectedViewColor = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, self.selectedBackgroundView.bounds.size.height)];
[selectedViewColor setBackgroundColor:[UIColor redColor]];
[container addSubview:selectedViewColor]
cell.selectedBackgroundView = container;
This will make your red square appear when (and only when) the cell is selected, over the other views in the cell. From Apple's docs:
UITableViewCell adds the value of this property as a subview only when the cell is selected. It adds the selected background view as a subview directly above the background view (backgroundView) if it is not nil, or behind all other views.
Second, use the following code in your cell:
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
if(selected == YES)
{
self.backgroundView.backgroundColor = [UIColor blackColor];
}
else
{
self.backgroundView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0] // replace this with whatever's appropriate - a return to the unselected state.
}
}
This will ensure that your background turns black when the cell is selected (without otherwise interfering with what's displayed. Hopefully these changes should also resolve the issue you're having.
In addition to Xono's answer above, following up on his comment on the answer above:
One thing I've come across a couple of times while researching this subject is a possibility that the code behind UITableViewCell may actually set the backgroundColor of all subviews to transparent when a cell is selected.
It does indeed do this if your cell's SelectionStyle is anything but None. And it does it in both the setHighlighted and setSelected calls of UITableViewCell.
My first solution was to subclass UITableViewCell and override both these methods, not calling the base class method and doing my own animations. This is not ideal as your now re-implenting (probably badly) standard iOS animations.
Looking into it further though, the standard methods animate the opacity of the whole view, not the subviews (they only set the color of the subviews). So the best approach is to still call the base class methods, and then just re-set your subview colors back to whatever they should be. Even though your setting them instantaneously, because their superview is still animating its opacity, it still fades in and out correctly:
public override void SetHighlighted(bool highlighted, bool animated)
{
base.SetHighlighted(highlighted, animated);
SelectedBackgroundView.Subviews[0].BackgroundColor = SelectionColor;
}
public override void SetSelected(bool selected, bool animated)
{
base.SetSelected(selected, animated);
SelectedBackgroundView.Subviews[0].BackgroundColor = SelectionColor;
}
This is c# MonoTouch code, but it applies equally well to obj-c.
Note that in my case I always have exactly 1 subview, hence the hardcoded 0 indexer. This may differ depending on your view structure.
You can override method "setBackgroundColor" for your subviews and add another method with the same functionality. At this case UITableCell won't be able to change backgroundColor after selection.
- (void)setBackgroundColor:(UIColor *)backgroundColor {
}
- (void)setColor:(UIColor *)color {
[super setBackgroundColor:color];
}
Basing on #Xono 's answer, I made this solution to the problem:
Inside of the initWithStyle:reuseIdentifier: method I added a separator view:
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
CGRect selectionViewFrame = self.contentView.bounds;
UIView *selectionView = [[UIView alloc] initWithFrame:selectionViewFrame];
[selectionView setBackgroundColor:[UIColor colorWithWhite:1. alpha:0.65]];
self.selectedBackgroundView = selectionView;
self.vwSelectedSeparator = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.contentView.frame.size.width, 1.)];
[self.vwSelectedSeparator setBackgroundColor:[UIColor colorWithHexString:#"aaa"]];
[self.vwSelectedSeparator setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
[selectionView addSubview:self.vwSelectedSeparator];
[self setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
}
return self;
}
And then in setSelected:animated: method I added these lines:
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
if (selected) {
[self.vwSelectedSeparator setBackgroundColor:[UIColor colorWithHexString:#"aaa"]];
}
}
Works like a charm for both ios6 and ios7 for me. I hope this helps.

Resources