Select a textView without select text inside? - ios

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;
}

Related

Search result auto complete does not display iOS Objective C

I've tried reading the google places API. and tried to duplicate their work. But I think I'm missing some steps here.
Here is the code for header my header file.
#class SPGooglePlacesAutocompleteQuery;
#interface GoogleMapViewViewController : UIViewController <UITableViewDataSource, UITableViewDelegate, UISearchDisplayDelegate, UISearchBarDelegate, MKMapViewDelegate, UISearchControllerDelegate>
{
NSArray *searchResultPlaces;
SPGooglePlacesAutocompleteQuery *searchQuery;
MKPointAnnotation *selectedPlaceAnnotation;
BOOL shouldBeginEditing;
}
#property (strong, nonatomic) UISearchController *searchController;
#property (retain, nonatomic) IBOutlet MKMapView *mapView;
#end
My implementation file
#import "GoogleMapViewViewController.h"
#import "SPGooglePlacesAutocompleteQuery.h"
#import "SPGooglePlacesAutocompletePlace.h"
#interface GoogleMapViewViewController ()
#property (weak, nonatomic) IBOutlet UISearchBar *searchBar;
#end
#implementation GoogleMapViewViewController
#synthesize mapView;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
searchQuery = [[SPGooglePlacesAutocompleteQuery alloc] init];
searchQuery.radius = 100.0;
shouldBeginEditing = YES;
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.searchBar.placeholder = #"Search or Address";
self.searchBar.delegate = self;
}
- (void)viewDidUnload {
[self setMapView:nil];
[super viewDidUnload];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
#pragma mark -
#pragma mark UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [searchResultPlaces count];
}
- (SPGooglePlacesAutocompletePlace *)placeAtIndexPath:(NSIndexPath *)indexPath {
return [searchResultPlaces objectAtIndex:indexPath.row];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"SPGooglePlacesAutocompleteCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.textLabel.font = [UIFont fontWithName:#"GillSans" size:16.0];
cell.textLabel.text = [self placeAtIndexPath:indexPath].name;
return cell;
}
#pragma mark UITableViewDelegate
- (void)recenterMapToPlacemark:(CLPlacemark *)placemark {
MKCoordinateRegion region;
MKCoordinateSpan span;
span.latitudeDelta = 0.02;
span.longitudeDelta = 0.02;
region.span = span;
region.center = placemark.location.coordinate;
[self.mapView setRegion:region];
}
- (void)addPlacemarkAnnotationToMap:(CLPlacemark *)placemark addressString:(NSString *)address {
[self.mapView removeAnnotation:selectedPlaceAnnotation];
selectedPlaceAnnotation = [[MKPointAnnotation alloc] init];
selectedPlaceAnnotation.coordinate = placemark.location.coordinate;
selectedPlaceAnnotation.title = address;
[self.mapView addAnnotation:selectedPlaceAnnotation];
}
- (void)dismissSearchControllerWhileStayingActive {
// Animate out the table view.
NSTimeInterval animationDuration = 0.3;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:animationDuration];
self.searchDisplayController.searchResultsTableView.alpha = 0.0;
[UIView commitAnimations];
[self.searchDisplayController.searchBar setShowsCancelButton:NO animated:YES];
[self.searchDisplayController.searchBar resignFirstResponder];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
SPGooglePlacesAutocompletePlace *place = [self placeAtIndexPath:indexPath];
[place resolveToPlacemark:^(CLPlacemark *placemark, NSString *addressString, NSError *error) {
if (error) {
SPPresentAlertViewWithErrorAndTitle(error, #"Could not map selected Place");
} else if (placemark) {
[self addPlacemarkAnnotationToMap:placemark addressString:addressString];
[self recenterMapToPlacemark:placemark];
[self dismissSearchControllerWhileStayingActive];
[self.searchDisplayController.searchResultsTableView deselectRowAtIndexPath:indexPath animated:NO];
}
}];
}
#pragma mark UISearchDisplayDelegate
- (void)handleSearchForSearchString:(NSString *)searchString {
searchQuery.location = self.mapView.userLocation.coordinate;
searchQuery.input = searchString;
[searchQuery fetchPlaces:^(NSArray *places, NSError *error) {
if (error) {
SPPresentAlertViewWithErrorAndTitle(error, #"Could not fetch Places");
} else {
searchResultPlaces = places;
[self.searchDisplayController.searchResultsTableView reloadData];
}
}];
}
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
[self handleSearchForSearchString:searchString];
// Return YES to cause the search result table view to be reloaded.
return YES;
}
- (BOOL)searchController:(UISearchController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
[self handleSearchForSearchString:searchString];
// Return YES to cause the search result table view to be reloaded.
return YES;
}
#pragma mark UISearchBar Delegate
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
if (![searchBar isFirstResponder]) {
// User tapped the 'clear' button.
shouldBeginEditing = NO;
[self.searchDisplayController setActive:NO];
[self.mapView removeAnnotation:selectedPlaceAnnotation];
}
}
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar {
if (shouldBeginEditing) {
// Animate in the table view.
NSTimeInterval animationDuration = 0.3;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:animationDuration];
self.searchDisplayController.searchResultsTableView.alpha = 1.0;
[UIView commitAnimations];
[self.searchDisplayController.searchBar setShowsCancelButton:YES animated:YES];
}
BOOL boolToReturn = shouldBeginEditing;
shouldBeginEditing = YES;
return boolToReturn;
}
#pragma mark MKMapView Delegate
- (MKAnnotationView *)mapView:(MKMapView *)mapViewIn viewForAnnotation:(id <MKAnnotation>)annotation {
if (mapViewIn != self.mapView || [annotation isKindOfClass:[MKUserLocation class]]) {
return nil;
}
static NSString *annotationIdentifier = #"SPGooglePlacesAutocompleteAnnotation";
MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:annotationIdentifier];
if (!annotationView) {
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:annotationIdentifier];
}
annotationView.animatesDrop = YES;
annotationView.canShowCallout = YES;
UIButton *detailButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[detailButton addTarget:self action:#selector(annotationDetailButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
annotationView.rightCalloutAccessoryView = detailButton;
return annotationView;
}
- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views {
// Whenever we've dropped a pin on the map, immediately select it to present its callout bubble.
[self.mapView selectAnnotation:selectedPlaceAnnotation animated:YES];
}
- (void)annotationDetailButtonPressed:(id)sender {
// Detail view controller application logic here.
}
#end
I am really confused now to my implementation file as I cannot really understand what is in there TBH.plus some codes here are mostly deprecated. Someone care to give a detailed guide about this? or explain to me in layman's term. TIA.
ANSWERED!
Basically my problem was in this function given on the sample project of google places API..
BOOL SPEnsureGoogleAPIKey() {
BOOL userHasProvidedAPIKey = YES;
if (![kGoogleAPIKey isEqualToString:#"AIzaSyA2vs9pJoLrLs6XU8IRVHo7WxiuMufYXl8"]) {
userHasProvidedAPIKey = NO;
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"API Key Needed" message:#"Please replace kGoogleAPIKey with your Google API key." delegate:nil cancelButtonTitle:#"Dismiss" otherButtonTitles:nil];
[alert show];
}
return userHasProvidedAPIKey;
}
The if statement originally is incorrect that's why it always gives me the wrong value. now its working :) just added the not "!" in if

How to copy self.title?

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

MLPAutoCompleteTextField suggestion table interaction issue

Currently I'm using this third-party library in my project https://github.com/EddyBorja/MLPAutoCompleteTextField. This library is used to show the suggestion list based on user input.
I did setup the text field like this
self.searchTextField = [[MLPAutoCompleteTextField alloc] initWithFrame:CGRectMake(0, 0, 250, 30)];
[self.searchTextField setBorderStyle:UITextBorderStyleRoundedRect];
self.searchTextField.backgroundColor = [UIColor whiteColor];
self.searchTextField.clearButtonMode = UITextFieldViewModeWhileEditing;
self.searchTextField.textColor = [UIColor blackColor];
self.searchTextField.returnKeyType = UIReturnKeyDone;
self.searchTextField.placeholder = #"Enter name to search";
self.searchTextField.autocorrectionType = UITextAutocorrectionTypeNo;
self.searchTextField.delegate = self;
self.searchTextField.autoCompleteDelegate = self;
self.searchTextField.autoCompleteDataSource = self;
Implement the Datasource protocol as below
- (NSArray *)autoCompleteTextField:(MLPAutoCompleteTextField *)textField possibleCompletionsForString:(NSString *)string {
return #[#"AAA", #"BBB", #"CCC", #"DDD"];
When I input something to the text field, the drop down list was shown but when I tap on a cell in the drop down list, the list dissappeared without completing any words in the text field.
Anyone experienced this problem please explain to me where I was wrong. Thanks in advance.
I had the same issue awhile back. I happened to be using MLPAutocomleteTextField inside a UITableView, so all the touch events were likely intercepted by the tableview.
I worked around this issue by setting the autoCompleteTableAppearsAsKeyboardAccessory of my MLPAutocomleteTextField instance to TRUE to enable enable autocomplete as a keyboard accessory. This allowed me to select my autocomplete options. Hopefully this solves your issue as well. :)
I solved it by subclassing my UITableViewCell, a little tricky but it's working for me:
#import "AutoCompleteTableViewCell.h"
#interface AutoCompleteTableViewCell()
#property (nonatomic, assign) BOOL selectedCell;
#end
#implementation AutoCompleteTableViewCell
- (void)awakeFromNib {
[super awakeFromNib];
self.selectedCell = NO;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event
{
UIView* hitView = [super hitTest:point withEvent:event];
if (hitView != nil)
{
[self.superview bringSubviewToFront:self];
}
return hitView;
}
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event
{
CGRect rect = self.bounds;
BOOL isInside = CGRectContainsPoint(rect, point);
if(!isInside)
{
for (UIView *view in self.subviews)
{
isInside = CGRectContainsPoint(view.frame, point);
if(isInside)
break;
}
}
if (!self.selectedCell) {
self.selectedCell = YES;
id view = [self superview];
while (view && [view isKindOfClass:[UITableView class]] == NO) {
view = [view superview];
}
UITableView *tableView = (UITableView *)view;
NSIndexPath *indexPath = [tableView indexPathForCell:self];
[tableView.delegate tableView:tableView didSelectRowAtIndexPath:indexPath];
}
return isInside;
}
Then delegate method is called:
- (void)autoCompleteTextField:(MLPAutoCompleteTextField *)textField
didSelectAutoCompleteString:(NSString *)selectedString
withAutoCompleteObject:(id<MLPAutoCompletionObject>)selectedObject
forRowAtIndexPath:(NSIndexPath *)indexPath;

Order of UIMenuItems in custom edit menu

I want to add my own commands to the selection menu, but also keep the standard "copy", "cut", etc. commands. I use this:
UIMenuItem *myItem = [[UIMenuItem alloc] initWithTitle:#"My Command" action:#selector(myCommand:)];
[[UIMenuController sharedMenuController] setMenuItems:[NSArray arrayWithObjects: myItem, nil]];
But this adds my command to the very end of the list in the edit menu. I want my command to appear first in it. How could I achieve this?
Solved it by myself. Here is what in my initWithCoder: method:
UIMenuItem *myCommandItem = [[UIMenuItem alloc] initWithTitle:#"My Command" action:#selector(myCommandPressed:)];
UIMenuItem *cutItem = [[UIMenuItem alloc] initWithTitle:#"Cut" action:#selector(myCut:)];
UIMenuItem *copyItem = [[UIMenuItem alloc] initWithTitle:#"Copy" action:#selector(myCopy:)];
UIMenuItem *pasteItem = [[UIMenuItem alloc] initWithTitle:#"Paste" action:#selector(myPaste:)];
UIMenuItem *selectItem = [[UIMenuItem alloc] initWithTitle:#"Select" action:#selector(mySelect:)];
UIMenuItem *selectAllItem = [[UIMenuItem alloc] initWithTitle:#"Select all" action:#selector(mySelectAll:)];
UIMenuItem *deleteItem = [[UIMenuItem alloc] initWithTitle:#"Delete" action:#selector(myDelete:)];
[[UIMenuController sharedMenuController] setMenuItems:[NSArray arrayWithObjects: myCommandItem,
cutItem, copyItem, pasteItem, selectItem, selectAllItem, deleteItem, nil]];
Now this:
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
if (action == #selector(myCommandPressed:)) {
return YES;
}
if (action == #selector(myCut:)) {
return [super canPerformAction:#selector(cut:) withSender:sender];
}
if (action == #selector(myCopy:)) {
return [super canPerformAction:#selector(copy:) withSender:sender];
}
if (action == #selector(myPaste:)) {
return [super canPerformAction:#selector(paste:) withSender:sender];
}
if (action == #selector(mySelect:)) {
return [super canPerformAction:#selector(select:) withSender:sender];
}
if (action == #selector(mySelectAll:)) {
return [super canPerformAction:#selector(selectAll:) withSender:sender];
}
if (action == #selector(myDelete:)) {
return [super canPerformAction:#selector(delete:) withSender:sender];
}
return NO;
}
And finally:
- (void) myCommandPressed: (id) sender {
NSLog(#"My Command pressed");
}
- (void) myCut: (id) sender {
[self cut:sender];
}
- (void) myCopy: (id) sender {
[self copy:sender];
}
- (void) myPaste: (id) sender {
[self paste:sender];
}
- (void) mySelect: (id) sender {
[self select:sender];
}
- (void) mySelectAll: (id) sender {
[self selectAll:sender];
}
- (void) myDelete: (id) sender {
[self delete:sender];
}

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