I am quite new to iOS development and trying hard to develop an App. I am unable to use swipe gestures in a multiview app. I am pasting the code, can you guys please point out the error.
It's a view based application.
Here is mainViewController.h
#import <UIKit/UIKit.h>
#interface mainViewController : UIViewController <UITableViewDelegate,UITableViewDataSource>
{
NSArray *listData;
}
#property (nonatomic, retain) NSArray *listData;
#end
Now mainViewController.m
#import "mainViewController.h"
#implementation mainViewController
#synthesize listData;
- (void)viewDidLoad {
NSArray *array =[[NSArray alloc] initWithObjects:#"Apple",#"Boy",#"Cat", nil];
self.listData = array;
[array release];
[super viewDidLoad];
}
- (void)dealloc
{
[listData release];
[super dealloc];
}
#pragma mark - View lifecycle
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section {
return [self.listData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *SimpleTableIdentifier = #"SimpleTableIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:
SimpleTableIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:SimpleTableIdentifier] autorelease];
}
NSUInteger row = [indexPath row];
cell.textLabel.text = [listData objectAtIndex:row];
//cell.textLabel.font = [UIFont boldSystemFontOfSize:50];
return cell;
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUInteger row = [indexPath row];
NSString *rowValue = [listData objectAtIndex:row];
if([rowValue isEqualToString:#"Apple"])
{
cell.backgroundColor = [UIColor redColor];
}
else
if([rowValue isEqualToString:#"Boy"])
cell.backgroundColor= [UIColor yellowColor];
}
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUInteger row = [indexPath row];
NSString *rowValue = [listData objectAtIndex:row];
if([rowValue isEqualToString:#"Apple"])
{
mainViewController* flashView=[[mainViewController alloc] initWithNibName:#"fl" bundle:[NSBundle mainBundle]];
[self.view addSubview:flashView.view];
}
//[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
- (void)viewDidUnload
{
[super viewDidUnload];
self.listData=nil;
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (CGFloat)tableView:(UITableView *)tableView
heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 110;
}
#end
I have added an UIViewSubController class with the xib file named "fl".
In fl.h:
#define kMinimumLength 5
#define kMaxVariance 1
#import <UIKit/UIKit.h>
#import "mainViewController.h"
#protocol flDelegate;
#interface fl : UIViewController <UIGestureRecognizerDelegate>
{
CGPoint gestureStartPoint;
id <flDelegate> delegate;
}
#property CGPoint gestureStartPoint;
#property (nonatomic,retain) id <flDelegate> delegate;
#end
#protocol flDelegate
-(IBAction)flDidFinish:(fl *)controller;
#end
And now in fl.m:
#import "fl.h"
#implementation fl
#synthesize delegate;
#synthesize gestureStartPoint;
- (void)dealloc
{
[super dealloc];
}
#pragma mark - View lifecycle
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch =[touches anyObject];
gestureStartPoint =[touch locationInView:self.view];
}
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch =[touches anyObject];
CGPoint CurrentPosition =[touch locationInView:self.view];
if(CurrentPosition.x >= kMinimumLength)
{
NSLog(#"Go");
}
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
Here everything is working, but it is not detecting swipes, and not printing Go.
I also suggest taking a look at UISwipeGestureRecognizer, but if you prefer staying with your current design, this is the code that I am using elsewhere to detect swipes and pinch (zoom).
You will need to adapt it to your case (you have three methods instead of three branches).
if (touch.phase == UITouchPhaseBegan) {
// NSLog(#"TOUCH BEGAN");
_initialView = touchView;
startTouchPosition1 = [touch locationInView:self];
startTouchTime = touch.timestamp;
if ([allTouches count] > 1) {
startTouchPosition2 = [[[allTouches allObjects] objectAtIndex:1] locationInView:self];
previousTouchPosition1 = startTouchPosition1;
previousTouchPosition2 = startTouchPosition2;
}
}
if (touch.phase == UITouchPhaseMoved) {
// NSLog(#"TOUCH MOVED");
if ([allTouches count] > 1) {
CGPoint currentTouchPosition1 = [[[allTouches allObjects] objectAtIndex:0] locationInView:self];
CGPoint currentTouchPosition2 = [[[allTouches allObjects] objectAtIndex:1] locationInView:self];
CGFloat currentFingerDistance = CGPointDist(currentTouchPosition1, currentTouchPosition2);
CGFloat previousFingerDistance = CGPointDist(previousTouchPosition1, previousTouchPosition2);
if (fabs(currentFingerDistance - previousFingerDistance) > ZOOM_DRAG_MIN) {
NSNumber* movedDistance = [NSNumber numberWithFloat:currentFingerDistance - previousFingerDistance];
if (currentFingerDistance > previousFingerDistance) {
NSLog(#"zoom in");
[[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_ZOOM_IN object:movedDistance];
} else {
NSLog(#"zoom out");
[[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_ZOOM_OUT object:movedDistance];
}
}
}
}
if (touch.phase == UITouchPhaseEnded) {
CGPoint currentTouchPosition = [touch locationInView:self];
// Check if it's a swipe
if (fabsf(startTouchPosition1.x - currentTouchPosition.x) >= SWIPE_DRAG_HORIZ_MIN &&
// fabsf(startTouchPosition1.y - currentTouchPosition.y) <= SWIPE_DRAG_VERT_MAX &&
fabsf(startTouchPosition1.x - currentTouchPosition.x) > fabsf(startTouchPosition1.y - currentTouchPosition.y) &&
touch.timestamp - startTouchTime < 0.7
) {
// It appears to be a swipe.
if (startTouchPosition1.x < currentTouchPosition.x) {
NSLog(#"swipe right");
[[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_SWIPE_RIGHT object:touch];
} else {
NSLog(#"swipe left");
[[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_SWIPE_LEFT object:touch];
}
}
startTouchPosition1 = CGPointMake(-1, -1);
_initialView = nil;
}
EDIT: about your code...
you are not doing a proper swipe detection. indeed, take this line:
if(CurrentPosition.x >= kMinimumLength)
you are comparing a position (CurrentPosition.x) with a distance (kMinimumLength). This is not really meaningful. What you need saving the last touch position and then calculate the distance between the last touch and the current touch and compare this distance to kMinimumLenght.
The reason why I posted the sample code is that, by inspecting a working implementation you can understand what needs to be done in order to detect a swipe.
You should definitely take a look at UISwipeGestureRecognizers.
Related
I have a UISwitch in UITableView,I want to pass the event as the following way,but the event is nil.If I have replaced the switch for the button, the event will exist
[switch addTarget:self action:#selector(switchTaped:event:) forControlEvents:UIControlEventValueChanged];
-(void)switchTaped:(id)sender event:(id)event {
NSSet *touches = [event allTouches];
UITouch *touch = [touches anyObject];
CGPoint currentTouchPosition = [touch locationInView:_tableView];
NSIndexPath *indexPath= [_tableView
indexPathForRowAtPoint:currentTouchPosition];
NSLog(#"%ld",indexPath.row);
}
This is an implementation of my own, a generic UITableViewCell for switch selection common tasks
FILE .h
#import <UIKit/UIKit.h>
#interface SPFGenericBoolDataTableViewCell : UITableViewCell
{
IBOutlet UILabel *dataTitleLabel;
IBOutlet UISwitch *swDataValue;
}
#property (strong, nonatomic) UILabel *dataTitleLabel;
#property (strong, nonatomic) UISwitch *swDataValue;
-(void)setupWithTitle:(NSString*)title
dataValue:(BOOL)dataValue
indexpath:(NSIndexPath*)indexPath
andDataUpdateCallback:(void(^)(BOOL newValue,NSIndexPath*indexpath)) callback;
#end
FILE .m
#import "SPFGenericBoolDataTableViewCell.h"
#interface SPFGenericBoolDataTableViewCell()
#property (strong) void(^dataWasUpdatedBlock)(BOOL newValue,NSIndexPath*indexpath);
#property (strong) NSIndexPath* currIndexPath;
#end
#implementation SPFGenericBoolDataTableViewCell
#synthesize swDataValue;
#synthesize dataTitleLabel;
#pragma mark -
#pragma mark NSCoding
- (void)encodeWithCoder:(NSCoder*)coder
{
[super encodeWithCoder:coder];
[coder encodeObject:self.dataTitleLabel forKey:#"dataTitleLabel"];
[coder encodeObject:self.swDataValue forKey:#"swDataValue"];
}
- (instancetype)initWithCoder:(NSCoder*)decoder
{
if(self = [super initWithCoder:decoder]){
self.dataTitleLabel = [decoder decodeObjectForKey:#"dataTitleLabel"];
self.swDataValue = [decoder decodeObjectForKey:#"swDataValue"];
}
return self;
}
-(void)setupWithTitle:(NSString*)title
dataValue:(BOOL)dataValue
indexpath:(NSIndexPath*)indexPath
andDataUpdateCallback:(void(^)(BOOL newValue,NSIndexPath*indexpath)) callback
{
self.dataTitleLabel.text = title;
[self.swDataValue setOn:dataValue];
self.dataWasUpdatedBlock = callback;
self.currIndexPath = indexPath;
[self.swDataValue removeTarget:self action:#selector(valueChangedAction:) forControlEvents:UIControlEventValueChanged];
[self.swDataValue addTarget:self action:#selector(valueChangedAction:) forControlEvents:UIControlEventValueChanged];
}
- (void)awakeFromNib {
[super awakeFromNib];
// Initialization code
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
- (void)valueChangedAction:(id)sender {
if(self.dataWasUpdatedBlock != nil)
self.dataWasUpdatedBlock(self.swDataValue.on,self.currIndexPath);
}
#end
EXAMPLE OF USE
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
SPFGenericBoolDataTableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:#"SPFGenericBoolDataTableViewCell" forIndexPath:indexPath];
[cell setupWithTitle:#"AnyTitle" dataValue:currValue indexpath:indexPath andDataUpdateCallback:^(BOOL newValue, NSIndexPath *indexpath) {
NSLog(#"%#",indexPath);
}];
return cell;
}
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
the code below not being called.
Header File
#import "SASlideMenuViewController.h"
#import "SASlideMenuDataSource.h"
#import "SASlideMenuDelegate.h"
#import "spHomeViewController.h"
#import <UIKit/UIKit.h>
#import "UIColor+CustomColor.h"
#interface spMenuViewController : SASlideMenuViewController<SASlideMenuDataSource,SASlideMenuDelegate, UITableViewDataSource>
#property NSMutableArray *menuArray;
#end
#import "spMenuViewController.h"
#interface spMenuViewController ()<SASlideMenuDataSource,SASlideMenuDelegate, UITableViewDataSource>
#property (nonatomic) CGFloat selectedHue;
#property (nonatomic) CGFloat selectedBrightness;
#end
#implementation spMenuViewController
#synthesize selectedHue;
#synthesize selectedBrightness;
-(id) initWithCoder:(NSCoder *)aDecoder{
if (self = [super initWithCoder:aDecoder]) {
self.selectedBrightness = 0.3;
self.selectedHue = 0.0;
}
return self;
}
-(void)tap:(id)sender{
}
-(void) viewDidLoad{
[super viewDidLoad];
}
-(BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{
return YES;
}
-(void)viewDidAppear:(BOOL)animated{
[self.tableView reloadData];
}
#pragma mark -
#pragma mark SASlideMenuDataSource
-(void) prepareForSwitchToContentViewController:(UINavigationController *)content{
UIViewController* controller = [content.viewControllers objectAtIndex:0];
if ([controller isKindOfClass:[spHomeViewController class]]) {
spHomeViewController* coloredViewController = (spHomeViewController*) controller;
}
}
// It configure the menu button. The beahviour of the button should not be modified
-(void) configureMenuButton:(UIButton *)menuButton{
menuButton.frame = CGRectMake(0, 0, 40, 29);
[menuButton setImage:[UIImage imageNamed:#"menuicon"] forState:UIControlStateNormal];
}
// It configure the right menu button. The beahviour of the button should not be modified
-(void) configureRightMenuButton:(UIButton *)menuButton{
menuButton.frame = CGRectMake(0, 0, 40, 29);
[menuButton setImage:[UIImage imageNamed:#"menuiconright"] forState:UIControlStateNormal];
}
// This is the segue you want visibile when the controller is loaded the first time
-(NSIndexPath*) selectedIndexPath{
return [NSIndexPath indexPathForRow:0 inSection:0];
}
// It maps each indexPath to the segueId to be used. The segue is performed only the first time the controller needs to loaded, subsequent switch to the content controller will use the already loaded controller
-(NSString*) segueIdForIndexPath:(NSIndexPath *)indexPath{
NSString* result;
switch (indexPath.section) {
case 0:
result = #"segueHome";
break;
case 1:
result = #"segueHome";
break;
default:
result = #"segueHome";
break;
}
return result;
}
-(Boolean) disableContentViewControllerCachingForIndexPath:(NSIndexPath *)indexPath{
return YES;
}
-(Boolean) hasRightMenuForIndexPath:(NSIndexPath *)indexPath{
return YES;
}
#pragma mark -
#pragma mark UITableViewDataSource
-(NSInteger) numberOfSectionsInTableView:(UITableView *)tableView{
return 3;
}
-(NSString*)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
if (section == 0) {
return #"Red";
}else if (section == 1){
return #"Green";
}else {
return #"Blue";
}
}
-(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return 4;
}
-(void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{
CGFloat brightness = 1-((double) indexPath.row)/5;
NSInteger section = indexPath.section;
CGFloat hue=0;
if (section == 0) {
hue = 0.0;
}else if (section==1){
hue = 0.33;
}else if (section==2){
hue = 0.66;
}
cell.backgroundColor = [UIColor colorWithHue:hue saturation:1.0 brightness:brightness alpha:1.0];
}
-(UITableViewCell*) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell* cell = [self.tableView dequeueReusableCellWithIdentifier:#"item"];
return cell;
}
-(CGFloat) leftMenuVisibleWidth{
return 260;
}
-(CGFloat) rightMenuVisibleWidth{
return 260;
}
//restricts pan gesture interation to 50px on the left and right of the view.
-(Boolean) shouldRespondToGesture:(UIGestureRecognizer*) gesture forIndexPath:(NSIndexPath*)indexPath {
CGPoint touchPosition = [gesture locationInView:self.view];
return (touchPosition.x < 50.0 || touchPosition.x > self.view.bounds.size.width - 50.0f);
}
#pragma mark -
#pragma mark UITableViewDelegate
-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
CGFloat brightness = 1-((double) indexPath.row)/5;
NSInteger section = indexPath.section;
CGFloat hue=0;
if (section == 0) {
hue = 0.0;
}else if (section==1){
hue = 0.33;
}else if (section==2){
hue = 0.66;
}
self.selectedHue = hue;
self.selectedBrightness = brightness;
[super tableView:tableView didSelectRowAtIndexPath:indexPath];
}
#pragma mark -
#pragma mark SASlideMenuDelegate
-(void) slideMenuWillSlideIn:(UINavigationController *)selectedContent{
NSLog(#"slideMenuWillSlideIn");
}
-(void) slideMenuDidSlideIn:(UINavigationController *)selectedContent{
NSLog(#"slideMenuDidSlideIn");
}
-(void) slideMenuWillSlideToSide:(UINavigationController *)selectedContent{
NSLog(#"slideMenuWillSlideToSide");
}
-(void) slideMenuDidSlideToSide:(UINavigationController *)selectedContent{
NSLog(#"slideMenuDidSlideToSide");
}
-(void) slideMenuWillSlideOut:(UINavigationController *)selectedContent{
NSLog(#"slideMenuWillSlideOut");
}
-(void) slideMenuDidSlideOut:(UINavigationController *)selectedContent{
NSLog(#"slideMenuDidSlideOut");
}
-(void) slideMenuWillSlideToLeft:(UINavigationController *)selectedContent{
NSLog(#"slideMenuWillSlideToLeft");
}
-(void) slideMenuDidSlideToLeft:(UINavigationController *)selectedContent{
NSLog(#"slideMenuDidSlideToLeft");
}
#end
Did you make SASlideMenuViewController as datasource of the UITableView ?
Check the code :
- (void)viewDidLoad
{
[super viewDidLoad];
self.tableView.dataSource = self;
}
or connecting File's owner as a datasource of your table view in Xib.
I think you just set UITableView.dataSource but not UITableView.delegate. Set it in your xib.
and you should implement the method below:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
and it must return a positive number.
In iOS for the iPhone I want to make a control with similar appearance and behavior to the android spinner control when configured to behave like a drop down list box. Specifically when pressed a modal list of text options with radio buttons comes up and when one of them is pressed the list disappears and the control updates to that choice. Example:
So far I have seen a full-screen option using [self presentViewController...] with a custom ViewController but I want a partial screen (like pictured above) solution. Does anyone know how to do this or could point in the right direction.
The native solution to this will be a UIActionSheet which on iPhone will appear from the bottom and be partial screen or on iPad be very similar to the android version.
You can find the documentation here: UIActionSheet
if you didnt want to use the UIActionSheet and you wanted to make it reusable rather than adding a whole bund of UIViews to your current XIB, you could create a custom UIView with whatever interface you would need to populate it and use the interface builder to help make it look ok.
that view could have a message handler that posts the response that you would need to listen for.
then just init and load the view into your subviews and populate it
then post a message from the custom view to the handler you registered
so for your custom view you would have something like this.
#implementation SomeCustomView
+(SomeCustomView*)viewFromNibNamed:(NSString *)nibName{
NSArray *nibContents = [[NSBundle mainBundle] loadNibNamed:nibName owner:self options:NULL];
NSEnumerator *nibEnumerator = [nibContents objectEnumerator];
SomeCustomView *customView = nil;
NSObject* nibItem = nil;
while ((nibItem = [nibEnumerator nextObject]) != nil) {
if ([nibItem isKindOfClass:[AADropDown class]]) {
customView = (SomeCustomView*)nibItem;
break;
}
}
return customView;
}
-(void)someInitializationWith:(NSArray*)repeatableData andNotificationId:(NSString*)noteId{
//set your stuff up for the view here and save the notification id
}
...
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
[[NSNotificationCenter defaultCenter] postNotificationName:Your_Notification_Id object:somevalue];
}
#end
and include other things, like in this case the tableview stuff or any other logic.
then in your viewcontroller you could call it like
__block id observer = [[NSNotificationCenter defaultCenter] addObserverForName:#"customViewAction" object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *note) {
//deal with notification here
[[NSNotificationCenter defaultCenter] removeObserver: observer];
}];
SomeCustomView *cv =(SomeCustomView*) [SomeCustomView viewFromNibNamed:#"SomeCustomView"];
[cv someInitializationWith:arrayOptions andNotificationId:#"customViewAction"];
[self.view addSubview:cv];
and in your interface builder you will just need to make sure that the class of the view is set to your class type.
then you can easily reuse this code again whenever a user needs to select something else in the same manner.
Here is a variation on the solution suggested by AtomRiot.
On your view (xib or storyboard) make a button and assign this graphic to it. Don't worry if it appears stretched out in the editor. The code will make it a realizable graphic.
2X version
Then include the following files in your project (copied below):
DDLBHelper.h
DDLBHelper.m
Then in your ViewController's .h file make links to the button:
#property (weak, nonatomic) IBOutlet UIButton *ddlbB;
- (IBAction)ddlbBClick:(id)sender;
In you ViewController's .m file make the following calls:
#synthesize ddlbB, choiceLabel;
DDLBHelper *mDDLBH;
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *strings = [[NSArray alloc] initWithObjects:#"Item 1", #"Item 2", #"Item 3", nil];
mDDLBH = [[DDLBHelper alloc] initWithWithViewController:self button:ddlbB stringArray:strings currentValue:1];
}
- (IBAction)ddlbBClick:(id)sender {
[mDDLBH popupList];
}
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
[mDDLBH adjustToRotation];
}
Works just like android.
Here are the files:
DDLBHelper.h
// DDLBHelper.h
// Created by MindSpiker on 9/27/12.
#import <Foundation/Foundation.h>
#protocol DDLBHelperDelegate <NSObject>
#required
- (void) itemSelected: (int)value;
#end
#interface DDLBHelper : UIViewController <UITableViewDelegate, UITableViewDataSource>{
id <DDLBHelperDelegate> delegate;
}
#property (retain) id delegate;
// external interface
- (id) init;
- (id) initWithWithViewController:(UIViewController *)viewController button:(UIButton *)button stringArray:(NSArray *)values currentValue:(int) currentValue;
- (void) popupList;
- (BOOL) isShown;
- (void) adjustToRotation;
- (int) getValue;
- (NSString *)getValueText;
#end
DDLBHelper.m
// DDLBHelper.m
// Created by MindSpiker on 9/27/12.
#import "DDLBHelper.h"
#import <QuartzCore/QuartzCore.h>
#interface DDLBHelper () {
#private
UIViewController *mVC;
UIButton *mButton;
NSArray *mValues;
int mValue;
UITableView *mTV;
UIView *mBackgroundV;
}
#end
#implementation DDLBHelper
#synthesize delegate;
- (id) init {
self = [super init];
mVC = nil;
mButton = nil;
mValues = nil;
mValue = -1;
return self;
}
- (id) initWithWithViewController:(UIViewController *)viewController button:(UIButton *)button stringArray:(NSArray *)values currentValue:(int) currentValue {
self = [super init];
// save pointers
mVC = viewController;
mButton = button;
mValues = values;
mValue = currentValue;
[self setupButton];
return self;
}
- (void) popupList{
if (mBackgroundV == nil){
mBackgroundV = [self setupBackgroundView];
[mVC.view addSubview:mBackgroundV];
}
if (mTV == nil){
mTV = [self setupTableView];
[mVC.view addSubview:mTV];
}
[mTV reloadData];
[mBackgroundV setHidden:NO];
[mTV setHidden:NO];
}
- (BOOL) isShown{
return !mTV.isHidden;
}
- (void) adjustToRotation{
BOOL isShown = [self isShown];
// remove the controls
if (mBackgroundV != nil){
[mBackgroundV removeFromSuperview];
mBackgroundV = nil;
}
if (mTV != nil){
[mTV removeFromSuperview];
mTV = nil;
}
if (isShown){
[self popupList];
}
}
- (int) getValue{
return mValue;
}
- (NSString *) getValueText{
if (mValues != nil && mValue > -1) {
if (mValues.count > mValue){
return [mValues objectAtIndex:mValue];
}
}
return nil;
}
- (void) updateButtonTitle{
NSString *title = [NSString stringWithFormat:#" %#", [self getValueText]];
[mButton setTitle:title forState:UIControlStateNormal];
}
- (void) setupButton {
UIImage *buttonBG = [UIImage imageNamed:#"sis_proceeds_ddlb.png"];
UIEdgeInsets insets = UIEdgeInsetsMake(8, 8, 8, 45);
UIImage *sizableImg = [buttonBG resizableImageWithCapInsets:insets];
[mButton setBackgroundImage:sizableImg forState:UIControlStateNormal];
[mButton setContentHorizontalAlignment:UIControlContentHorizontalAlignmentLeft];
[self updateButtonTitle];
}
- (UIView *) setupBackgroundView{
UIView *v = [[UIView alloc] initWithFrame:mVC.view.bounds];
[[v layer] setOpaque:NO];
[[v layer] setOpacity:0.7f];
[[v layer] setBackgroundColor:[UIColor blackColor].CGColor];
return v;
}
- (UITableView *) setupTableView {
CGRect rect = [self makeTableViewRect];
UITableView *tv = [[UITableView alloc] initWithFrame:rect style:UITableViewStylePlain];
[tv setDelegate:self];
[tv setDataSource:self];
[tv setBackgroundColor:[UIColor whiteColor]];
[[tv layer] setBorderWidth:2];
[[tv layer] setBorderColor:[UIColor lightGrayColor].CGColor];
[[tv layer] setCornerRadius:10];
[mVC.view addSubview:tv];
return tv;
}
- (CGRect) makeTableViewRect {
float l=0.0, t=0.0, w=0.0, h=0.0, maxH=0.0, cellH=0.0, cellsH=0.0;
// get
l = mButton.frame.origin.x;
w = mButton.frame.size.width;
t = mVC.view.bounds.origin.y + 50;
maxH = mVC.view.bounds.size.height - 100;
// get cell height
UITableViewCell *c = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
cellH = c.bounds.size.height;
// see if list will overlow maxH(eight)
cellsH = cellH * mValues.count;
if (cellsH > maxH) {
h = maxH;
} else {
h = cellsH;
}
return CGRectMake(l, t, w, h);
}
#pragma mark - TableView Delegate functions
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1; // this is a one section table
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return mValues.count; // should be called for only one section
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
// try to resuse a cell if possible
static NSString *RESUSE_IDENTIFIER = #"myResuseIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:RESUSE_IDENTIFIER];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:RESUSE_IDENTIFIER];
}
cell.textLabel.text = [mValues objectAtIndex:indexPath.row];
if (mValue == indexPath.row){
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
// save value and hide view
mValue = indexPath.row;
[self updateButtonTitle];
[mBackgroundV setHidden:YES];
[mTV setHidden:YES];
[delegate itemSelected:mValue];
}
#end
I was wondering why this code would give me black UITableViewCells when I set the selected property ON. If I do that, the content of the cell turns completely black, and I have no idea why.
Here's the code
//
// TableViewAdapter.m
// TableviewScanMode
//
// Created by Nick Overdijk on 8/26/10.
// Copyright 2010 Nick Overdijk. All rights reserved.
//
#import "TableViewAdapter.h"
#import "Model.h"
#implementation TableViewAdapter
#synthesize model;
- (id) initWithModel: (Model*) model {
self = [super init];
if(self != nil){
self->model = [model retain];
}
return self;
}
- (void) dealloc {
[model release];
[super dealloc];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [[model cellData] count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [[[model cellData] objectAtIndex: section] count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = nil;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
cell.textLabel.text = [[[model cellData] objectAtIndex: indexPath.section] objectAtIndex: indexPath.row];
if(indexPath.row == [[model currentSelected] row] && indexPath.section == [[model currentSelected] section]){
cell.selected = YES;
} else {
cell.selected = NO;
}
return cell;
}
#end
//
// RootViewController.m
// TableviewScanMode
//
// Created by Nick Overdijk on 8/24/10.
// Copyright Nick Overdijk 2010. All rights reserved.
//
#import "RootViewController.h"
#import "Model.h"
#import "TableViewAdapter.h"
#implementation RootViewController
#pragma mark -
#pragma mark View lifecycle
- (void)viewDidLoad {
model = [[Model alloc] init];
[model addObserver:self
forKeyPath:#"updatedIndexPaths"
options:NSKeyValueObservingOptionNew
context:NULL
];
[model startSelectionRotation];
adapter = [[TableViewAdapter alloc] initWithModel: model];
self.tableView.dataSource = adapter;
[super viewDidLoad];
}
- (void)dealloc {
[adapter release];
[model release];
[super dealloc];
}
#pragma mark -
#pragma mark KVO updates
- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
NSArray * reloadThese = [change objectForKey: NSKeyValueChangeNewKey];
[self.tableView reloadRowsAtIndexPaths: reloadThese withRowAnimation: UITableViewRowAnimationFade];
}
#pragma mark -
#pragma mark Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
}
#end
If you need more code, shout. :)
Many thanks in advance,
Nick
I was having the same problem and fixed it by moving the cell.selected = YES into tableView:willDisplayCell:forRowAtIndexPath instead.
I think it might be related to the note at the bottom of the UITableViewCell docs about changes to background color requiring use of tableView:willDisplayCell:forRowAtIndexPath (presumably selected sets the background color).