I have a UISearchController just over my UITableView and my table has many recrods. When a user goes to bottom in the table, he has to come back to top to see the search bar. Below you can see how I create the search bar:
- (void) showSearchBar {
_searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
self.searchController.searchResultsUpdater = self;
self.searchController.searchBar.placeholder = nil;
[self.searchController.searchBar sizeToFit];
self.tableView.tableHeaderView = self.searchController.searchBar;
//self.sharedNavigationItem.titleView = _searchController.searchBar;
self.searchController.delegate = self;
self.searchController.dimsBackgroundDuringPresentation = NO; // default is YES
self.searchController.searchBar.delegate = self; // so we can monitor text changes + others
self.definesPresentationContext = YES;
_searchController.hidesNavigationBarDuringPresentation = NO;
}
I was wondering how to show the search bar when I scroll down (go up) in the table and hide it back when I scroll up (go down) in the table even I am at the bottom of the table.
The search bar can be placed arbitrarily in the UI. Create a sibling view to the table view, placed -- for example -- above the table. Give that view a height constraint set initially to 44px and provide outlets to both the view and the constraint...
#property(weak,nonatomic) IBOutlet UIView *searchBarContainerView;
#property(weak,nonatomic) IBOutlet NSLayoutConstraint *searchBarHeightConstraint;
Now, your setup code changes to:
// ...
self.searchBarHeightConstraint.constant = self.searchController.searchBar.bounds.size.height;
[self.searchBarContainerView addSubview:self.searchController.searchBar];
// ...
If you make the header stay at top, then the search field should stay visible
UITableViewStylePlain: A plain table view. Any section headers or footers are displayed as inline separators and float when the table view is scrolled.
UITableViewStyleGrouped: A table view whose sections present distinct groups of rows. The section headers and footers do not float.
I trying to help you out with what I did, hope it helps you.
This is how I added my label in header view of table view, I tried to replace it by your search controller;
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
CGRect frame = CGRectMake(0, 0, tableView.frame.size.width, 40);
UIView *view = [[UIView alloc] initWithFrame:frame];
view.backgroundColor = [UIColor clearColor];
view.autoresizingMask = UIViewAutoresizingFlexibleWidth;
_searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
self.searchController.searchResultsUpdater = self;
self.searchController.searchBar.placeholder = nil;
[self.searchController.searchBar sizeToFit];
[view addSubview:_searchController];
view.tag = 123;
return view;
}
If you wish to hide effect at complete end of dragging move use below method;
-(void)scrollViewWillEndDragging:(UIScrollView *)scrollView
withVelocity:(CGPoint)velocity
targetContentOffset:(inout CGPoint *)targetContentOffset{
if (velocity.y > 0){
NSLog(#"up");
[self.view viewWithTag:123].hidden = true;
}
if (velocity.y < 0){
NSLog(#"down");
[self.view viewWithTag:123].hidden = false;
}
And for immediate changes of scrolling the tableview use below method :
-(void)scrollViewDidScroll:(UIScrollView *)scrollView //working delegate
{
if ([scrollView.panGestureRecognizer translationInView:scrollView].y > 0) {
NSLog(#"down");
[self.view viewWithTag:123].hidden = false;
} else {
NSLog(#"up");
[self.view viewWithTag:123].hidden = true;
}
}
After some searching I thought of some new answer, hope it helps you!
To identify direction of Scroll:
BOOL showSearch;
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if ([scrollView.panGestureRecognizer translationInView:scrollView].y > 0) {
// down
showSearch = true;
} else {
// up
showSearch = false;
}
}
-(void)scrollViewWillEndDragging:(UIScrollView *)scrollView
withVelocity:(CGPoint)velocity
targetContentOffset:(inout CGPoint *)targetContentOffset{
if (showSearch) {
[self addSearch];
}
else {
[self removeSearch];
}
[_tableView reloadData];
}
To add & remove SearchController:
-(void)addSearch {
if (!_searchController){
_searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
_searchController.searchResultsUpdater = self;
[_searchController.searchBar sizeToFit];
_tableView.tableHeaderView = _searchController.searchBar;
_searchController.delegate = self;
_searchController.dimsBackgroundDuringPresentation = NO;
self.definesPresentationContext = YES;
_searchController.active = NO;
_searchController.searchResultsUpdater = self;
_searchController.dimsBackgroundDuringPresentation = NO;
self.definesPresentationContext = YES;
_tableView.tableHeaderView = _searchController.searchBar;
_searchController.searchBar.delegate = self;
}
}
-(void)removeSearch {
_searchController.active = NO;
[_searchController removeFromParentViewController];
_searchController = nil;
_tableView.tableHeaderView = nil;
}
Related
All,
I want to add UISearchBar to UINavigationbar, I dont dont want to use UISearchController, Just UISearchbar programmatically and it must work in landscape as well.
I tried it is working well in Portrait well, but in Landscape, i have issues in iPhone X width. Can we use Constraints.
Below is the code
CGFloat width = [UIScreen mainScreen].bounds.size.width;
search = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, width - 2 * 44 - 2 * 15, 44)];
search.delegate = self; // search.tintColor = [UIColor redColor];
search.searchBarStyle = UISearchBarStyleMinimal;
search.placeholder = #"Search";
search.translucent = NO;
search.opaque = NO;
search.showsCancelButton = NO;
[search setBackgroundImage:[[UIImage alloc] init]];
//customize textfield inside UISearchBar
#try {
for (id object in [[[search subviews] firstObject] subviews])
{
if (object && [object isKindOfClass:[UITextField class]])
{
UITextField *textFieldObject = (UITextField *)object;
textFieldObject.backgroundColor = [UIColor whiteColor];
textFieldObject.borderStyle = UITextBorderStyleRoundedRect;
textFieldObject.layer.borderColor = (__bridge CGColorRef _Nullable)([brandingObj getValueForKey:navBarTitleColor]);
textFieldObject.layer.borderWidth = 1.0;
break;
}
}
}
#catch (NSException *exception) {
NSLog(#"Error while customizing UISearchBar");
}
#finally {
}
I don't understand why you want to use UISearchDisplayController, its highly configurable and recommended by apple, working with geometry (CGRecr, CGFrame, etc.) to adjust UIKit objects layout could be a pain, use auto layout avoiding UIKits convenience initializers, to adjust later constraints.
Anyway if you want explicitly do with this way, this should work.
#import "ViewController.h"
#interface ViewController ()<UISearchBarDelegate>
#property UISearchBar *searchbar;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_searchbar = [UISearchBar new];
_searchbar.delegate = self;
_searchbar.searchBarStyle = UISearchBarStyleMinimal;
self.navigationItem.titleView = self.searchbar;
// Do any additional setup after loading the view, typically from a nib.
}
Maybe you should need configure appearance , take a look here
Cheers.
I apply touches move action on a label to drag it into a rectangle box it is moving with touch fine, now i want to remove touch action from label when it is dropped in rectangle how can i get this any help.
here is my code after label drag end.
- (void)dragEnd:(UIPanGestureRecognizer *)gestureRecognizer {
BOOL cancelPanGesture = YES;
if (cancelPanGesture) {
gestureRecognizer.enabled = NO;
}
if(rectangle.frame.size.width == _lbl.frame.size.width){
gestureRecognizer.enabled = NO;
}
if (gestureRecognizer.state == UIGestureRecognizerStateCancelled) {
gestureRecognizer.enabled = YES;
}
try this one
if(rectangle.frame.size.width == _lbl.frame.size.width){
gestureRecognizer.enabled = NO;
_lbl.userInteractionEnabled = false;
UILabel *tapLable = (UILabel *)[gestureRecognizer view];
[tempLabel removeGestureRecognizer:gestureRecognizer];
}
Hope this will help you :)
if(CGRectContainsRect(rectangle.frame, _lbl.frame){
gestureRecognizer.enabled = NO;
_lbl.userInteractionEnabled = false;
UILabel *tapLable = (UILabel *)[gestureRecognizer view];
[tempLabel removeGestureRecognizer:removeGestureRecognizer];
}
I am trying to create an NSMatrix of NSButtonCells where between zero and four buttons can be selected (toggled on). I have tried the following (test) code, but am not sure how I can provide the functionality I require. Perhaps it's not possible with NSMatrix and I need to look at an alternative control, or create my own?
#interface MatrixView : NSView
{
NSScrollView *_scrollView;
NSMatrix *_matrixView;
}
#end
#implementation MatrixView
- (id)initWithFrame:(NSRect)frameRect
{
NSLog(#"initWithFrame. frameRect=%#", NSStringFromRect(frameRect));
self = [super initWithFrame:frameRect];
if (self != nil)
{
_scrollView = [[NSScrollView alloc] initWithFrame:NSMakeRect(0, 0, frameRect.size.width, frameRect.size.height)];
[_scrollView setBorderType:NSNoBorder];
[_scrollView setHasVerticalScroller:YES];
[_scrollView setHasHorizontalScroller:NO];
[_scrollView setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
NSSize contentSize = [_scrollView contentSize];
contentSize.height = 300;
// Make it 3 x however-many-buttons-will-fit-the-height
CGFloat gap = 8.0;
CGFloat width = (contentSize.width / 3.0) - (gap * 2.0);
NSUInteger rows = (contentSize.height / (width + gap));
NSLog(#"width=%f, rows=%lu", width, rows);
NSButtonCell *prototype = [[NSButtonCell alloc] init];
[prototype setTitle:#"Hello"];
[prototype setButtonType:NSToggleButton];
[prototype setShowsStateBy:NSChangeGrayCellMask];
_matrixView = [[NSMatrix alloc] initWithFrame:NSMakeRect(0, 0, contentSize.width, contentSize.height)
mode:NSListModeMatrix
prototype:prototype
numberOfRows:rows
numberOfColumns:3];
[_matrixView setCellSize:NSMakeSize(width, width)];
[_matrixView setIntercellSpacing:NSMakeSize(gap, gap)];
[_matrixView setAllowsEmptySelection:YES];
[_matrixView sizeToCells];
[_scrollView setDocumentView:_matrixView];
[self addSubview:_scrollView];
[self setAutoresizesSubviews:YES];
[prototype release];
}
return self;
}
...
I got this to work with the following subclass of NSMatrix. I added one property, onCount, to keep track of how many buttons were in the on state:
#implementation RDMatrix
#synthesize onCount;
-(id) initWithParentView:(NSView *) cv {
NSButtonCell *theCell = [[NSButtonCell alloc ]init];
theCell.bezelStyle = NSSmallSquareBezelStyle;
theCell.buttonType = NSPushOnPushOffButton;
theCell.title = #"";
if (self = [super initWithFrame:NSMakeRect(200,150,1,1) mode:2 prototype:theCell numberOfRows:4 numberOfColumns:4]){
[self setSelectionByRect:FALSE];
[self setCellSize:NSMakeSize(40,40)];
[self sizeToCells];
self.target = self;
self.action = #selector(buttonClick:);
self.drawsBackground = FALSE;
self.autoresizingMask = 8;
self.allowsEmptySelection = TRUE;
self.mode = NSHighlightModeMatrix;
self.onCount = 0;
[cv addSubview:self];
return self;
}
return nil;
}
-(IBAction)buttonClick:(NSMatrix *)sender {
NSUInteger onOrOff =[sender.selectedCells.lastObject state];
if (onOrOff) {
self.onCount += 1;
}else{
self.onCount -= 1;
}
NSLog(#"%ld",self.onCount);
if (self.onCount == 5) {
[sender.selectedCells.lastObject setState:0];
self.onCount -= 1;
}
}
When you try to select the 5th button it will flash on, but then go off. This could be a problem depending on how you are using the state of these buttons. I just logged them with this method:
-(IBAction)checkMatrix:(id)sender {
NSIndexSet *indxs = [self.mat.cells indexesOfObjectsPassingTest:^BOOL(NSButtonCell *cell, NSUInteger idx, BOOL *stop) {
return cell.state == NSOnState;
}];
NSLog(#"%#",indxs);
}
After Edit: I didn't like the way my first method flashed the button on briefly before turning it off again when you try to click the 5th button. I found what I think is a better solution that involves overriding mouseDown in the matrix subclass (if you want to try this, you should delete the setAction and setTarget statements and delete the buttonClick method):
-(void)mouseDown:(NSEvent *) event {
NSPoint matPoint = [self convertPoint:event.locationInWindow fromView:nil];
NSInteger row;
NSInteger column;
[self getRow:&row column:&column forPoint:matPoint];
NSButtonCell *cell = [self cellAtRow:row column:column];
if (self.onCount < 4 && cell.state == NSOffState) {
cell.state = NSOnState;
self.onCount += 1;
}else if (cell.state == NSOnState) {
cell.state = NSOffState;
self.onCount -= 1;
}
}
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
I'm trying to understand how to add a label with a UISwitch or other controller to a footer (or header) in a sectioned tableView. Any help would be greatly appreciated. Thank you in advance!
Okay, after searching and working at it I've done the following:
// Need to refactor so that the label is Public Sharing and Priviate Sharing and the actions work for each switch
- (UIView *) tableView: (UITableView *) tableView
viewForFooterInSection: (NSInteger) section
{
if (section == 0 || section == 1) {
CGRect screenRect = [[UIScreen mainScreen] applicationFrame];
UIView* footerView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, screenRect.size.width, 44.0)] autorelease];
footerView.autoresizesSubviews = YES;
footerView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
footerView.userInteractionEnabled = YES;
footerView.hidden = NO;
footerView.multipleTouchEnabled = NO;
footerView.opaque = NO;
footerView.contentMode = UIViewContentModeScaleToFill;
// Add the label
UILabel* footerLabel = [[UILabel alloc] initWithFrame:CGRectMake(150.0, -5.0, 120.0, 45.0)];
footerLabel.backgroundColor = [UIColor clearColor];
footerLabel.opaque = NO;
footerLabel.text = #"Sharing";
footerLabel.textColor = [UIColor tableHeaderAndFooterColor];
footerLabel.highlightedTextColor = [UIColor tableHeaderAndFooterColor];
footerLabel.font = [UIFont boldSystemFontOfSize:17];
footerLabel.shadowColor = [UIColor whiteColor];
footerLabel.shadowOffset = CGSizeMake(0.0, 1.0);
[footerView addSubview: footerLabel];
[footerLabel release];
// Add the switch
UISwitch* footerSwitch = [[UISwitch alloc] initWithFrame:CGRectMake(215.0, 5, 80.0, 45.0)];
[footerView addSubview: footerSwitch];
// Return the footerView
return footerView;
}
else return nil;
}
// Need to call to pad the footer height otherwise the footer collapses
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
switch (section) {
case 0:
case 1:
return 40.0;
default:
return 0.0;
}
}
I hope this is correct and if this helps anyone else please vote this up. Cheers!
i think you need to autorelease the uiview-