Getting started with UICollectionViewController Programmatically - ios

I am currently working on writing a UICollectionViewController to load images from a server and put the images into custom UICollectionViewCells within a UICollectionView. To make things simpler than it already is, I don't pull from a database, I just simply create an array of images that are stored locally. It works but for some reason, not all of the cells show the image until I start scrolling.
Heres an image of whats going on!
Image
I have read up on a few tutorials but they all use storyboard... I am wanting to write this programmatically.
Heres some code:
AppDelegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
JSMediaCollectionController *instagram = [[JSMediaCollectionController alloc] initWithCollectionViewLayout:[UICollectionViewFlowLayout new]];
instagram.datasource = self;
self.array = [NSMutableArray array];
for (int i = 0; i < 100; i++) {
[self.array addObject:#"instant_noodle_with_egg.jpg"];
}
UINavigationController *navCon = [[UINavigationController alloc] initWithRootViewController:instagram];
self.window.rootViewController = navCon;
[self.window makeKeyAndVisible];
return YES;
}
- (NSArray *)itemsToLoad
{
return [NSArray arrayWithArray:self.array];
}
JSMediaController.m
- (void)viewDidLoad {
[super viewDidLoad];
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = NO;
// Register cell classes
[self.collectionView registerClass:[JSMediaCollectionCell class] forCellWithReuseIdentifier:reuseIdentifier];
self.showOneItemPerRow = false;
// Do any additional setup after loading the view.
}
#pragma mark <UICollectionViewDataSource>
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return [[self.datasource itemsToLoad] count];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
JSMediaCollectionCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
[cell setImage:[UIImage imageNamed:[[self.datasource itemsToLoad] objectAtIndex:indexPath.row]]];
cell.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"photo-frame.png"]];
return cell;
}
...
...
JSMediaCell.m:
#interface JSMediaCollectionCell()
#property (nonatomic) UIImageView *view;
#end
#implementation JSMediaCollectionCell
- (id)initWithFrame:(CGRect)frame
{
if (!(self = [super initWithFrame:frame])) return nil;
self.view = [[UIImageView alloc] initWithFrame:self.frame];
[self.viewForBaselineLayout addSubview:self.view];
return self;
}
- (void)setImage:(UIImage *)image
{
self.view.image = image;
}
I greatly appreciate anyones help in getting me on the right track... Just as a reminder... As I start scrolling, the images are reloaded, but not all the cells have an image loaded in the subview... just some.

I can see that you are initialising the view property in the cell file with self.frame.
Instead, it should be
self.view = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
I think you can guess what went wrong.!!!
The frame should be wrt to the cell.
When the subview is added to cell, it takes the values of the origin of the cell, so it goes out of cell's view

Related

UITableView bottom area keeps out of screen if navigationBar.translucent is NO;

I use UITableView instance as the subview of my ViewController's view, the table's content is higher than the screen so it is scrollable. Here is the code in AppDelegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)opts {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
UINavigationController *nav = [[UINavigationController alloc] init];
self.window.rootViewController = nav;
[self.window makeKeyAndVisible];
UIViewController *controller = [[ViewController alloc] init];
[nav pushViewController:controller animated:YES];
// set to No cause the problem
nav.navigationBar.translucent = NO;
return YES;
}
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_tableView = [[UITableView alloc] initWithFrame:self.view.frame style:UITableViewStylePlain];
_tableView.delegate = self;
_tableView.dataSource = self;
[self.view addSubview:_tableView];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 20;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [[UITableViewCell alloc] init];
cell.textLabel.text = [NSString stringWithFormat:#"test %u", indexPath.row];
return cell;
}
#end
Now the problem is
if nav.navigationBar.translucent = YES, the content is scrolling right, the bottom line is visible if I scroll to bottom.
if nav.navigationBar.translucent = NO, the content isn't scrolling right, the bottom line automatically move out of the screen if I end the swip.
Seems like the auto hidden area is of the height of navigationBar, any one who knows how to fix it? I want it work the same no matter translucent = YES or translucent = NO.
Try this & let me know if it works:
self.tableView.contentInset = UIEdgeInsetsMake(44,0,0,0);
I figure out the solution, I set the tableView as the mainview of the controller, not a subview of the controller's mainview
[self setView:_tableView];
instead of
[self.view addSubview:_tableView];

UITableViewController cells disappear if inside a UIScrollView

