UITableViewController - Drop down table view to show a new UIView - ios

I'm trying to design a UITableViewController such that when the user hits the "Search" button on the navigation bar, the table view drops down and a UIView drops down from the navigation bar. Then, when the user taps anywhere outside of the UIView, the UIView should retract and the table view should return to its original position.
Currently, I have the following method that is the selector for the "Search" button. Note - self.searchBar is a custom UIView subclass.
Is there a cleaner/better way to accomplish this? Also I'm not sure how to get rid of the view after the user taps out of the search menu... I'm guessing I should call, [self.searchBar removeFromSuperview]; but not sure in which delegate method to put that line.
Thanks!
- (void)_showSearchMenu
{
CGRect frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height * .25);
frame.origin.y = CGRectGetMaxY(self.navigationController.navigationBar.frame) - frame.size.height;
self.searchBar.frame = frame;
[self.navigationController.navigationBar.superview insertSubview:self.searchBar belowSubview:self.navigationController.navigationBar];
[UIView animateWithDuration:0.5 animations:^{
CGRect frame = self.searchBar.frame;
frame.origin.y = CGRectGetMaxY(self.navigationController.navigationBar.frame);
self.searchBar.frame = frame;
self.tableView.contentOffset = CGPointMake(0, -250);
}];
}
To be more clear, I'm trying to achieve something similar to the effect seen in the HotelTonight app here (the second screen shows what happens when you hit the top right bar button)

This is I think the best approach for that, use these delegates:
(CGFloat) tableView:(UITableView *)tableView
heightForHeaderInSection:(NSInteger)section (UIView *)
tableView:(UITableView *)tableView
viewForHeaderInSection:(NSInteger)section
How:
Create a BOOL isOpen with a default value of NO
When you click the Search Button, implement this:
(void) searchButtonTouch:(id)sender {
isOpen = (isOpen) ? YES : NO;
isOpen = !isOpen;
[self.urTableView reloadData];
}
Now in your delegates:
(CGFloat) tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return (isOpen) ? 170.0f : 0.0f;
}
(UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
CGFloat height = [self tableView:tableView heightForHeaderInSection:section];
UIView *vw = [[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, height)];
vw.backgroundColor = [UIColor yellowColor];
// add other controls here in your UIView
// or
// just add a UIView at top of your UITableView
// then add other controls to it (if ur using storyboard)
return vw;
}

Add Tapgesture on superview
In TapGesture Action check in if is searchBar view visible
If Visible hide DropDown view by setting new frame with height zero
You can Add Tap Gesture Programmatically or from Interface Builder , You can use its delegate method "shouldReceiveTouch" or any other custom action.
Gesture Implementation

Related

Scroll view with a special effect

I want to make a screen with like the video I attach.
I want to scroll until a part of the screen, then, that part sticks in the top and I can go on scrolling.
sample video
For Name and Image create customview.
yourTable.tableHeaderView = yourCustomView_Name_image;
For message,call,contact Create customview with 4 UIButtons
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
if(section == 0)//do this if you have multiple section.
return youroutletforcustomview_message_call_contact;
return nil;
}
Maybe this will help you . :)
One possible solution using hard-coded values for a contrived example:
In your view controller create two properties:
#property (nonatomic, strong) UIView *stickyHeader;
#property (nonatomic, assign) CGFloat stickyHeaderYPos;
in viewDidLoad:
self.stickyHeader = [[UIView alloc] initWithFrame:CGRectMake(0, 100.0, 320.0, 100.0)];
self.stickyHeader.backgroundColor = [UIColor blueColor];
[self.scrollView addSubview:self.stickyHeader];
self.stickyHeaderYPos = self.stickyHeader.frame.origin.y;
// Allow us to scroll to test
self.scrollView.contentSize = CGSizeMake(320.0, 2000.0);
Set the view controller as the UIScrollView's delegate, and implement scrollViewDidScroll
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (scrollView.contentOffset.y > self.stickyHeaderYPos) {
CGRect frame = self.stickyHeader.frame;
frame.origin.y = scrollView.contentOffset.y;
self.stickyHeader.frame = frame;
}
}
Make the thing which should stick to the top a table view section header.

Hiding UITableView footer

