How to copy self.title? - ios

I'm setting my page title as:
self.title = #"My Title";
Now I want to enable this title as that user can copy this title.
So How do I do that ?
EDIT:
self is my UIViewController class and my view is in navigation controller.
When user hold the title it can show tooltip like "Copy" and title text copied.

You can subclass UILabel named 'YourTitleLabel' and assign it as titleView of UIViewController's navigationItem.
self.navigationItem.titleView = YourTitleLabel;
And you should override several methods of UIResponder.
#interface YourTitleLabel : UILabel
#end
#implementation YourTitleLabel
- (BOOL)canBecomeFirstResponder
{
return YES;
}
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
if (action == #selector(copy:)) {
return YES;
}
return NO;
}
- (void)copy:(id)sender
{
[[UIPasteboard generalPasteboard] setString:self.text];
[self resignFirstResponder];
}
#end
Hope helpful for you!

Here is the way :
Make UILable subclass, and add this methods to the class.
TitleLabel.h file:
#import <UIKit/UIKit.h>
#interface TitleLabel : UILabel
#end
and TitleLabel.m file:
#import "TitleLabel.h"
#implementation TitleLabel
- (void)initCommon
{
UILongPressGestureRecognizer *lpRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(handleLongPress:)];
[self addGestureRecognizer:lpRecognizer];
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
[self initCommon];
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self)
{
[self initCommon];
}
return self;
}
- (BOOL)canBecomeFirstResponder
{
return YES;
}
- (void)copy:(id)sender
{
[[UIPasteboard generalPasteboard] setString:self.text];
[self resignFirstResponder];
}
- (void)handleLongPress:(UILongPressGestureRecognizer *)sender
{
UIMenuController *menu = [UIMenuController sharedMenuController];
if (![menu isMenuVisible])
{
[self becomeFirstResponder];
[menu setTargetRect:self.frame inView:self.superview];
[menu setMenuVisible:YES animated:YES];
}
}
#end
Now add this lable to your navigation titleView like :
TitleLabel *title = [[TitleLabel alloc] initWithFrame:CGRectMake(0, 0, 150, 50)];
title.textAlignment = NSTextAlignmentCenter;
title.text = #"My title";
title.userInteractionEnabled = YES;
self.navigationItem.titleView = title;
and here is you can copy self.title on long press on lable.

you can set your custom label in self.navigationbar.titleview and set title in your custom label. If that will also not work. then you can try with uitextfield (actually it is weird to set textfield in titleview) with non-editable.