This is my storyboard:
My scrollView is contains 3 NavigationController(containing BubbleListController which is a sort of Table view). These 3 views are put one aside the other and this is the code:
ioBubbleListController.h
#import <UIKit/UIKit.h>
#interface ioBubbleListController : UITableViewController {
NSDictionary *bubbles;
}
#end
ioBubbleListController.m
#import "ioBubbleListController.h"
#interface ioBubbleListController ()
#property (nonatomic, retain) NSDictionary *bubbles;
#end
#implementation ioBubbleListController
#synthesize bubbles;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (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.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
self.bubbles = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"bubbles" ofType:#"plist"]];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [self.bubbles count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return [[self.bubbles allKeys] objectAtIndex:section];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSString *continent = [self tableView:tableView titleForHeaderInSection:section];
return [[self.bubbles valueForKey:continent] count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CountryCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell...
NSString *continent = [self tableView:tableView titleForHeaderInSection:indexPath.section];
NSString *country = [[self.bubbles valueForKey:continent] objectAtIndex:indexPath.row];
cell.textLabel.text = country;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *continent = [self tableView:tableView titleForHeaderInSection:indexPath.section];
NSString *country = [[self.bubbles valueForKey:continent] objectAtIndex:indexPath.row];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil
message:[NSString stringWithFormat:#"You selected %#!", country]
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
#end
This is my ioUIPager which puts one BubbleList aside the other
#import "ioUIPager.h"
#implementation ioUIPager
#synthesize scrollView;
- (void)viewDidLoad {
[super viewDidLoad];
[self scrollView].contentSize = CGSizeMake(self.scrollView.frame.size.width * 3, self.scrollView.frame.size.height);
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"MainStoryboard_iPhone" bundle:nil];
// View1
UITableViewController *view1 = [sb instantiateViewControllerWithIdentifier:#"BubblesList"];
CGRect frame1;
frame1.origin.x = self.scrollView.frame.size.width * 0;
frame1.origin.y = 0;
frame1.size = self.scrollView.frame.size;
[self.scrollView addSubview:view1.view];
view1.view.frame = frame1;
view1.view.backgroundColor = [UIColor greenColor];
// View2
UIViewController *view2 = [sb instantiateViewControllerWithIdentifier:#"BubblesList"];
CGRect frame2;
frame2.origin.x = self.scrollView.frame.size.width * 1;
frame2.origin.y = 0;
frame2.size = self.scrollView.frame.size;
[self.scrollView addSubview:view2.view];
view2.view.frame = frame2;
view2.view.backgroundColor = [UIColor redColor];
// View2
UIViewController *view3 = [sb instantiateViewControllerWithIdentifier:#"BubblesList"];
CGRect frame3;
frame3.origin.x = self.scrollView.frame.size.width * 2;
frame3.origin.y = 0;
frame3.size = self.scrollView.frame.size;
[self.scrollView addSubview:view3.view];
view3.view.frame = frame3;
}
- (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;
self.scrollView = nil;
}
//- (void)dealloc {
// [scrollView release];
// [super dealloc];
//}
#end
Everything is rendered fine at first look, however any gesture/touch/tap I do on the UITableView/ioBubbleList, every cell disappears like this:
If from the storyboard I start from the navigator controller, then everything works fine. Any hint?
I solved this.
My issue was I was not keeping a reference of the UITableViewControllers and UITableViews I was adding inside the UIScrollView.
I just initialized and NSMutableArray and saved the UITableViewControllers the way I added the UITableViews into the UIScrollView.
EDIT
After some research I found that there is a smarter/better way to do this. Instead of keeping the instance inside our own array we should add the view controllers as childs to the container view controller (the UIViewController with the UIScrollView).
Here the explanation from apple docs:
https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/CreatingCustomContainerViewControllers/CreatingCustomContainerViewControllers.html
Here the code I used:
self.addChildViewController(tableViewController)
self.scrollView.addSubview(tableViewController.view)
tableViewController.didMoveToParentViewController(self)
Saving the tableViewControllers just in an array cannot keep track of the hierarchy inside the content view controller. This means that if we want to access the content view controller from the table view controllers we cannot. And several errors could happen with the UINavigationController if we are using it.

IOS, UICollectionview

New to IOS and objective C and been doing several tutorials, with adding buttons, textfields etc. Been looking alot on stackoverflow, which has been very helpful :) Now I am trying to create a collectionview within a frame and then put a button below it. I can get a button to show up, and the top half of the screen where I have defined the collection to appear turns black, while the rest goes white, as intended. Currently the collection should come up with a label telling me the cell number, so very basic. Not sure if I'm setting up my views wrong, or if there is something wrong with my CellViews.
I have created a mainView controller, where I have defined my button and collection view, like this:
MainViewController.h:
#interface MainViewController : UIViewController <UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>
#property(nonatomic, strong) IBOutlet UICollectionView *collectionView;
#property(nonatomic, strong) IBOutlet UIButton *diaryButton;
- (id)init;
My .m looks like this:
#implementation MainViewController
#synthesize collectionView;
#synthesize diaryButton;
- (id) init {
self = [super init];
if (self) {
CGRect buttonFrame = CGRectMake(10, 250, 70, 30);
diaryButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[diaryButton setFrame:buttonFrame];
[diaryButton setTitle:#"Diary" forState:UIControlStateNormal];
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
layout.itemSize = CGSizeMake(64.0, 64.0);
layout.minimumInteritemSpacing = 4;
layout.minimumLineSpacing = 4;
layout.scrollDirection = UICollectionViewScrollPositionCenteredVertically;
layout.sectionInset = UIEdgeInsetsMake(2.0, 2.0, 2.0, 2.0);
CGRect collectionFrame = CGRectMake(0, 0, 320, 200);
collectionView = [[UICollectionView alloc] initWithFrame:collectionFrame collectionViewLayout:layout];
[self.view addSubview:collectionView];
[self.view addSubview:diaryButton];
//[self.view setBackgroundColor:[UIColor blueColor]];
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"ID"];
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return 30;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"ID" forIndexPath:indexPath];
UILabel *label = [[UILabel alloc] initWithFrame:cell.bounds];
label.textAlignment = NSTextAlignmentCenter;
label.text = [NSString stringWithFormat:#"%d", indexPath.row];
[cell.contentView addSubview:label];
return cell;
}
/////////////////////////////////////////////////////////////////////////////////
// collection view delegate methods ////////////////////////////////////////
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"cell #%d was selected", indexPath.row);
}
My appdelegate looks like this:
#synthesize mainVC;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.mainVC = [[MainViewController alloc] init];
[self.window addSubview:mainVC.view];
//self.window.rootViewController = mainVC;
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Any help will be greatly appreciated.
I don't know exactly why your collection isn't showing anything, but you're missing the numberOfSectionsInCollectionView: method from the UICollectionViewDataSource. The collection view might be assuming that the number of sections is 0.
http://developer.apple.com/library/ios/#documentation/uikit/reference/UICollectionViewDataSource_protocol/Reference/Reference.html
Also, did you set the datasource and delegate to self for your UICollectionView?

Create a tableview with cells that link to videos

I want to create tableview cells that have a disclosure button that when pressed would link to a local video but I am having problems, when i click on the disclosure button the screen goes black, i am using arc. how can i go about this?
here's my sample code..What am i doing wrong
here is my header file
#import <UIKit/UIKit.h>
#import <MediaPlayer/MediaPlayer.h>
#interface BIDVideosViewController : UIViewController
<UITableViewDelegate, UITableViewDataSource>
#property (nonatomic,strong) NSArray *tableList;
#end
Here is my .m file
#import "BIDVideosViewController.h"
#interface BIDVideosViewController ()
{
MPMoviePlayerController *moviePlayer;
}
#end
#implementation BIDVideosViewController
#synthesize tableList;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
UITableView *table = [[UITableView alloc]initWithFrame:self.view.bounds];
[table setDelegate:self];
[table setDataSource:self];
[self.view addSubview:table];
NSArray *array = [[NSArray alloc] initWithObjects:#"Gangan",#"SwimGood", nil];
self.tableList = array;
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [tableList count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *DisclosureButtonIdentifier = #"DisclosurebutotonIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:DisclosureButtonIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:DisclosureButtonIdentifier];
}
NSInteger row = [indexPath row];
NSString *rowString = [tableList objectAtIndex:row];
cell.textLabel.text = rowString;
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
return cell;
}
-(void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath: (NSIndexPath *)indexPath
{
NSString *thePath = [[NSBundle mainBundle] pathForResource:#"Gangan" ofType:#"mp4"];
NSLog(#"path is ...%#", thePath);
NSURL *theurl = [NSURL fileURLWithPath:thePath];
MPMoviePlayerController *moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:theurl];
[moviePlayer.view setFrame:CGRectMake(0, 0, 320, 460)];
[self.view addSubview:moviePlayer.view];
[moviePlayer prepareToPlay];
[moviePlayer play];
}
You don't have a UITableView or the required numberOfSectionsInTableView: and tableView:numberOfRowsInSection: methods.
Try adding
UITableView *table = [[UITableView alloc] initWithFrame:self.view.bounds];
[table setDelegate:self];
[table setDataSource:self];
[self.view addSubview:table];
To your viewDidLoad function.
Check out the delegate and data source documentation for the required methods (and available ones too) to properly implement a UITableView. Its nice to do it this way, since it handles everything (drawing and setup) for you. All you have to do is give it the values and it automatically draws it upon loading the data.
you can try like this
NSString *thePath=[[NSBundle mainBundle] pathForResource:#"animation" ofType:#"mov"];
NSLog(#" path is...%#",thePath);
NSURL *theurl=[NSURL fileURLWithPath:thePath];
MPMoviePlayerController *moviePlayer =[[MPMoviePlayerController alloc] initWithContentURL:theurl];
[moviePlayer.view setFrame:CGRectMake(0, 0, 320, 460)];
[self.view addSubview: moviePlayer.view];
//[moviePlayer setFullscreen:YES animated:NO];
[moviePlayer prepareToPlay];
[moviePlayer play];
its worked for me , hope work for you too

iOS partial screen dialog for drop down listbox (android spinner) style control

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

Resources