I am unable to hide my UITableView footer (i.e. setting it's height to 0 and animating the transition).
I tried to wrap tableView.tableViewFooter.height = 0 (and tableView.tableViewFooter = nil) between [tableView beginUpdates] and [tableView endUpdates] but it doesn't work.
Implementing the method below creates another footer.
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
return 50;
}
Is there a difference between a tableview footer and a section footer? I created mine by dropping a button under my tableview in my storyboard.
Any ideas to do this simply?
Ok here's how I solved this problem.
- (void)refreshTableFooterButton
{
if (should be visible) {
self.tableView.tableFooterView = self.tableFooterButton;
} else {
self.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
}
}
I used [[UIView alloc] initWithFrame:CGRectZero instead of nil to prevent unwanted empty cells to appear in the tableview.
I didn't need an animation block, but other people might.
[UIView animateWithDuration:0.5 animations:^{
}];
Also, i had to keep a strong reference to my tableFooterButton IBOutlet. That was part of why my initial attempt at solving the problem failed. I'm not sure if having a strong reference to an IBOutlet is good practice though. Feel free to leave a comment about that.
using the following code :
self.tableView.tableFooterView?.hidden = false
This should do the trick. There are other alternatives such as this answer here.
tableView.sectionHeaderHeight = 0.0;
tableView.sectionFooterHeight = 0.0;
-(CGFloat)tableView:(UITableView*)tableView heightForHeaderInSection:(NSInteger)section
{
return 1.0;
-(CGFloat)tableView:(UITableView*)tableView heightForFooterInSection:(NSInteger)section
{
return 1.0;
}
-(UIView*)tableView:(UITableView*)tableView viewForHeaderInSection:(NSInteger)section
{
return [[[UIView alloc] initWithFrame:CGRectZero] autorelease];
}
-(UIView*)tableView:(UITableView*)tableView viewForFooterInSection:(NSInteger)section
{
return [[[UIView alloc] initWithFrame:CGRectZero] autorelease];
}`
use following methods :
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 0.0f;
}
-(UIView*)tableView:(UITableView*)tableView viewForFooterInSection:(NSInteger)section
{
return [[[UIView alloc] initWithFrame:CGRectZero] autorelease];
}`
So in the end here's the simplest solution I can give you. So as you can see I just put the .m (for simplicity).
There is a difference between table footer and section footer. What you're looking for is the section footer.
I also added an animation block for adding and removing it.
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
UIButton *_footerButton;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self createAndAddFooterButton];
}
-(void) buttonPressed:(id)button
{
[UIView animateWithDuration:2 animations:^{
self.tableView.tableFooterView = nil;
}];
}
- (void)createAndAddFooterButton
{
// here you create the button
_footerButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[_footerButton setTitle:#"Button Title" forState:UIControlStateNormal];
[_footerButton sizeToFit];
[_footerButton addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
[UIView animateWithDuration:2 animations:^{
self.tableView.tableFooterView = _footerButton;
}];
}
#end
My problem was that the clear line was the footer which I could only define as 1 pixel high and not 0 (as I do not want to have a footer).
The only way I could fix it was to provide a view in viewForFooterInSection and set the background colour to the same as the header, so that visually you don't notice, and when I animate-in new rows they do not show through the top of the header where the clear line (footer) was.
override func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let blankView = UIView(frame: CGRect(x: 0, y: 0, width: 300, height: 1))
blankView.backgroundColor = {Same colour as Header}
return blankView

iCarousel not setting label in it properly

In my code i was trying to set label in iCarouselView.My icarousel contains labels and textView so i am trying to set label but it is not setting properly.I have array of months and setting that array of months to each icarousel label, like this.
(UIView *)carousel:(iCarousel *)carousel viewForItemAtIndex:(NSUInteger)index reusingView:(UIView *)view
{
if (!view)
{
UIViewController * viewController = [self.storyboard instantiateViewControllerWithIdentifier:#"PopUpView"];
view = [viewController.view viewWithTag:999];
UILabel *label=(UILabel*)[viewController.view viewWithTag:109];
label.text = [_monthsArray objectAtIndex:index];
CGRect Frame = CGRectMake(view.frame.origin.x, view.frame.origin.y+100, view.frame.size.width, view.frame.size.height);
view.frame = Frame;
}
return view;}
I am loading external view as popUpView in storyBoard and getting label using tag.
And i am returning carousel count as [monthsArray count].
carousel delegate and datasource is also set and reloadData method is also called on iCarousel.
The output which i am getting is something like this.
| January,February,March,November,December|
Please tell me where i am wrong?and what to do now?
Update you code to below one -
- (UIView *)carousel:(iCarousel *)carousel viewForItemAtIndex:(NSUInteger)index reusingView:(UIView *)view
{
if (!view){
UIViewController * viewController = [self.storyboard instantiateViewControllerWithIdentifier:#"PopUpView"];
view = [viewController.view viewWithTag:999];
CGRect Frame = CGRectMake(view.frame.origin.x, view.frame.origin.y+100, view.frame.size.width, view.frame.size.height);
view.frame = Frame;
}
UILabel *label=(UILabel*)[view viewWithTag:109];
label.text = [_monthsArray objectAtIndex:index];
return view;
}
iCaurosel will take UIView, In your case you are creating a view controller, which is not retained and is dangerous. See if you change it to view via a custom Xib.

UITableView reorder button covering the entire cell

I've been trying to use this tutorial to make the reorder button cover the entire cell. It works great until the cell disappears from the view. Once you go back to the cell, the reorder button has shifted over quite a bit.
In this picture, the red represents the reorder button.
Here's the code used in the tutorial.
- (void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
// Grip customization code goes in here...
for(UIView* view in cell.subviews)
{
if([[[view class] description] isEqualToString:#"UITableViewCellReorderControl"])
{
UIView* resizedGripView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetMaxX(view.frame), CGRectGetMaxY(view.frame))];
[resizedGripView addSubview:view];
[cell addSubview:resizedGripView];
[resizedGripView release];
CGSize sizeDifference = CGSizeMake(resizedGripView.frame.size.width - view.frame.size.width, resizedGripView.frame.size.height - view.frame.size.height);
CGSize transformRatio = CGSizeMake(resizedGripView.frame.size.width / view.frame.size.width, resizedGripView.frame.size.height / view.frame.size.height);
// Original transform
CGAffineTransform transform = CGAffineTransformIdentity;
// Scale custom view so grip will fill entire cell
transform = CGAffineTransformScale(transform, transformRatio.width, transformRatio.height);
// Move custom view so the grip's top left aligns with the cell's top left
transform = CGAffineTransformTranslate(transform, -sizeDifference.width / 2.0, -sizeDifference.height / 2.0);
[resizedGripView setTransform:transform];
for(UIImageView* cellGrip in view.subviews)
{
if([cellGrip isKindOfClass:[UIImageView class]])
[cellGrip setImage:nil];
}
}
}
}
How do I keep the reorder control from moving to the left? I've tried to translate the transform again, but that just makes it so the reorder control is completely off the screen. What's wrong with the code that makes it move to the left and how do I fix it?
I figured out how to do it! I had to add a property to the viewController that stored the initial frame of the resizedGripView. It turns out that every time the method was being called (every time the cell appeared again), the reorder button was being moved from it's current position, so I had to store it's initial position.
UIView* resizedGripView = [[UIView alloc] init];
if (!initialFrame.size.height)
[resizedGripView setFrame: CGRectMake(0, 0, CGRectGetMaxX(view.frame), CGRectGetMaxY(view.frame))];
else
[resizedGripView setFrame: initialFrame];
if (!initialFrame.size.height)
[self setInitialFrame: resizedGripView.frame];

iOS: Place UIView on top of UITableView in fixed position

I need to put a UIView (for ads) on top of a UITableView in my iphone app. The problem is that when I scroll the table to the bottom the added UIView is scrolling with the table. What I want is for it to be fixed on the bottom of the screen. Is there a way to do that?
This is the code which I have used to add the UIView to the table:
awView = [AdWhirlView requestAdWhirlViewWithDelegate:self];
awView.autoresizingMask=UIViewAutoresizingFlexibleLeftMargin;
[self.tableView addSubview:awView];
Here is how it worked for me. The Ad stays at the bottom of the view.
In ViewDidLoad, in YourController.m:
awView = [AdWhirlView requestAdWhirlViewWithDelegate:self];
awView.center = CGPointMake(self.view.frame.size.width/2, self.view.frame.size.height-kAdWhirlViewHeight/2);
[self.view addSubview:awView];
Then add this method somewhere in the same .m file:
-(void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGRect newFrame = awView.frame;
newFrame.origin.x = 0;
newFrame.origin.y = self.tableView.contentOffset.y+(self.tableView.frame.size.height-kAdWhirlViewHeight);
awView.frame = newFrame;
}
Don't forget to declare awView.
I appreciate this is an old question. But I've found the answers either with false information in part and unclear snippets. So for what it's still worth, here is how I added a "floating" view to the bottom of my UITableViewController's view. Yes, you can do that, even if the accepted answers says you cannot.
In your -viewDidLoad method, you can create a view which we will name bottomFloatingView. This is also set up as a property.
Be sure to add a content inset to the bottom of your table view, this will avoid hiding any of the table's content with your floating view.
Next, you should use the UIScrollViewDelegate to update the frame of the floating view.
The illusion will be that your view is stuck to the bottom. In reality, this view is moving all the time you are scrolling, and is always being computed to appear at the bottom. Scroll views are very powerful ! And probably are one of the most underrated UIKit classes I think.
So here is my code. Note the property, the content inset on the table view and the -scrollViewDidScroll: delegate method implementation. I created my floating view in my storyboard which is why you can't see that being setup.
Also don't forget you should probably also use KVO to observe changes to the table view's frame. It's possible for that to change over time, the easiest way to test that is by toggling on and off the in call status bar in the simulator.
Last thing, if you're using section header views in your table view, those views will be the top most view in the table view so you'll also want to bring your floating view to the front, do this when you change its frame.
#interface MyTableViewController ()
#property (strong, nonatomic) IBOutlet UIView *bottomFloatingView;
#end
#implementation MyTableViewController
static NSString *const cellIdentifier = #"MyTableViewCell";
- (void)dealloc
{
[self.tableView removeObserver:self forKeyPath:#"frame"];
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self.tableView addSubview:self.bottomFloatingView];
self.tableView.contentInset = UIEdgeInsetsMake(0.0, 0.0, CGRectGetHeight(self.bottomFloatingView.bounds), 0.0);
self.tableView.scrollIndicatorInsets = UIEdgeInsetsMake(0.0, 0.0, CGRectGetHeight(self.bottomFloatingView.bounds), 0.0);
[self.tableView addObserver:self
forKeyPath:#"frame"
options:0
context:NULL];
}
#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 20;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
cell.textLabel.text = [NSString stringWithFormat:#"Row %d", indexPath.row];
return cell;
}
#pragma mark - UIScrollViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
[self adjustFloatingViewFrame];
}
#pragma mark - KVO
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
if([keyPath isEqualToString:#"frame"]) {
[self adjustFloatingViewFrame];
}
}
- (void)adjustFloatingViewFrame
{
CGRect newFrame = self.bottomFloatingView.frame;
newFrame.origin.x = 0;
newFrame.origin.y = self.tableView.contentOffset.y + CGRectGetHeight(self.tableView.bounds) - CGRectGetHeight(self.bottomFloatingView.bounds);
self.bottomFloatingView.frame = newFrame;
[self.tableView bringSubviewToFront:self.bottomFloatingView];
}
#end
Add your view to the superview of the table view (if possible; UITableViewControllermakes this impossible).
Add your view to the table view and reposition it in the -scrollViewDidScroll:delegate method (UITableViewDelegateis a sub-protocol of UIScrollViewDelegate).
I had a similar problem where I wanted to add a loading indicator on top of my UITableViewController. To solve this, I added my UIView as a subview of the window. That solved the problem. This is how I did it.
-(void)viewDidLoad{
[super viewDidLoad];
//get the app delegate
XYAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
//define the position of the rect based on the screen bounds
CGRect loadingViewRect = CGRectMake(self.view.bounds.size.width/2, self.view.bounds.size.height/2, 50, 50);
//create the custom view. The custom view is a property of the VIewController
self.loadingView = [[XYLoadingView alloc] initWithFrame:loadingViewRect];
//use the delegate's window object to add the custom view on top of the view controller
[delegate.window addSubview: loadingView];
}
For people like me looking for a simple solution using Swift, these answers are kind of outdated. Here's what I did (assuming myCustomView was established somewhere else in the file):
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let pixelsFromBottom = CGFloat(20)//or whatever the
let theHeight = self.tableView.frame.height + scrollView.contentOffset.y
myCustomView.frame = CGRect(x: 0, y: theHeight - pixelsFromBottom , width: self.view.frame.width, height: myCustomView.frame.height)
}
- (void)viewDidLoad
{
[super viewDidLoad];
footerView = [[UIView alloc] initWithFrame:CGRectMake(0, SCREEN_HEIGHT-64, SCREEN_WIDTH, 64)];
footerView.backgroundColor = [UIColor blueColor ];
[self.navigationController.view addSubview:footerView];
}
- (void)dealloc
{
[footerView removeFromSuperview];
}

Resources