you need to create one sampleLabel class, which is the sub class of UILabel as follows , where you required copy text option use this SampleLabel intead of UILabel
#implementation SampleLabel UILabel
- (void) awakeFromNib
{
[super awakeFromNib];
[self attachTapHandler];
}
- (void) attachTapHandler
{
if (self.tag != 100 ) {
[self setUserInteractionEnabled:YES];
UITapGestureRecognizer *touchy = [[UITapGestureRecognizer alloc]
initWithTarget:self action:#selector(handleTap:)];
touchy.numberOfTapsRequired = 2;
[self addGestureRecognizer:touchy];
}
}
- (void) copy: (id) sender
{
[[UIPasteboard generalPasteboard] setString:self.text];
}
- (BOOL) canPerformAction: (SEL) action withSender: (id) sender
{
return (action == #selector(copy:));
}
- (void) handleTap: (UIGestureRecognizer*) recognizer
{
[self becomeFirstResponder];
UIMenuController *menu = [UIMenuController sharedMenuController];
[menu setTargetRect:self.frame inView:self.superview];
[menu setMenuVisible:YES animated:YES];
}
- (BOOL) canBecomeFirstResponder
{
return YES;
}
#end

UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
pasteboard.string = self.title;
Refer to this link: https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/UsingCopy,Cut,andPasteOperations/UsingCopy,Cut,andPasteOperations.html

Related

Custom UIMenuItem not working on PDFKit's PDFView

I'm trying to add a custom UIMenuItem to my PDFView
Here's what I'm doing in my sample Xcode project
#import <PDFKit/PDFKit.h>
#import <objc/runtime.h>
#import "ViewController.h"
#interface ViewController ()
#property(nonatomic) PDFDocument *document;
#property(nonatomic) PDFView *pdfView;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
NSURL *pdfPath = [[NSBundle mainBundle] URLForResource:#"pdf" withExtension:#"pdf"];
_document = [[PDFDocument alloc] initWithURL:pdfPath];
_pdfView = [[PDFView alloc] initWithFrame:CGRectZero];
_pdfView.document = _document;
[self.view addSubview:_pdfView];
_pdfView.translatesAutoresizingMaskIntoConstraints = NO;
[_pdfView.topAnchor constraintEqualToAnchor:self.view.topAnchor].active = YES;
[_pdfView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor].active = YES;
[_pdfView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES;
[_pdfView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES;
UIMenuItem *menuItem =
[[UIMenuItem alloc] initWithTitle:#"Custom Action"
action:#selector(doSomething)];
[[UIMenuController sharedMenuController] setMenuItems:#[ menuItem ]];
[[UIMenuController sharedMenuController] update];
}
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
if (sel_isEqual(action, #selector(doSomething))) {
return YES;
}
return NO;
}
- (void)viewDidAppear:(BOOL)animated {
[self becomeFirstResponder];
}
- (void)doSomething {
NSLog(#"In Do Something!");
}
- (BOOL)canBecomeFirstResponder {
return YES;
}
#end
This works fine on iOS 11 and 12, but on iOS 13, the UIMenuItem is not showing up
For me assigning menuItems in handler of NSNotification.Name.PDFViewSelectionChanged works
NotificationCenter.default.addObserver(self,
selector: #selector(selectionChangeNotification),
name: NSNotification.Name.PDFViewSelectionChanged,
object: pdfView)
#objc
private func selectionChangeNotification() {
let menuItem = UIMenuItem(title: "Custom Action", action: #selector(doSomething))
UIMenuController.shared.menuItems = [menuItem]
}

Select a textView without select text inside?

I have a UITextView inside of UITableViewCell. That UITextView I want be selectable but not text to. When the Menu Controller is appearing and i want to perform copy action, copy all text inside not just a part.
I want something like messenger app :
For the moment i have that :
Thank you in advance!
In fact it's not quite so easy, as on the road show up some strange stuff, but I managed to create a customized one.
The steps are as following:
Create a subclass of UITextView
Override canPerformAction:
withSender: for filtering the default actions of the menu
that pops up.
Configuring textView in order not to be able to edit or
select.
Editing UIMenuController items which provide the actions and buttons on the menu
Add different selectors for each UIMenuItem **** (That is because the sender of the selector is not an UIMenuItem, but a UIMenuController which leads to another matter. Check here for more info. A gist by me for that)
Code
No more talking so here is the code:
EBCustomTextView.h
//
// EBCustomTextView.h
// TestProject
//
// Created by Erid Bardhaj on 3/8/16.
// Copyright © 2016 Erid Bardhaj. All rights reserved.
//
#import <UIKit/UIKit.h>
typedef NS_ENUM(NSInteger, EBCustomTextViewMenuAction) {
EBCustomTextViewMenuActionCopy,
EBCustomTextViewMenuActionDefine,
EBCustomTextViewMenuActionRead
};
#class EBCustomTextView;
#protocol EBCustomTextViewMenuActionDelegate <NSObject>
- (void)customTextView:(EBCustomTextView *)textView didSelectMenuAction:(EBCustomTextViewMenuAction)action;
#end
#interface EBCustomTextView : UITextView
#property (weak, nonatomic) id<EBCustomTextViewMenuActionDelegate> menuActionDelegate;
#end
EBCustomTextView.m
//
// EBCustomTextView.m
// TestProject
//
// Created by Erid Bardhaj on 3/8/16.
// Copyright © 2016 Erid Bardhaj. All rights reserved.
//
#import "EBCustomTextView.h"
#implementation EBCustomTextView {
EBCustomTextViewMenuAction currentAction;
}
- (void)awakeFromNib {
[super awakeFromNib];
// Configure the textView
self.editable = NO;
self.selectable = NO;
}
#pragma mark - Datasource
- (NSArray *)items {
UIMenuItem *item = [[UIMenuItem alloc] initWithTitle:#"Copy" action:#selector(copyMenuItemPressed)];
UIMenuItem *item1 = [[UIMenuItem alloc] initWithTitle:#"Define" action:#selector(defineMenuItemPressed)];
UIMenuItem *item2 = [[UIMenuItem alloc] initWithTitle:#"Read" action:#selector(readMenuItemPressed)];
return #[item, item1, item2];
}
#pragma mark - Actions
- (void)copyMenuItemPressed {
if ([self.menuActionDelegate respondsToSelector:#selector(customTextView:didSelectMenuAction:)]) {
[self.menuActionDelegate customTextView:self didSelectMenuAction:EBCustomTextViewMenuActionCopy];
}
}
- (void)defineMenuItemPressed {
if ([self.menuActionDelegate respondsToSelector:#selector(customTextView:didSelectMenuAction:)]) {
[self.menuActionDelegate customTextView:self didSelectMenuAction:EBCustomTextViewMenuActionDefine];
}
}
- (void)readMenuItemPressed {
if ([self.menuActionDelegate respondsToSelector:#selector(customTextView:didSelectMenuAction:)]) {
[self.menuActionDelegate customTextView:self didSelectMenuAction:EBCustomTextViewMenuActionRead];
}
}
#pragma mark - Private
- (void)menuItemPressedAtIndex:(NSInteger)index {
currentAction = index;
if ([self.menuActionDelegate respondsToSelector:#selector(customTextView:didSelectMenuAction:)]) {
[self.menuActionDelegate customTextView:self didSelectMenuAction:currentAction];
}
}
#pragma mark Helpers
- (void)showMenuController {
UIMenuController *theMenu = [UIMenuController sharedMenuController];
theMenu.menuItems = [self items];
[theMenu update];
CGRect selectionRect = CGRectMake (0, 0, self.contentSize.width, self.contentSize.height);
[theMenu setTargetRect:selectionRect inView:self];
[theMenu setMenuVisible:(theMenu.isMenuVisible) ? NO : YES animated:YES];
}
#pragma mark - Overridings
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
// Filter any action for this textView except our custom ones
if (action == #selector(copyMenuItemPressed) || action == #selector(defineMenuItemPressed) || action == #selector(readMenuItemPressed)) {
return YES;
}
return NO;
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *theTouch = [touches anyObject];
if ([theTouch tapCount] == 1 && [self becomeFirstResponder]) {
[self showMenuController];
}
}
#end
Implementation
Set your textView's class to EBCustomTextView and conform to EBCustomTextViewMenuActionDelegate
Interface
#interface ViewController () <EBCustomTextViewMenuActionDelegate>
viewDidLoad
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.textView.menuActionDelegate = self;
}
Protocol conformance
#pragma mark - Delegation
#pragma mark EBCustomTextViewMenuActionDelegate
- (void)customTextView:(EBCustomTextView *)textView didSelectMenuAction:(EBCustomTextViewMenuAction)action {
switch (action) {
case EBCustomTextViewMenuActionCopy:
NSLog(#"Copy Action");
break;
case EBCustomTextViewMenuActionRead:
NSLog(#"Read Action");
break;
case EBCustomTextViewMenuActionDefine:
NSLog(#"Define Action");
break;
default:
break;
}
}
Output
Enjoy :)
you have to use
[UITextView selectAll:self];
or (with specific range)
UITextView.selectedRange = NSMakeRange(0, 5);
or add txtview.delegate = self;
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView {
dispatch_async(dispatch_get_main_queue(), ^{
[textView selectAll:nil]; //nil or self as per needed
});
return YES;
}
Use UILongPressGestureRecognizer Gesture
#import "ViewController.h"
#interface ViewController ()<UIGestureRecognizerDelegate>
{
UITextView * txtV;
UILongPressGestureRecognizer * longPressGestureRecognizer;
}
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
txtV=[[UITextView alloc]initWithFrame:CGRectMake(20, 50, 280, 300)];
txtV.text = #"Jai Maharashtra";
txtV.userInteractionEnabled=YES;
txtV.selectable=NO;
txtV.editable=NO;
txtV.font= [UIFont italicSystemFontOfSize:[UIFont systemFontSize]];
[self.view addSubview:txtV];
longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longPressGesture:)];
longPressGestureRecognizer.delegate=self;
[txtV addGestureRecognizer:longPressGestureRecognizer];
}
- (void)longPressGesture:(UILongPressGestureRecognizer *)gestureRecognizer
{
if (gestureRecognizer.state == UIGestureRecognizerStateBegan)
{
txtV.selectable=YES;
[txtV selectAll:self];
}
}
-(BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
[txtV selectAll:self];
if (action == #selector(cut:))
{
return YES;
}
if (action == #selector(selectAll:))
{
return YES;
}
if (action == #selector(copy:))
{
return YES;
}
if (action == #selector(delete:))
{
return YES;
}
txtV.selectable=NO;
return YES;
}
First i start with create for every UITextView in cell a UILongPressGestureRecognizer to recognize long press.
In cellForRowAtIndexPath i just add that code :
UILongPressGestureRecognizer *recognizer1 = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:#selector(handleLongPressText1:)];
messageRecognizer.delaysTouchesBegan = YES;
UILongPressGestureRecognizer *recognizer2 = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:#selector(handleLongPressText2:)];
translateRecognizer.delaysTouchesBegan = YES;
[cell.backgroundViewText1 addGestureRecognizer:recognizer1];
[cell.backgroundViewText2 addGestureRecognizer:recognizer2];
I use two different selectors because i need to know which text to get from cell.
After the methods :
-(void)handleLongPressText1:(UILongPressGestureRecognizer *)gestureRecognizer
{
if ([gestureRecognizer state] == UIGestureRecognizerStateBegan) {
CGPoint p = [gestureRecognizer locationInView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:p];
if (indexPath == nil){
NSLog(#"couldn't find index path");
} else {
[self becomeFirstResponder];
UIMenuController *menuController = [UIMenuController sharedMenuController];
UIMenuItem *resetMenuItem = [[UIMenuItem alloc] initWithTitle:#"Copy" action:#selector(copyMethod)];
UIMenuItem *menuItem = [[UIMenuItem alloc] initWithTitle:#"Read" action:#selector(readButtonAction)];
[menuController setMenuItems:[NSArray arrayWithObjects:resetMenuItem,menuItem, nil]];
CGRect rect =gestureRecognizer.view.frame;
NSLog(#"%#", NSStringFromCGRect(rect));
[menuController setTargetRect:gestureRecognizer.view.frame inView:[[gestureRecognizer view] superview]];
[menuController setMenuVisible:YES animated:YES];
}
}
}
-(void)handleLongPressText2:(UILongPressGestureRecognizer *)gestureRecognizer
{
if ([gestureRecognizer state] == UIGestureRecognizerStateBegan) {
CGPoint p = [gestureRecognizer locationInView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:p];
if (indexPath == nil){
NSLog(#"couldn't find index path");
} else {
[self becomeFirstResponder];
UIMenuController *menuController = [UIMenuController sharedMenuController];
UIMenuItem *resetMenuItem = [[UIMenuItem alloc] initWithTitle:#"Copy" action:#selector(copyMethod)];
UIMenuItem *menuItem = [[UIMenuItem alloc] initWithTitle:#"Read" action:#selector(readButtonAction)];
[menuController setMenuItems:[NSArray arrayWithObjects:resetMenuItem,menuItem, nil]];
CGRect rect =gestureRecognizer.view.frame;
NSLog(#"%#", NSStringFromCGRect(rect));
[menuController setTargetRect:gestureRecognizer.view.frame inView:[[gestureRecognizer view] superview]];
[menuController setMenuVisible:YES animated:YES];
}
}
}
And for disable all default items in UIMenuController use above code
- (BOOL)canPerformAction:(SEL)iAction withSender:(id)iSender {
SEL copySelector = NSSelectorFromString(#"copyMethod");
SEL readSeletor = NSSelectorFromString(#"readButtonAction");
if (iAction == copySelector) {
return YES;
}else if (iAction ==readSeletor){
return YES;
}else{
return NO;
}
return NO;
}

UISearchDisplayController does not entirely cover a child view controller

I have a root view controller which composes a search bar on the top and a child table view controller on the bottom. I used composition instead of assigning the search bar to the table view's header for these reasons:
I didn't want the index to overlap with the search bar (like Contacts app).
I wanted the search bar to be sticky. That is, it doesn't move when I scroll the table view (again like the Contacts app).
My table view already had a header.
Since the search bar is in the root view controller, I instantiate my search display controller in the root view controller also. There are two problems with the search UI for which I seek advice:
The translucent gray overlay does not cover the entire child table view. It leaves the top portion of the header and the index visible.
Likewise, the search results table does not cover the entirety of the child table view. I know how to manually change the frame of this results table view, but doing so only fixes just that ... the gray translucent overlay's frame is not linked to the results table view frame. Their is no property to access the overlay.
1) Idle
2) Enter Search Bar
3) Start Typing
#import "ContactsRootViewController.h"
#import "ContactsViewController.h"
#import "UIView+position.h"
#import "User.h"
#import "UserCellView.h"
#import "UserViewController.h"
#interface ContactsRootViewController ()
#property(nonatomic, strong) UISearchBar* searchBar;
#property(nonatomic, strong) ContactsViewController* contactsViewController;
#property(nonatomic, strong) UISearchDisplayController* searchController;
#property(nonatomic, strong) NSMutableArray* matchedUsers;
#end
#implementation ContactsRootViewController
#pragma mark UIViewController
- (NSString*)title
{
return #"Contacts";
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.matchedUsers = [NSMutableArray array];
self.searchBar = [[UISearchBar alloc] init];
self.searchBar.placeholder = #"Search";
[self.searchBar sizeToFit];
[self.view addSubview:self.searchBar];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
if (self.contactsViewController == nil) {
self.contactsViewController = [[ContactsViewController alloc] init];
[self addChildViewController:self.contactsViewController];
self.contactsViewController.view.frame = CGRectMake(
0.0,
self.searchBar.bottomY,
self.view.frame.size.width,
self.view.frame.size.height - self.searchBar.bottomY
);
self.contactsViewController.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
[self.view addSubview:self.contactsViewController.view];
[self.contactsViewController didMoveToParentViewController:self];
self.searchController = [[UISearchDisplayController alloc] initWithSearchBar:self.searchBar contentsController:self.contactsViewController];
self.searchController.delegate = self;
self.searchController.searchResultsDataSource = self;
self.searchController.searchResultsDelegate = self;
}
}
#pragma mark UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.matchedUsers.count;
}
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString* identifier = #"contactsRootViewUserCell";
UserCellView* cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
cell = [[UserCellView alloc] initWithIdentifier:identifier];
}
cell.user = [self.matchedUsers objectAtIndex:indexPath.row];
return cell;
}
#pragma mark UITableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.navigationController pushViewController:[[UserViewController alloc] initWithUser:[self.matchedUsers objectAtIndex:indexPath.row]] animated:YES];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return [UserCellView height];
}
#pragma mark UISearchDisplayControllerDelegate
- (BOOL)searchDisplayController:(UISearchDisplayController*)controller shouldReloadTableForSearchString:(NSString *)searchString
{
[self.matchedUsers removeAllObjects];
searchString = [searchString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if (searchString.length > 0) {
for (User* user in self.contactsViewController.allUsers) {
NSRange match = [user.userDisplayName rangeOfString:searchString options:NSCaseInsensitiveSearch];
if (match.location != NSNotFound) {
[self.matchedUsers addObject:user];
}
}
}
return YES;
}
- (void)searchDisplayControllerDidEndSearch:(UISearchDisplayController *)controller
{
[self.searchBar resignFirstResponder];
}
#end
I re-implemented UISearchDisplayController, calling my implementation SearchController. It does the same thing and has similar delegate callbacks, but the frame of the search results can be controlled by the programmer.
Header
#import <Foundation/Foundation.h>
#class SearchController;
#protocol SearchControllerDelegate <NSObject>
#required
- (BOOL)searchController:(SearchController*)controller shouldReloadTableForSearchString:(NSString*)searchText;
#optional
- (void)searchController:(SearchController*)controller didShowSearchResultsTableView:(UITableView*)tableView;
- (void)searchController:(SearchController *)controller didHideSearchResultsTableView:(UITableView *)tableView;
- (void)searchControllerDidBeginSearch:(SearchController*)controller;
- (void)searchControllerDidEndSearch:(SearchController*)controller;
#end
#interface SearchController : UIViewController <UISearchBarDelegate>
#property(nonatomic, weak) NSObject<SearchControllerDelegate>* delegate;
#property(nonatomic, weak) NSObject<UITableViewDataSource>* searchResultsDataSource;
#property(nonatomic, weak) NSObject<UITableViewDelegate>* searchResultsDelegate;
#property(nonatomic, strong, readonly) UITableView* searchResultsTableView;
- (id)initWithSearchBar:(UISearchBar*)searchBar;
#end
Implementation
#import "SearchController.h"
#import "UIView+position.h"
#interface SearchController ()
#property(nonatomic, strong) UISearchBar* searchBar;
#property(nonatomic, strong) UIButton* searchResultsVeil;
#property(nonatomic, strong, readwrite) UITableView* searchResultsTableView;
#property(nonatomic, assign) BOOL searchResultsTableViewHidden;
- (void)didTapSearchResultsVeil;
- (void)hideSearchResults;
#end
#implementation SearchController
#pragma mark UIViewController
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.searchResultsTableView deselectRowAtIndexPath:[self.searchResultsTableView indexPathForSelectedRow] animated:YES];
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.userInteractionEnabled = NO;
}
#pragma mark SearchController ()
- (void)hideSearchResults
{
self.searchBar.text = nil;
[self.searchResultsTableView reloadData];
self.searchResultsTableViewHidden = YES;
[self.searchBar resignFirstResponder];
}
- (void)didTapSearchResultsVeil
{
[self hideSearchResults];
}
- (void)setSearchResultsTableViewHidden:(BOOL)searchResultsTableViewHidden
{
if (self.searchResultsTableView != nil) {
if (self.searchResultsTableView.hidden && !searchResultsTableViewHidden) {
self.searchResultsTableView.hidden = searchResultsTableViewHidden;
if ([self.delegate respondsToSelector:#selector(searchController:didShowSearchResultsTableView:)]) {
[self.delegate searchController:self didShowSearchResultsTableView:self.searchResultsTableView];
}
} else if (!self.searchResultsTableView.hidden && searchResultsTableViewHidden) {
self.searchResultsTableView.hidden = searchResultsTableViewHidden;
if ([self.delegate respondsToSelector:#selector(searchController:didHideSearchResultsTableView:)]) {
[self.delegate searchController:self didHideSearchResultsTableView:self.searchResultsTableView];
}
}
}
}
- (BOOL)searchResultsTableViewHidden
{
return self.searchResultsTableView == nil || self.searchResultsTableView.hidden;
}
#pragma mark SearchController
- (id)initWithSearchBar:(UISearchBar *)searchBar
{
if (self = [super init]) {
self.searchBar = searchBar;
self.searchBar.delegate = self;
}
return self;
}
- (void)setSearchResultsDataSource:(NSObject<UITableViewDataSource> *)searchResultsDataSource
{
_searchResultsDataSource = searchResultsDataSource;
if (self.searchResultsTableView != nil) {
self.searchResultsTableView.dataSource = searchResultsDataSource;
}
}
- (void)setSearchResultsDelegate:(NSObject<UITableViewDelegate> *)searchResultsDelegate
{
_searchResultsDelegate = searchResultsDelegate;
if (self.searchResultsTableView != nil) {
self.searchResultsTableView.delegate = searchResultsDelegate;
}
}
#pragma mark UISearchBarDelegate
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
if ([self.delegate searchController:self shouldReloadTableForSearchString:searchText]) {
[self.searchResultsTableView reloadData];
self.searchResultsTableViewHidden = [self.searchResultsTableView.dataSource tableView:self.searchResultsTableView numberOfRowsInSection:0] == 0;
}
}
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar
{
[searchBar setShowsCancelButton:YES animated:YES];
if (self.searchResultsVeil == nil) {
self.searchResultsVeil = [[UIButton alloc] initWithFrame:self.view.bounds];
self.searchResultsVeil.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.6];
self.searchResultsVeil.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.searchResultsVeil addTarget:self action:#selector(didTapSearchResultsVeil) forControlEvents:UIControlEventTouchUpInside];
self.searchResultsTableView = [[UITableView alloc] initWithFrame:self.searchResultsVeil.bounds style:UITableViewStylePlain];
self.searchResultsTableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
if ([self.searchResultsTableView respondsToSelector:#selector(setSeparatorInset:)]) {
self.searchResultsTableView.separatorInset = UIEdgeInsetsMake(
0.0,
self.searchResultsTableView.width,
0.0,
0.0
);
}
self.searchResultsTableViewHidden = YES;
if (self.searchResultsDataSource != nil) {
self.searchResultsTableView.dataSource = self.searchResultsDataSource;
}
if (self.searchResultsDelegate != nil) {
self.searchResultsTableView.delegate = self.searchResultsDelegate;
}
[self.view addSubview:self.searchResultsVeil];
[self.searchResultsVeil addSubview:self.searchResultsTableView];
}
self.view.userInteractionEnabled = YES;
self.searchResultsVeil.hidden = NO;
if ([self.delegate respondsToSelector:#selector(searchControllerDidBeginSearch:)]) {
[self.delegate searchControllerDidBeginSearch:self];
}
}
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar
{
[searchBar setShowsCancelButton:NO animated:YES];
self.view.userInteractionEnabled = NO;
self.searchResultsVeil.hidden = YES;
if ([self.delegate respondsToSelector:#selector(searchControllerDidEndSearch:)]) {
[self.delegate searchControllerDidEndSearch:self];
}
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{
[self hideSearchResults];
}
#end
Usage
self.searchController = [[SearchController alloc] initWithSearchBar:self.searchBar];
self.searchController.delegate = self;
self.searchController.searchResultsDataSource = self;
self.searchController.searchResultsDelegate = self;
[self addChildViewController:self.searchController];
self.searchController.view.frame = CGRectMake(
self.searchBar.x,
self.searchBar.bottomY,
self.searchBar.width,
self.view.height - self.searchBar.bottomY
);
[self.view addSubview:self.searchController.view];
[self.searchController didMoveToParentViewController:self];
It looks like your view controller does not define a presentation context. I had a similar problem and was able to resolve it by setting
self.definesPresentationContext = YES;
in viewDidLoad. According to the documentation this property is
A Boolean value that indicates whether this view controller's view is covered when the view controller or one of its descendants presents a view controller.

UIPickerView doesn't appear

In a ViewController call by push, I try to programmatically display a ComboBox. This combobox implement UIPickerView delegate protocol and add a .xib file.
When i run the app, i can see my combobox on the screen, but when i click on it, nothing append. Normally the pickerview will be displayed.
What i don't understand, is in another viewcontroller call modal it works fine
//
// ComboBox.h
//
#import <UIKit/UIKit.h>
#interface ComboBox : UIViewController<UIPickerViewDelegate, UIPickerViewDataSource, UITextFieldDelegate>
{
UIPickerView* pickerView;
IBOutlet UITextField* textField;
NSMutableArray *dataArray;
}
-(void) setComboData:(NSMutableArray*) data; //set the picker view items
-(void) setPlaceholder:(NSString*) label;
#property (retain, nonatomic) NSString* selectedText; //the UITextField text
#property (retain, nonatomic) IBOutlet UITextField* textField; //the UITextField
#end
//
// ComboBox.m
//
#import "ComboBox.h"
#implementation ComboBox
#synthesize selectedText;
#synthesize textField;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
return [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
//-- UIPickerViewDelegate, UIPickerViewDataSource
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView;
{
return 1;
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
textField.text = [dataArray objectAtIndex:row];
selectedText = textField.text;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component;
{
return [dataArray count];
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component;
{
return [dataArray objectAtIndex:row];
}
//-- ComboBox
-(void) setComboData:(NSMutableArray*) data
{
dataArray = data;
}
-(void) setPlaceholder:(NSString *)label
{
textField.placeholder = label;
}
-(void)doneClicked:(id) sender
{
[textField resignFirstResponder]; //hides the pickerView
}
- (IBAction)showPicker:(id)sender {
pickerView = [[UIPickerView alloc] init];
pickerView.showsSelectionIndicator = YES;
pickerView.dataSource = self;
pickerView.delegate = self;
UIToolbar* toolbar = [[UIToolbar alloc] init];
toolbar.barStyle = UIBarStyleBlackTranslucent;
[toolbar sizeToFit];
//to make the done button aligned to the right
UIBarButtonItem *flexibleSpaceLeft = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
UIBarButtonItem* doneButton = [[UIBarButtonItem alloc] initWithTitle:#"Done"
style:UIBarButtonItemStyleDone target:self
action:#selector(doneClicked:)];
[toolbar setItems:[NSArray arrayWithObjects:flexibleSpaceLeft, doneButton, nil]];
//custom input view
textField.inputView = pickerView;
textField.inputAccessoryView = toolbar;
}
- (BOOL)textFieldShouldBeginEditing:(UITextField *)aTextField
{
[self showPicker:aTextField];
return YES;
}
#end
the viewdidload of my viewcontroller
- (void)viewDidLoad
{
[super viewDidLoad];
NSMutableArray* ServeurArray = [[NSMutableArray alloc] init];
[ServeurArray addObject:#"1"];
[ServeurArray addObject:#"2"];
[ServeurArray addObject:#"3"];
comboServeur = [[ComboBox alloc] init];
[comboServeur setComboData:ServeurArray]; //Assign the array to ComboBox
comboServeur.view.frame = CGRectMake(95, 220, 130, 31); //ComboBox location and size (x,y,width,height)
[self.view addSubview:comboServeur.view];
}
thx for your answers
I assume that you are targeting iOS 5.0 and above. Since you are adding a view of a viewController to another viewController you can use the childViewController introduced in iOS 5.0.
Modify your viewDidLoad method
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
ComboBox *comboServeur = [[ComboBox alloc]initWithNibName:#"ComboBoxController" bundle:nil];
[comboServeur setComboData:#[#"1",#"2",#"3"]];
comboServeur.view.frame = CGRectMake(50.0f, 200.0f, 220.0f, 31.0f);
[self.view addSubview:comboServeur.view];
[self addChildViewController:comboServeur];
[comboServeur didMoveToParentViewController:self];
}
Few steps to check
Make the view of the ComboBox viewController freeform with maskType UIViewAutoresizingNone.
Check the textField and delegate of textField is connected
Demo project
I forget the specifics but I remember having the same problem but the thing for me was that I needed to link it to delegate or datasource or something? I'm not 100% sure since it's been quite a while but make sure when you have it on your view you link it to your picker reference + the other thing that you need.
Your ComboBox class isn't set as a delegate for the UITextField, so textFieldShouldBeginEditing: will never be called.
i try to use this combo class in my viewcontroller, i try all the solution you give to me, but nothing work, so the solution is to implement all the combo class code directly in my viewcontroller, and now it works, but it's a little bit uggly...

On UITableView editing mode, UITableView:didSelectRowAtIndexPath: doesn't respond

I'm developing an iOS application and I'm trying to implement my own custom UITableView edit mode with a custom UITableViewCell.
I have an edit button and this is the IBAction for it:
- (IBAction)editFavList:(id)sender
{
if ([_favList isEditing])
{
[_favList setEditing:NO animated:YES];
[_editButton setTitle:#"Edit" forState:UIControlStateNormal];
}
else
{
[_favList setEditing:YES animated:YES];
[_editButton setTitle:#"Done" forState:UIControlStateNormal];
}
}
I have connected UITableView* _favList delegate with UIViewController and this UITableViewDelegate method works fine until I tap over edit button:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (tableView.editing)
{
NSNumber* obj = [favsSelected objectAtIndex:indexPath.row];
BOOL selected;
if (obj == nil)
selected = NO;
else
selected = [obj boolValue];
FavouriteCell* cell =
(FavouriteCell*)[tableView cellForRowAtIndexPath:indexPath];
cell.checked = !selected;
// Actualizo el estado en el vector de los favoritos seleccionados
[favsSelected insertObject:[NSNumber numberWithBool:!selected] atIndex:indexPath.row];
}
}
After tapping edit button, this method doesn't fire (I'm sure about that because I add a breakpoint on the method).
This is custom cell implementation:
#import "FavouriteCell.h"
const NSInteger EDITING_HORIZONTAL_OFFSET = 35;
#implementation FavouriteCell
#synthesize selectIcon = _selectIcon;
#synthesize favName = _favName;
#synthesize checked = _checked;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
self.checked = NO;
}
return self;
}
- (void)setChecked:(BOOL)checked
{
if (checked == _checked)
return;
_selectIcon.highlighted = checked;
_checked = checked;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
+ (NSString *)reuseIdentifier
{
return #"favouriteCell";
}
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
//self.editing = editing;
[super setNeedsLayout];
}
#pragma mark - Private methods
- (void)layoutSubviews
{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationBeginsFromCurrentState:YES];
[super layoutSubviews];
if (((UITableView *)self.superview).isEditing)
{
CGRect contentFrame = self.contentView.frame;
contentFrame.origin.x = EDITING_HORIZONTAL_OFFSET;
self.contentView.frame = contentFrame;
self.accessoryType = UITableViewCellAccessoryNone;
}
else
{
CGRect contentFrame = self.contentView.frame;
contentFrame.origin.x = 0;
self.contentView.frame = contentFrame;
self.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
[UIView commitAnimations];
}
#end
But if I tap over edit button again (and then, I leave edit mode), if I tap over a row, didSelectRowAtIndexPath it's triggered again.
Why am I doing wrong? Probably this issue is related to if UITableView is in editing mode or not.
Check nib file .You should change the tableView editing property into Single Selection during editing.
You should set: allowsSelectionDuringEditing property of UITableView to YES
In your case:
_favList.allowSelectionDuringEditing = YES;

Resources