Objective-C Index Array - ios

I'm building a (joke) app based on tinder's card swiping that enables me to keep score of a Magic the Gathering Game.
In the past, I've simply done this by incrementing and decrementing numbers as strings through. This worked fine.
Now I'm using Richard Kim's TinderSimpleSwipeCards, which loads cards from an array with integers. There is a method called to load the next number in the array when the card is swiped. Being new to Objective-C, I've spent an hour trying to repurpose the array to my needs. But I'm stuck.
Since players can gain and lose life in Magic The Gathering, my goal is to be able to first load 20, then swipe right to increase the number, and swipe left in decrease the number (down to 0).
My first idea was to create an array with 40 numbers, then have the method start at index of 20, which would load the card with the integer 20. Then, by calling the method in either direction, I could load cards in the positive or negative direction.
But that didn't work.
Here is Richard's DraggableViewBackground.m file. He calls the method in -(void)loadCards, which is where I've been attempting to manipulate the index number.
I'm fairly certain this can't be done using an array by simply starting at an index in the middle then running a For Loop in either direction (i-1) or (i+1). When I do call the object at a specific index number, the method will just continue to create cards at that index (for example, if I createDraggableViewWithDataAtIndex:4, a new card of 16 - the 5th item in the array will just continue to load the card with 16).
Can someone please confirm this can or cannot be done with a single array? If it can, could someone please lead me in the direction of how to load a card from the correct index?
//
// DraggableViewBackground.m
// testing swiping
//
// Created by Richard Kim on 8/23/14.
// Copyright (c) 2014 Richard Kim. All rights reserved.
//
#import "DraggableViewBackground.h"
#implementation DraggableViewBackground{
NSInteger cardsLoadedIndex; //%%% the index of the card you have loaded into the loadedCards array last
NSMutableArray *loadedCards; //%%% the array of card loaded (change max_buffer_size to increase or decrease the number of cards this holds)
UIButton* menuButton;
UIButton* messageButton;
UIButton* checkButton;
UIButton* xButton;
}
//this makes it so only two cards are loaded at a time to
//avoid performance and memory costs
static const int MAX_BUFFER_SIZE = 2; //%%% max number of cards loaded at any given time, must be greater than 1
static const float CARD_HEIGHT = 200; //%%% height of the draggable card
static const float CARD_WIDTH = 290; //%%% width of the draggable card
#synthesize exampleCardLabels; //%%% all the labels I'm using as example data at the moment
#synthesize allCards;//%%% all the cards
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[super layoutSubviews];
[self setupView];
exampleCardLabels = [[NSArray alloc]initWithObjects:#"20",#"19",#"18",#"17",#"16",#"15",#"14",#"13",#"12",#"11",#"10",#"9",#"8",#"7",#"6",#"5",#"4",#"3",#"2",#"1",#"DEATH", nil]; //%%% placeholder for card-specific information
loadedCards = [[NSMutableArray alloc] init];
allCards = [[NSMutableArray alloc] init];
cardsLoadedIndex = 0;
[self loadCards];
}
return self;
}
//%%% sets up the extra buttons on the screen
-(void)setupView
{
#warning customize all of this. These are just place holders to make it look pretty
self.backgroundColor = [UIColor colorWithRed:.92 green:.93 blue:.95 alpha:1]; //the gray background colors
menuButton = [[UIButton alloc]initWithFrame:CGRectMake(17, 34, 22, 15)];
[menuButton setImage:[UIImage imageNamed:#"menuButton"] forState:UIControlStateNormal];
messageButton = [[UIButton alloc]initWithFrame:CGRectMake(284, 34, 18, 18)];
[messageButton setImage:[UIImage imageNamed:#"messageButton"] forState:UIControlStateNormal];
xButton = [[UIButton alloc]initWithFrame:CGRectMake(60, 485, 59, 59)];
[xButton setImage:[UIImage imageNamed:#"xButton"] forState:UIControlStateNormal];
[xButton addTarget:self action:#selector(swipeLeft) forControlEvents:UIControlEventTouchUpInside];
checkButton = [[UIButton alloc]initWithFrame:CGRectMake(200, 485, 59, 59)];
[checkButton setImage:[UIImage imageNamed:#"checkButton"] forState:UIControlStateNormal];
[checkButton addTarget:self action:#selector(swipeRight) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:menuButton];
[self addSubview:messageButton];
[self addSubview:xButton];
[self addSubview:checkButton];
}
#warning include own card customization here!
//%%% creates a card and returns it. This should be customized to fit your needs.
// use "index" to indicate where the information should be pulled. If this doesn't apply to you, feel free
// to get rid of it (eg: if you are building cards from data from the internet)
-(DraggableView *)createDraggableViewWithDataAtIndex:(NSInteger)index
{
DraggableView *draggableView = [[DraggableView alloc]initWithFrame:CGRectMake((self.frame.size.width - CARD_WIDTH)/2, (self.frame.size.height - CARD_HEIGHT)/2, CARD_WIDTH, CARD_HEIGHT)];
draggableView.information.text = [exampleCardLabels objectAtIndex:index]; //%%% placeholder for card-specific information
draggableView.delegate = self;
return draggableView;
}
//%%% loads all the cards and puts the first x in the "loaded cards" array
-(void)loadCards
{
if([exampleCardLabels count] > 0) {
NSInteger numLoadedCardsCap =(([exampleCardLabels count] > MAX_BUFFER_SIZE)?MAX_BUFFER_SIZE:[exampleCardLabels count]);
//%%% if the buffer size is greater than the data size, there will be an array error, so this makes sure that doesn't happen
//%%% loops through the exampleCardsLabels array to create a card for each label. This should be customized by removing "exampleCardLabels" with your own array of data
for (int i = 0; i<[exampleCardLabels count]; i++) {
DraggableView* newCard = [self createDraggableViewWithDataAtIndex:i];
[allCards addObject:newCard];
if (i<numLoadedCardsCap) {
//%%% adds a small number of cards to be loaded
[loadedCards addObject:newCard];
}
}
//%%% displays the small number of loaded cards dictated by MAX_BUFFER_SIZE so that not all the cards
// are showing at once and clogging a ton of data
for (int i = 0; i<[loadedCards count]; i++) {
if (i>0) {
[self insertSubview:[loadedCards objectAtIndex:i] belowSubview:[loadedCards objectAtIndex:i-1]];
} else {
[self addSubview:[loadedCards objectAtIndex:i]];
}
cardsLoadedIndex++; //%%% we loaded a card into loaded cards, so we have to increment
}
}
}
#warning include own action here!
//%%% action called when the card goes to the left.
// This should be customized with your own action
-(void)cardSwipedLeft:(UIView *)card;
{
//do whatever you want with the card that was swiped
// DraggableView *c = (DraggableView *)card;
[loadedCards removeObjectAtIndex:0]; //%%% card was swiped, so it's no longer a "loaded card"
if (cardsLoadedIndex < [allCards count]) { //%%% if we haven't reached the end of all cards, put another into the loaded cards
[loadedCards addObject:[allCards objectAtIndex:cardsLoadedIndex]];
cardsLoadedIndex++;//%%% loaded a card, so have to increment count
[self insertSubview:[loadedCards objectAtIndex:(MAX_BUFFER_SIZE-1)] belowSubview:[loadedCards objectAtIndex:(MAX_BUFFER_SIZE-2)]];
}
}
#warning include own action here!
//%%% action called when the card goes to the right.
// This should be customized with your own action
-(void)cardSwipedRight:(UIView *)card
{
//do whatever you want with the card that was swiped
// DraggableView *c = (DraggableView *)card;
[loadedCards removeObjectAtIndex:0]; //%%% card was swiped, so it's no longer a "loaded card"
if (cardsLoadedIndex < [allCards count]) { //%%% if we haven't reached the end of all cards, put another into the loaded cards
[loadedCards addObject:[allCards objectAtIndex:cardsLoadedIndex]];
cardsLoadedIndex++;//%%% loaded a card, so have to increment count
[self insertSubview:[loadedCards objectAtIndex:(MAX_BUFFER_SIZE-1)] belowSubview:[loadedCards objectAtIndex:(MAX_BUFFER_SIZE-2)]];
}
}
//%%% when you hit the right button, this is called and substitutes the swipe
-(void)swipeRight
{
DraggableView *dragView = [loadedCards firstObject];
dragView.overlayView.mode = GGOverlayViewModeRight;
[UIView animateWithDuration:0.2 animations:^{
dragView.overlayView.alpha = 1;
}];
[dragView rightClickAction];
}
//%%% when you hit the left button, this is called and substitutes the swipe
-(void)swipeLeft
{
DraggableView *dragView = [loadedCards firstObject];
dragView.overlayView.mode = GGOverlayViewModeLeft;
[UIView animateWithDuration:0.2 animations:^{
dragView.overlayView.alpha = 1;
}];
[dragView leftClickAction];
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
#end

If I understood you correctly, an array is not necessary. I would save the current index of the cards in an integer value and a method to increase and decrease it by checking bounds.
There is already an ivar NSInteger cardsLoadedIndex;
In my opionion a method like this would work:
- (NSUInteger) getIndexDirectionRight:(BOOL)direction{
if (direction){
return (cardsLoadedIndex < MAX_VALUE) ? cardsLoadedIndex + 1 : 0;
}else{
return (cardsLoadedIndex > 0) ? cardsLoadedIndex - 1 : MAX_VALUE;
}
}
And you can call the method in swipeRight or swipeLeft
and you initialize the cardsLoadedIndex to 20 in the initWithFrame method (as it is already set to 0).

Related

VFL with Xcode for Auto Layout

I have an existing application that has the positioning of all the elements written in code rather then in auto-layout. I am trying to use that existing code to add Auto-Layout for those elements.
I am trying to have the two buttons xButton and checkButton to show up at the bottom of the screen next to each other, which will work for all iPhone screens. The current behavior is that the buttons are offset towards the bottom of the screen.
Below is my code where my VFL is located - however this is placed in a UIView instead of a ViewController.
I have tried to figure this out on my own but no luck, I would love it if someone could give me a hand with this topic as well as this certain issue.
Thank you
#implementation DraggableViewBackground{
NSInteger cardsLoadedIndex; //%%% the index of the card you have loaded into the loadedCards array last
NSMutableArray *loadedCards; //%%% the array of card loaded (change max_buffer_size to increase or decrease the number of cards this holds)
UIButton* checkButton;
UIButton* xButton;
}
//this makes it so only two cards are loaded at a time to
//avoid performance and memory costs
static const int MAX_BUFFER_SIZE = 2; //%%% max number of cards loaded at any given time, must be greater than 1
static const float CARD_HEIGHT = 386; //%%% height of the draggable card
static const float CARD_WIDTH = 290; //%%% width of the draggable card
#synthesize exampleCardLabels; //%%% all the labels I'm using as example data at the moment
#synthesize allCards;//%%% all the cards
- (void)loadView {
[self setupView];
exampleCardLabels = [[NSArray alloc]initWithObjects:#"Are you in the Technology Industry?",#"Do you have more then 3 years of work experiance?",#"Do you have more then 3 years of work experiance?",#"Are you willing to relocate?",#"Did you enjoy this app?", nil]; //%%% placeholder for card-specific information
loadedCards = [[NSMutableArray alloc] init];
allCards = [[NSMutableArray alloc] init];
cardsLoadedIndex = 0;
[self loadCards];
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[super layoutSubviews];
[self setupView];
exampleCardLabels = [[NSArray alloc]initWithObjects:#"Are you in the Technology Industry?",#"Do you have more then 3 years of work experiance?",#"Do you have more then 3 years of work experiance?",#"Are you willing to relocate?",#"Did you enjoy this app?", nil]; //%%% placeholder for card-specific information
loadedCards = [[NSMutableArray alloc] init];
allCards = [[NSMutableArray alloc] init];
cardsLoadedIndex = 0;
[self loadCards];
}
return self;
}
//%%% sets up the extra buttons on the screen
// VFL Visual Formal Language -
- (void)setupView {
#warning customize all of this. These are just place holders to make it look pretty
self.backgroundColor = [UIColor colorWithRed:.92 green:.93 blue:.95 alpha:1]; //the gray background colors
xButton = [[UIButton alloc]initWithFrame:CGRectMake(60, CGRectGetHeight(self.frame)- 100, 59, 59)];
[xButton setImage:[UIImage imageNamed:#"xButton"] forState:UIControlStateNormal];
[xButton addTarget:self action:#selector(swipeLeft) forControlEvents:UIControlEventTouchUpInside];
[xButton setTranslatesAutoresizingMaskIntoConstraints:NO];
[xButton setBackgroundColor:[UIColor redColor]];
checkButton = [[UIButton alloc]initWithFrame:CGRectMake(200, CGRectGetHeight(self.frame)- 100, 59, 59)];
[checkButton setImage:[UIImage imageNamed:#"checkButton"] forState:UIControlStateNormal];
[checkButton addTarget:self action:#selector(swipeRight) forControlEvents:UIControlEventTouchUpInside];
[checkButton setTranslatesAutoresizingMaskIntoConstraints:NO];
[checkButton setBackgroundColor:[UIColor blueColor]];
[self addSubview:xButton];
[self addSubview:checkButton];
}
#warning include own card customization here!
//%%% creates a card and returns it. This should be customized to fit your needs.
// use "index" to indicate where the information should be pulled. If this doesn't apply to you, feel free
// to get rid of it (eg: if you are building cards from data from the internet)
-(DraggableView *)createDraggableViewWithDataAtIndex:(NSInteger)index
{
DraggableView *draggableView = [[DraggableView alloc]initWithFrame:CGRectMake((self.frame.size.width - CARD_WIDTH)/2,(self.frame.size.height - CARD_HEIGHT)/2, CARD_WIDTH, CARD_HEIGHT)];
draggableView.information.text = [exampleCardLabels objectAtIndex:index];//%%% placeholder for card-specific information
draggableView.delegate = self;
return draggableView;
}
//%%% loads all the cards and puts the first x in the "loaded cards" array
-(void)loadCards
{
if([exampleCardLabels count] > 0) {
NSInteger numLoadedCardsCap =(([exampleCardLabels count] > MAX_BUFFER_SIZE)?MAX_BUFFER_SIZE:[exampleCardLabels count]);
//%%% if the buffer size is greater than the data size, there will be an array error, so this makes sure that doesn't happen
//%%% loops through the exampleCardsLabels array to create a card for each label. This should be customized by removing "exampleCardLabels" with your own array of data
for (int i = 0; i<[exampleCardLabels count]; i++) {
DraggableView* newCard = [self createDraggableViewWithDataAtIndex:i];
[allCards addObject:newCard];
if (i<numLoadedCardsCap) {
//%%% adds a small number of cards to be loaded
[loadedCards addObject:newCard];
}
}
//%%% displays the small number of loaded cards dictated by MAX_BUFFER_SIZE so that not all the cards
// are showing at once and clogging a ton of data
for (int i = 0; i<[loadedCards count]; i++) {
if (i>0) {
[self insertSubview:[loadedCards objectAtIndex:i] belowSubview:[loadedCards objectAtIndex:i-1]];
} else {
[self addSubview:[loadedCards objectAtIndex:i]];
}
cardsLoadedIndex++; //%%% we loaded a card into loaded cards, so we have to increment
}
}
}
#warning include own action here!
//%%% action called when the card goes to the left.
// This should be customized with your own action
-(void)cardSwipedLeft:(UIView *)card;
{
//do whatever you want with the card that was swiped
// DraggableView *c = (DraggableView *)card;
[loadedCards removeObjectAtIndex:0]; //%%% card was swiped, so it's no longer a "loaded card"
if (cardsLoadedIndex < [allCards count]) { //%%% if we haven't reached the end of all cards, put another into the loaded cards
[loadedCards addObject:[allCards objectAtIndex:cardsLoadedIndex]];
cardsLoadedIndex++;//%%% loaded a card, so have to increment count
[self insertSubview:[loadedCards objectAtIndex:(MAX_BUFFER_SIZE-1)] belowSubview:[loadedCards objectAtIndex:(MAX_BUFFER_SIZE-2)]];
}
}
#warning include own action here!
//%%% action called when the card goes to the right.
// This should be customized with your own action
-(void)cardSwipedRight:(UIView *)card
{
//do whatever you want with the card that was swiped
// DraggableView *c = (DraggableView *)card;
[loadedCards removeObjectAtIndex:0]; //%%% card was swiped, so it's no longer a "loaded card"
if (cardsLoadedIndex < [allCards count]) { //%%% if we haven't reached the end of all cards, put another into the loaded cards
[loadedCards addObject:[allCards objectAtIndex:cardsLoadedIndex]];
cardsLoadedIndex++;//%%% loaded a card, so have to increment count
[self insertSubview:[loadedCards objectAtIndex:(MAX_BUFFER_SIZE-1)] belowSubview:[loadedCards objectAtIndex:(MAX_BUFFER_SIZE-2)]];
}
}
//%%% when you hit the right button, this is called and substitutes the swipe
-(void)swipeRight
{
DraggableView *dragView = [loadedCards firstObject];
dragView.overlayView.mode = GGOverlayViewModeRight;
[UIView animateWithDuration:0.2 animations:^{
dragView.overlayView.alpha = 1;
}];
[dragView rightClickAction];
}
//%%% when you hit the left button, this is called and substitutes the swipe
-(void)swipeLeft
{
DraggableView *dragView = [loadedCards firstObject];
dragView.overlayView.mode = GGOverlayViewModeLeft;
[UIView animateWithDuration:0.2 animations:^{
dragView.overlayView.alpha = 1;
}];
[dragView leftClickAction];
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
#end
To achieve what you want to do with the buttons you can use VFL like this:
self.view.translatesAutoresizingMaskIntoConstraints = NO;
button1.translatesAutoresizingMaskIntoConstraints = NO;
button2.translatesAutoresizingMaskIntoConstraints = NO;
NSDictionary *viewsDict = #{#"button1": button1, #"button2": button2};
NSArray *horizontalContraints = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[button1(150)][button2(150)]-|"
options:NSLayoutFormatAlignAllBottom
metrics:nil
views:viewsDict];
NSArray *verticalConstraintsButton1 = [NSLayoutConstraint constraintsWithVisualFormat:#"V:[button1]-20-|"
options:NSLayoutFormatAlignAllCenterX
metrics:nil
views:viewsDict];
NSArray *verticalConstraintsButton2 = [NSLayoutConstraint constraintsWithVisualFormat:#"V:[button2]-20-|"
options:NSLayoutFormatAlignAllCenterX
metrics:nil
views:viewsDict];
[self.view addConstraints:horizontalContraints];
[self.view addConstraints:verticalConstraintsButton1];
[self.view addConstraints:verticalConstraintsButton2];
This give the buttons each a width of 150 pt and places them 20 pt from the left, right and bottom of your view.

Reload UIScrollView by tapping a UIButton

Let me explain my project first. I have some data in my SQLIte DB table called "note".
In "note" table I have these fields: id, noteToken, note.
What I am doing here is load all the note in an NSMUtableArray from that table. And create UIButton according to that array content number and add those buttons in a UIScrollView as subView. The number of buttons and width of scrollview generate auto according to the number of content of that array. Now, when some one tap one of those Buttons, it will bring him to a next viewController and show him the corresponding note details in that viewController.
I do the same thing with another NSMUtableArray, but these time it read all the id from the "note" table. It equally generate new delete button in the same UIScrollView. But if some one tap on these delete button it will delete that particular note from the table "note" of SQLIte DB. AND RELOAD THE UIScrollView. All are done except the RELOAD THE UIScrollView part. This is what I want. I tried with all exist solution but don't know why it's not working.
Here is my code:
- (void)viewDidLoad
{
[super viewDidLoad];
self.noteToken = [NSString stringWithFormat:#"%#%#", fairId, exibitorId];
scrollViewNoteWidth = 100;
[scrollViewNote setScrollEnabled:YES];
[scrollViewNote setContentSize:CGSizeMake((noteButtonWidth * countNoteButtonArray) + scrollViewNoteWidth, 100)];
sqLite = [[SQLite alloc] init];
[self.sqLite callDataBaseAndNoteTableMethods];
self.noteButtonArrayy = [[NSMutableArray alloc] init];
noteButtonArrayy = [self.sqLite returnDataFromNoteTable:noteToken];
[self LoadNoteButtonAndDeleteButton:noteButtonArrayy];
}
//////////////*----------------------- Note Section (Down) -----------------------*//////////////
-(void) LoadNoteButtonAndDeleteButton:(NSMutableArray *) noteButtonArray
{
sQLiteClass = [[SQLiteClass alloc] init];
noteButtonArrayToShowNoteButton = [[NSMutableArray alloc] init];
/*--------------- Load the noteButton & pass note (Down)---------------*/
for (int i = 0; i < [noteButtonArray count]; i++)
{
sQLiteClass = [noteButtonArray objectAtIndex:i];
// NSString *ids = [NSString stringWithFormat:#"%d", sQLiteClass.idNum];
NSString *nt = sQLiteClass.note;
[noteButtonArrayToShowNoteButton addObject:nt];
}
[self ShowNoteButtonMethod:noteButtonArrayToShowNoteButton];
/*--------------- Load the noteButton & pass note (Up)---------------*/
/*--------------- Load the deleteButton & pass id (Down)---------------*/
noteButtonArrayToDeleteNoteButton = [[NSMutableArray alloc] init];
for (int i = 0; i < [noteButtonArray count]; i++)
{
sQLiteClass = [noteButtonArray objectAtIndex:i];
// Convert int into NSString
NSString *ids = [NSString stringWithFormat:#"%d", sQLiteClass.idNum];
[noteButtonArrayToDeleteNoteButton addObject:ids];
}
[self ShowNoteDeleteButtonMethod:noteButtonArrayToDeleteNoteButton];
/*--------------- Load the deleteButton & pass id (Down)---------------*/
}
-(void) ShowNoteButtonMethod:(NSMutableArray *) btnarray
{
countNoteButtonArray = [btnarray count];
// For note button
noteButtonWidth = 60;
noteButtonXposition = 8;
for (NSString *urls in btnarray)
{
noteButtonXposition = [self addNoteButton:noteButtonXposition AndURL:urls];
}
}
-(int) addNoteButton:(int) xposition AndURL:(NSString *) urls
{
noteButton =[ButtonClass buttonWithType:UIButtonTypeCustom];
noteButton.frame = CGRectMake(noteButtonXposition, 8.0, noteButtonWidth, 60.0);
[noteButton setImage:[UIImage imageNamed:#"note.png"] forState:UIControlStateNormal];
[noteButton addTarget:self action:#selector(tapOnNoteButton:) forControlEvents:UIControlEventTouchUpInside];
[noteButton setUrl:urls];
noteButton.backgroundColor = [UIColor clearColor];
[self.scrollViewNote addSubview:noteButton];
noteButtonXposition = noteButtonXposition + noteButtonWidth + 18;
return noteButtonXposition;
}
-(void)tapOnNoteButton:(ButtonClass*)sender
{
urlNote = sender.url;
[self performSegueWithIdentifier:#"goToNoteDetailsViewController" sender:urlNote];
}
-(void) ShowNoteDeleteButtonMethod:(NSMutableArray *) btnarray
{
countNoteButtonArray = [btnarray count];
// For delete button
deleteNoteButtonWidth = 14;
deleteNoteButtonXposition = 31;
for (NSString *idNumber in btnarray)
{
deleteNoteButtonXposition = [self addDeleteButton:deleteNoteButtonXposition AndURL:idNumber];
}
}
-(int) addDeleteButton:(int) xposition AndURL:(NSString *) idNumber
{
deleteNoteButton =[ButtonClass buttonWithType:UIButtonTypeCustom];
deleteNoteButton.frame = CGRectMake(deleteNoteButtonXposition, 74.0, deleteNoteButtonWidth, 20.0);
[deleteNoteButton setImage:[UIImage imageNamed:#"delete.png"] forState:UIControlStateNormal];
[deleteNoteButton addTarget:self action:#selector(tapOnDeleteButton:) forControlEvents:UIControlEventTouchUpInside];
[deleteNoteButton setIdNum:idNumber];
deleteNoteButton.backgroundColor = [UIColor clearColor];
[self.scrollViewNote addSubview:deleteNoteButton];
deleteNoteButtonXposition = deleteNoteButtonXposition + deleteNoteButtonWidth + 65;
return deleteNoteButtonXposition;
}
-(void)tapOnDeleteButton:(ButtonClass*)sender
{
idNumb = sender.idNum;
[self.sqLite deleteData:[NSString stringWithFormat:#"DELETE FROM note WHERE id IS '%#'", idNumb]];
// NSLog(#"idNumb %#", idNumb);
//[self.view setNeedsDisplay];
//[self.view setNeedsLayout];
//[self LoadNoteButtonAndDeleteButton];
//[self viewDidLoad];
// if ([self isViewLoaded])
// {
// //self.view = Nil;
// //[self viewDidLoad];
// [self LoadNoteButtonAndDeleteButton];
// }
}
//////////////*----------------------- Note Section (Up) -----------------------*//////////////
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"goToNoteDetailsViewController"])
{
NoteDetailsViewController *noteDetailsViewController = [segue destinationViewController];
[noteDetailsViewController setUrl:sender];
}
}
Here's the screen shot:
Here we can feel the difference between UIScrollView and UICollectionView, however UICollectionView is made up of UIScrollView, UICollectionView can be reload and adjust its content accordingly, where UIScrollView can't.
Ok, now in your case, you've to reload (refresh) your scroll view, which is not possible as we can with UICollectionView or UITableView.
You've two options,
Best option (little tough) : replace UIScrollView with UICollectionView - will take some of your time, but better for reducing code complexity and good performance of your app.
Poor option (easy) : Stay as it with UIScrollView - when you want to reload, delete each subview from it, and then again show and load everything. Highly not recommended.
IMHO, you should go with best option.

Implementing a volume graph on iOS

I'm trying to implement a graph (UIView) like this:
My current approach is to draw the rounded rects with UIBezierPath inside drawRect, store a pointer to every path in a private NSMutableArray and in my View Controller send a message to update the graph with the new value. (https://gist.github.com/gverri/f238ad17f90013bfc832)
But somehow I can't send a message to my view to change the colors of the paths.
.
I'm still a relative beginner and I'm sure I'm trying to reinvent the wheel somehow. Or just missing something obvious.
Should I redraw the graph at every update (1s ~ 2s)?! Should I use a special framework to do this?
Edit:
After digging a little I found out that I can't save a pointer to a path. After drawRect my pointers disappear from the array.
It seems I would need to use Core Graphics do make it work with this approach.
Is there an easier alternative?
I made a test app that uses a column view with 7 rounded rect subviews to implement the graph. Here's the ColumnView class (a subview of UIView),
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
NSMutableArray *temp = [NSMutableArray new];
_offColor = [UIColor colorWithRed:238/255.0 green:230/255.0 blue:238/255.0 alpha:1];
_onColor = [UIColor colorWithRed:154/255.0 green:102/255.0 blue:155/255.0 alpha:1];
for (int i=0; i<7; i++) {
UIView *roundRect = [[UIView alloc] initWithFrame:CGRectMake(0, i*34, frame.size.width -2, (frame.size.height/7) - 4)];
roundRect.backgroundColor = _offColor;
roundRect.layer.cornerRadius = 3;
[temp insertObject:roundRect atIndex:0];
[self addSubview:roundRect];
}
_columns = [NSArray arrayWithArray:temp];
}
return self;
}
-(void)setNumberOfDarkRects:(NSInteger) num {
[self.columns enumerateObjectsUsingBlock:^(UIView *sub, NSUInteger idx, BOOL *stop) {
if (idx + 1 <= num) {
sub.backgroundColor = self.onColor;
}else{
sub.backgroundColor = self.offColor;
}
}];
}
This is how I create the grid, and test updating the columns,
#interface ViewController ()
#property (strong,nonatomic) NSMutableArray *columns;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.columns = [NSMutableArray new];
for (int i=0; i<21; i++) {
ColumnView *column = [[ColumnView alloc] initWithFrame:CGRectMake(i * 22 + 10, 50, 22, 240)];
[self.view addSubview:column];
[self.columns addObject:column];
}
[self performSelector:#selector(doRandomColoring) withObject:nil afterDelay:2];
}
-(void)doRandomColoring {
for (ColumnView *col in self.columns) {
[col setNumberOfDarkRects:arc4random_uniform(8)];
}
[self performSelector:#selector(doRandomColoring) withObject:nil afterDelay:.2];
}

UIStepper issue: decrements but won't increment

I have a weird issue with a UIStepper (and it's accompanying UITextField)
Consider this code snippet:
#interface LTRPageTracker : UIView <UITextFieldDelegate>
{
UIStepper* page_move;
UITextField* page_no_view;
}
-(void) nextOrPrevPage:(id)sender forEvent:(UIControlEvents) event;
#implementation LTRPageTracker
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
CGRect stepperFrame, pageNoframe;
pageNoframe.origin = frame.origin;
pageNoframe.size.height = frame.size.height;
pageNoframe.size.width = frame.size.width/2;
stepperFrame.origin.x = pageNoframe.origin.x + pageNoframe.size.width +1;
stepperFrame.origin.y = frame.origin.y;
stepperFrame.size = pageNoframe.size;
page_move = [[UIStepper alloc] initWithFrame:stepperFrame];
[page_move setMinimumValue:0];
[page_move setValue:7];
page_move.maximumValue =1000;
[page_move addTarget:self action:#selector(nextOrPrevPage:forEvent:) forControlEvents:UIControlEventValueChanged];
page_no_view = [[UITextField alloc] initWithFrame:pageNoframe];
page_no_view.delegate = self;
page_no_view.backgroundColor = [UIColor redColor];
[self addSubview:page_no_view];
[self addSubview:page_move];
[page_move sendActionsForControlEvents:UIControlEventValueChanged];
[page_move setEnabled:YES];
}
return self;
}
-(void) nextOrPrevPage:(id) sender forEvent:(UIControlEvents) event {
//assert(sender == page_move);
NSLog(#"Event is %x", event);
page_no_view.text = [[NSNumber numberWithDouble: page_move.value] stringValue];
}
I have added this View to the navigation bar.
And I can decrement the value of the UIStepper but no increment it (the event will simply not get triggered for increment but will do so decrement).
WHY?
Using iOS 7, running on simulator.
Whenever you have a problem with a UI element not responding, the first thing you should check is whether it (or part of it) is outside the bounds of its superview (the part that's out of the bounds will not respond). An easy way to do this, is to give the superview a background color. In the init method assign a background color to self, and see what that shows you. I'm betting that you'll see that the right side of the stepper is not within its superview, so you'll need to make that view bigger, or change the stepper's position within that view.
If you make the view's frame 150x30, and change these two lines in the view's init method, I think it should work ok for a number as large as 1000:
pageNoframe.size.width = frame.size.width/4; // changed 2 to 4
stepperFrame.origin.x = pageNoframe.origin.x + pageNoframe.size.width+20; // changed 1 to 20

Generate grid of buttons with two parameters for iOS

I need to generate a grid of buttons for an iOS app. Each button needs two parameters: the number of the column and the number of the row. A button will also have two states, activated and deactivated.
When the app is loaded I want there to be like 21 rows and 16 columns. And somewhere on the screen there will also be a button that says "add columns" and this would add 4 extra columns every time it's clicked.
Any suggestions how I should do this? I could start by adding the first 21*16 buttons with the IB but will that allow me to extend it with extra columns later on, and how?
Edit: the bounty was only started to reward mbm30075, no new answers necessary
I believe this is a more complete solution. Here's the .h/.m pair I wrote up for testing:
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#property (assign, nonatomic) int numColumns;
#property (assign, nonatomic) int numRows;
#property (strong, nonatomic) NSMutableArray *buttonsArray;
#property (strong, nonatomic) IBOutlet UIScrollView *scrollView;
#property (strong, nonatomic) IBOutlet UIButton *addButtons;
#property (strong, nonatomic) IBOutlet UIView *buttonsView;
- (IBAction)addFourMoreColumns;
#end
ViewController.m
#import "ViewController.h"
#implementation ViewController
#synthesize addButtons;
#synthesize buttonsArray;
#synthesize buttonsView;
#synthesize numColumns;
#synthesize numRows;
#synthesize scrollView;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self setButtonsArray:[NSMutableArray array]];
[self setNumColumns:16];
[self setNumRows:21];
[self layoutButtons];
}
- (void)layoutButtons {
static int width = 100;
static int height = 37;
static int buffer = 8; // space between buttons (horiz. & vert.)
static int margin = 20;
CGPoint topLeft = CGPointMake(margin,margin); // standard "top left" in iOS
// Since you appear to be wanting to modify the number of columns,
// I'm going to make the multi-dimension array an array of columns,
// with each column containing an array of buttons (representing the rows)
// Iterate through how many columns SHOULD exist ([self numColumns])
for (int i = 0; i < [self numColumns]; i = i + 1) {
// Check if this "column" exists (does this index exist in [self buttonsArray]?)
if (i >= [[self buttonsArray] count]) {
// It doesn't exist, so we need to add a blank array
[[self buttonsArray] addObject:[NSMutableArray array]];
}
NSMutableArray *column = [[self buttonsArray] objectAtIndex:i];
// Now, we iterate through how many rows/buttons SHOULD exist ([self numRows])
for (int j = 0; j < [self numRows]; j = j + 1) {
// Check if this "row"/"cell"/"button" exists
if (j >= [column count]) {
// It doesn't exist, so we need to add a new button AND PLACE IT!
// Of course, you need to make your button type correctly
// This is just standard button code...
UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[btn setFrame:CGRectMake(topLeft.x,topLeft.y,width,height)];
// Do whatever else you need to do with the button...
// Set title...
[btn setTitle:[NSString stringWithFormat:#"(%d,%d)", i + 1, j + 1] forState:UIControlStateNormal];
// Add target actions...
[btn addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
// Add the button to the view
[[self buttonsView] addSubview:btn];
// Add the button to the array
[column addObject:btn];
}
// Increment topLeft to the next "row" for correct button placement...
topLeft = CGPointMake(topLeft.x, topLeft.y + height + buffer);
}
// Increment topLeft to the next "column" for correct button placement...
topLeft = CGPointMake(topLeft.x + width + buffer, margin);
}
// So, I'm assuming your "add columns" button will be placed equivalent to
// "(columnCount + 1, 1)", or at the top of the screen, just to the right
// of the right-most column of buttons
// [self addButtons] is the property to the UIButton that calls [self addFourMoreColumns]
[[self addButtons] setFrame:CGRectMake(topLeft.x, topLeft.y, [[self addButtons] frame].size.width, [[self addButtons] frame].size.height)];
// Now, update the view that holds the buttons to give it a new size (based on the buttons added)
CGRect viewFrame = CGRectMake(0, 0, CGRectGetMaxX([[self addButtons] frame]) + buffer, 20 + ([[self buttonsArray] count] * (height + buffer)));
[[self buttonsView] setFrame:viewFrame];
[[self scrollView] setContentSize:viewFrame.size];
// Redraw the view...
[[self view] setNeedsDisplay];
}
- (IBAction)addFourMoreColumns {
[self setNumColumns:[self numColumns] + 4];
[self layoutButtons];
}
// Shows in the log which button you pressed: "(col, row)"
- (void)buttonPressed:(id)sender {
for (int i = 0; i < [[self buttonsArray] count]; i = i + 1) {
NSMutableArray *col = [[self buttonsArray] objectAtIndex:i];
for (int j = 0; j < [col count]; j = j + 1) {
if (sender == [col objectAtIndex:j]) {
NSLog(#"button (%d,%d) pressed", i + 1, j + 1);
break;
}
}
}
}
#end
Xib setup is basic with:
View // tied to [ViewController view]
|
--->ScrollView // tied to [ViewController scrollView]
|
--->View // tied to [ViewController buttonsView]
|
--->UIButton // tied to [ViewController addButtons]
this can be achieved using the scroll view UIScrollView and using two for loops to add required buttons at run time like
for(int col = 0; col < [max column]; col++)
{
for(int row = 0; row < [max row]; row++)
{
//add buttons assigning them proper frame size
}
}
You will need to add buttons programmatically using 2 loops. Also to identify the buttons assign them tags which are a number made by combination of column number and row number.
Eg:- button at row 1 and column 1 may have tag as 11.
Using the tag values you can identify which button is clicked and perform corresponding action.

Resources