I have a custom cell with a UITextField . Where I should set the delegate, in the custom cell class or in the view's class ?
I was trying to do this in both, but no results. I set the delegate from storyboard.
Here is what I did:
-(void)textViewShouldReturn:(UITextField *)textField
{
if ([textField.text isEqualToString:#""]){
return;
}
UIAlertView *helloEarthInputAlert = [[UIAlertView alloc]
initWithTitle:#"Name!" message:[NSString stringWithFormat:#"Message: %#", textField.text]
delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[helloEarthInputAlert show];
}
But this part is working if i put this cell.noteTextField.delegate=self :
-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
self.tableView.frame=CGRectMake(self.tableView.frame.origin.x, self.tableView.frame.origin.y-30, self.tableView.frame.size.width, self.tableView.frame.size.height);
return YES;
}
Add the delegate in the custom cell's class. But do not forget to implement the protocols
// MyCell.h
#interface MyCell : UITableViewCell <UITextFieldDelegate>
// ...
// MyCell.m
-(void)autoconfigureCell // a method I added to configure cell, but also can do in "-(void)layoutSubviews"
{
// ...
myTextField.delegate = self;
// ...
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField // <-- BOOL
{
// do stuff
return YES;
}
You should set the delegate in your ViewController, it has to implement UITextFieldDelegate and to know what textfield is calling the delegate methods, you can do something like this:
-(void)textViewShouldReturn:(UITextField *)textField
{
CGPoint textFieldPosition = [textField convertPoint:CGPointZero toView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:textFieldPosition];
...
}
Related
I want to add a CollectionView inside my ViewController using the same code that I have on a CollectionViewController.
CollectionViewController.m
#interface StoreViewController ()
#property (readwrite, nonatomic, strong) NSArray *latestProducts;
#end
#implementation StoreViewController
- (void)setLatestProducts:(NSArray *)latestProducts {
_latestProducts = latestProducts;
[self.collectionView reloadData];
}
- (Product *)releaseForIndexPath:(NSIndexPath *)indexPath {
return [self.latestProducts objectAtIndex:indexPath.row];
}
- (void)loadData:(id)sender {
[self showLoadingView];
[Product latestProductsWithBlock:^(NSArray *products, NSError *error) {
self.latestProducts = products;
dispatch_async(dispatch_get_main_queue(), ^{
[self hideLoadingView];
});
if (error) {
[[[UIAlertView alloc] initWithTitle:[error localizedDescription] message:[error localizedFailureReason] delegate:nil cancelButtonTitle:NSLocalizedString(#"OK", nil) otherButtonTitles:nil, nil] show];
}
}];
}
#pragma mark - UIViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title = NSLocalizedString(#"Deadstock", nil);
[self.collectionView registerClass:[ProductCell class] forCellWithReuseIdentifier:#"ProductCell"];
[self loadData:nil];
}
#pragma mark - UICollectionViewDelegate
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return [self.latestProducts count];
}
#pragma mark - Collection View Cell
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
static NSString *identifier = #"productCell";
ProductCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
cell.product = [self releaseForIndexPath:indexPath];
return cell;
}
#end
ProductCell.m
#implementation ProductCell
- (void)setProduct:(Product *)product {
_product = product;
dispatch_async(dispatch_get_main_queue(), ^{
[self.image setImageWithURL:self.product.thumbnailImageURL];
});
self.image.clipsToBounds = YES;
}
#end
I have an NSObject that parses my cell's content, from my database.
Product.h
#interface Product : NSObject
#property (readonly) NSURL *thumbnailImageURL;
- (instancetype)initWithAttributes:(NSDictionary *)attributes;
+ (void)latestProductsWithBlock:(void (^)(NSArray *products, NSError *error))block;
#end
Following a tutorial I fount online, I created a NSObject file ("ProductDataSource") and on my Storyboard I added an Object to my ViewController and linked it to my CollectionView. I copied the code from my CollectionViewController to ProductDataSource but it's not creating my cells. If I set the numberOfItemsInSection to a number it created the cells but not when I change the code to return [self.latestProducts count]. It might have something to do with "loadData" section I have on my CollectionViewController, since ProductDataSource doesn't have a viewDidLoad method.
- (void)loadData:(id)sender {
[self showLoadingView];
[Product latestProductsWithBlock:^(NSArray *products, NSError *error) {
self.latestProducts = products;
dispatch_async(dispatch_get_main_queue(), ^{
[self hideLoadingView];
});
if (error) {
[[[UIAlertView alloc] initWithTitle:[error localizedDescription] message:[error localizedFailureReason] delegate:nil cancelButtonTitle:NSLocalizedString(#"OK", nil) otherButtonTitles:nil, nil] show];
}
}];
}
#pragma mark - UIViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title = NSLocalizedString(#"Deadstock", nil);
[self.collectionView registerClass:[ProductCell class] forCellWithReuseIdentifier:#"ProductCell"];
[self loadData:nil];
}
Any help? Thanks.
You have to reload the collection view after you get latestProducts. Try to put [self.collectionView reloadData] after [self hideLoadingView];
Put a breakpoint in your cellForItemAtIndexPath method to ensure that method is being hit. If it doesn't get hit, that means you need to set your collection view's datasource.
So if I am understanding correctly, you have an existing UICollectionViewController called CollectionViewController and want to reuse the logic in another UIViewController.
a UICollectionViewController is essentially a UIViewController that has a UICollectionView subview and conforms to the UICollectionViewDataSource and UICollectionViewDelegate protocols.
In order to embed a UICollectionView into your UIViewController, you need to create Delegate and DataSource classes for your CollectionView and assign them in the UIViewController.
There are some good code examples here: UICollectionView with UIViewController As Data Source
GitHub Repo with a small single page app using a CollectionView inside a UIViewController:
https://github.com/pnavk/CollectionViewSample
I am using UISearchbar in tableview controller in storyboard.
And searchbar returnKeyType is UIReturnKeySearch.
Its working fine with iOS7 but returnKeyType is not working with iOS8.
in iOS8, return key appears every time in keyboard.
I tried to set returnkeytype in viewDidLoad method of controller too.
What I need to do to set returnKeyType = UIReturnKeySearch in iOS8?
I think you can go with your hard codded logic for right now.
I will update if I will get better solution for your problem.
-(void)viewDidLoad {
[self setReturnKeyTypeSearchForView:searchBar];
}
-(void)setReturnKeyTypeSearchForView:(UIView *)view
{
for (id subView in view.subviews) {
if ([subView isKindOfClass:[UITextField class]]) {
[subView setReturnKeyType:UIReturnKeySearch];
}
else {
[self setReturnKeyTypeSearchForView:subView];
}
}
if ([view isKindOfClass:[UITextField class]]) {
[(UITextField *)view setReturnKeyType:UIReturnKeySearch];
}
}
Try making IBOutlet of your SearchBar
#property (weak, nonatomic) IBOutlet UISearchBar *searchBar;
and add the below line code to your viewDidLoad Method
// if u want Done return key and change accordingly.
_searchBar.returnKeyType = UIReturnKeyDone;
SearchViewController.h
//
#import <UIKit/UIKit.h>
#interface SearchViewController : UIViewController
<UISearchBarDelegate, UITableViewDataSource> {
NSMutableArray *tableData;
UIView *disableViewOverlay;
UITableView *theTableView;
UISearchBar *theSearchBar;
}
#property(retain) NSMutableArray *tableData;
#property(retain) UIView *disableViewOverlay;
#property (nonatomic, retain) IBOutlet UITableView *theTableView;
#property (nonatomic, retain) IBOutlet UISearchBar *theSearchBar;
- (void)searchBar:(UISearchBar *)searchBar activate:(BOOL) active;
#end
SearchViewController.m
//
#import "SearchViewController.h"
#implementation SearchViewController
#synthesize tableData;
#synthesize disableViewOverlay;
#synthesize theSearchBar;
#synthesize theTableView;
// Initialize tableData and disabledViewOverlay
- (void)viewDidLoad {
[super viewDidLoad];
self.tableData =[[NSMutableArray alloc]init];
self.disableViewOverlay = [[UIView alloc]
initWithFrame:CGRectMake(0.0f,44.0f,320.0f,416.0f)];
self.disableViewOverlay.backgroundColor=[UIColor blackColor];
self.disableViewOverlay.alpha = 0;
}
// Since this view is only for searching give the UISearchBar
// focus right away
- (void)viewDidAppear:(BOOL)animated {
[self.theSearchBar becomeFirstResponder];
[super viewDidAppear:animated];
}
#pragma mark -
#pragma mark UISearchBarDelegate Methods
- (void)searchBar:(UISearchBar *)searchBar
textDidChange:(NSString *)searchText {
// We don't want to do anything until the user clicks
// the 'Search' button.
// If you wanted to display results as the user types
// you would do that here.
}
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
// searchBarTextDidBeginEditing is called whenever
// focus is given to the UISearchBar
// call our activate method so that we can do some
// additional things when the UISearchBar shows.
[self searchBar:searchBar activate:YES];
}
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar {
// searchBarTextDidEndEditing is fired whenever the
// UISearchBar loses focus
// We don't need to do anything here.
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
// Clear the search text
// Deactivate the UISearchBar
searchBar.text=#"";
[self searchBar:searchBar activate:NO];
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
// Do the search and show the results in tableview
// Deactivate the UISearchBar
// You'll probably want to do this on another thread
// SomeService is just a dummy class representing some
// api that you are using to do the search
NSArray *results = [SomeService doSearch:searchBar.text];
[self searchBar:searchBar activate:NO];
[self.tableData removeAllObjects];
[self.tableData addObjectsFromArray:results];
[self.theTableView reloadData];
}
// We call this when we want to activate/deactivate the UISearchBar
// Depending on active (YES/NO) we disable/enable selection and
// scrolling on the UITableView
// Show/Hide the UISearchBar Cancel button
// Fade the screen In/Out with the disableViewOverlay and
// simple Animations
- (void)searchBar:(UISearchBar *)searchBar activate:(BOOL) active{
self.theTableView.allowsSelection = !active;
self.theTableView.scrollEnabled = !active;
if (!active) {
[disableViewOverlay removeFromSuperview];
[searchBar resignFirstResponder];
} else {
self.disableViewOverlay.alpha = 0;
[self.view addSubview:self.disableViewOverlay];
[UIView beginAnimations:#"FadeIn" context:nil];
[UIView setAnimationDuration:0.5];
self.disableViewOverlay.alpha = 0.6;
[UIView commitAnimations];
// probably not needed if you have a details view since you
// will go there on selection
NSIndexPath *selected = [self.theTableView
indexPathForSelectedRow];
if (selected) {
[self.theTableView deselectRowAtIndexPath:selected
animated:NO];
}
}
[searchBar setShowsCancelButton:active animated:YES];
}
#pragma mark -
#pragma mark UITableViewDataSource Methods
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section {
return [tableData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *MyIdentifier = #"SearchResult";
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:MyIdentifier] autorelease];
}
id *data = [self.tableData objectAtIndex:indexPath.row];
cell.textLabel.text = data.name;
return cell;
}
#pragma mark -
#pragma mark Memory Management Methods
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[theTableView release], theTableView = nil;
[theSearchBar release], theSearchBar = nil;
[tableData dealloc];
[disableViewOverlay dealloc];
[super dealloc];
}
#end
Building a SearchView with UISearchBar and UITableView
this might helps you :)
I'm not sure if I understood your question correctly. You want to have "search" button instead of "return" button, right? There is a new SearchController in ios 8, give it a try:
YourTableViewController.h
#interface YourTableViewController : UITableViewController<UISearchResultsUpdating>
#end
And now the implementation:
YourTableViewController.m
- (void)viewDidLoad {
// initializing with the same controller as presenting
UISearchController *searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
searchController.searchResultsUpdater = self;
searchController.searchBar.frame = CGRectMake(searchController.searchBar.frame.origin.x, searchController.searchBar.frame.origin.y, searchController.searchBar.frame.size.width, 44.0f);
searchController.dimsBackgroundDuringPresentation = NO;
searchController.searchBar.delegate = self;
searchController.searchBar.returnKeyType = UIReturnKeySearch; //should be search by default.. you can change to whatever you want.
// adding searchBar into HeaderView
self.tableView.tableHeaderView = searchController.searchBar;
// just to be able to present results on the same controller
self.definesPresentationContext = YES;
}
You also have to implement method from UISearchResultsUpdating protocol:
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController {
// you can leave it blank
}
EDIT: If it is not what you were looking for please comment, so I can update my answer accordingly
try this in viewDidLoad:
UITextField *txfSearchField = [yourSearchbar valueForKey:#"_searchField"];
if([txfSearchField conformsToProtocol:#protocol(UITextInputTraits)]) {
[txfSearchField setReturnKeyType:UIReturnKeyDefault];
}
I'm trying to delete a row in table view after confirmation from the user, using an alert view. However I don't know how to let the UIAlertViewDelegate method know which row in the table to delete.
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
UIAlertView *alert_delete = [[UIAlertView alloc]initWithTitle:[NSString stringWithFormat:#"Confirm Delete %#",[names objectAtIndex:indexPath.row] ] message:#"Warning all student data will be earsed" delegate:self cancelButtonTitle:#"Dismess" otherButtonTitles:#"YES", nil];
[alert_delete show];
// Delete the row from the data source
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
} else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
in alert method i try handle it to delete row from table and database
-(void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
NSString*title = [alertView buttonTitleAtIndex:buttonIndex];
if ([title isEqualToString:#"YES"]) {
// how to pass indexPath.row to alertview
[names removeObjectAtIndex:indexPath.row];
}
}
If you want to pass something to the delegate then add a property to the delegate class and pass the information to it before invoking the alert view:
#interface AlertDelegate : NSObject <UIAlertViewDelegate>
#property (nonatomic) NSIndexPath *indexPath;
#end
// #implementation AlertDelegate omitted
And use thus:
UIAlertView *alertView = ...;
AlertDelegate *delegate = [AlertDelegate new];
alertView.delegate = delegate;
delegate.indexPath = indexPathFromSomewhere;
[alertView show]; // or whatever
If the delegate is self, then that means adding the property to self (or use a private instance variable).
In the delegate method you then have access to the indexPath:
-(void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
NSString*title = [alertView buttonTitleAtIndex:buttonIndex];
if ([title isEqualToString:#"YES"]) {
[names removeObjectAtIndex:self.indexPath.row];
}
}
Add a variable to your tableView controller class to hold the indexPath.row and then use it in the alertview. Save indexPath.row in it before showing the alert.
Also you need to call
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
after confirming that user selected YES in the alertView delegate method.
You can also use objc_setAssociatedObject if info to be passed is a collection object. link -
How do you pass a variable to the UIAlertView delegate?
Instead UIAlertview use
CustomAlertview CustomAlertView *lAlert = [[CustomAlertView alloc] init.....
#import <UIKit/UIKit.h>
#interface CustomAlertView : UIAlertView
#property (nonatomic,retain)NSString *mIndex;
#end
#import "CustomAlertView.h"
#implementation CustomAlertView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
#end
In the delegate method get the selected data or index as below
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
NSLog(#"index %#",((CustomAlertView *)alertView).mIndex);
}
In the table delegate method assing the index or data as below
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{
CustomAlertView *lAlert = [[CustomAlertView alloc] .....
lAlert.mIndex = #"1";
[lAlert show];
lAlert = nil;
}
I have alert-view that has a tableview as a subview. I want to disable firstOtherbutton after tableview didSelectRowAtIndexPath. I can call alertViewShouldEnableFirstOtherButton but firstotherbutton doesn't change.
- (void)viewDidLoad
{
self.announcement=[[UIAlertView alloc] initWithTitle:#"Announcement" message:nil delegate:self cancelButtonTitle:nil otherButtonTitles:#"Tamam", nil];
[announcement setValue:self.tbl.view forKey:#"accessoryView"];
announcement.delegate =self;
announcement.tag=100;
[announcement show];
[self.tbl.tableView reloadData];
}
-(void)didSelectAnswer
{
[self performSelector:#selector(alertViewShouldEnableFirstOtherButton:) withObject:announcement afterDelay:0.001];
}
- (BOOL)alertViewShouldEnableFirstOtherButton:(UIAlertView *)alertView
{
if (alertView.tag==100)
{
if(!self.tbl.deger)
{
return YES;
}
return NO;
}
return NO;
}
you have to write your custom alertview to achieve this feature.
Here are some open source implementations of alertview for iOS:
https://www.cocoacontrols.com/tags/uialertview
i want to clear all my textfields when clicking cancelButtonTitle: on action sheet;
here is my action sheet code:
- (IBAction)cancelButtonPressed:(id)sender {
UIActionSheet *actionSheet = [[UIActionSheet alloc]
initWithTitle:#"Are you sure?"
delegate:self
cancelButtonTitle:#"No Way!"
destructiveButtonTitle:#"Yes, I’m Sure!"
otherButtonTitles:nil];
[actionSheet showInView:self.view];
}
Maybe you haven't implemented UIActionSheet delegate:
#pragma mark - UIActionSheetDelegate
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == actionSheet.cancelButtonIndex) {
//Clear textfiled at here
self.firstNameField.text = #"";
}
else{
//Do somethings for #"Yes, I’m Sure!"
}
}
In addition to simalone's answer, which states you will need to implement the following action sheet's delegate method:
#pragma mark - UIActionSheetDelegate
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == actionSheet.cancelButtonIndex) {
//Clear textfileds at here
}
else{
//Do somethings for #"Yes, I’m Sure!"
}
}
If you wanted something a bit automatic, you could create a category on UIView, and implement the following recursive method:
UIView+ClearTextFields.h
-(void)clearAllTextFields;
UIView+ClearTextFields.m
-(void)clearAllTextFields
{
if ([self isKindOfClass:[UITextField class]])
{
[(UITextField*)self setText:nil];
}
for (UIView* subview in self.subviews)
{
[subview clearAllTextFields];
}
}
If you needed to also clear all TextViews, you could add the following to the above method:
if ([self isKindOfClass:[UITextView class]])
{
[(UITextView*)self setText:nil];
}