Properties of UILabel on UIViewController on UIScrollView - ios

Consider the following situation:
I have this myViewcontroller. On the Storyboard I have added a UIViewController, defined it as a myViewcontroller, with a couple of UILabels on them. I have properly connected them to the IBOutlets.
Then, I have a scrollview. I add instances of myViewcontroller to that scrollview as such:
- (void)configureInfoViewController
{
for (int i = 0; i < [Lists count]; i++) {
myViewcontroller *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"myLabelLayout"];
[self addChildViewController:vc];
}
}
- (void)configureScrollView
{
for (int i = 0; i < [self.childViewControllers count]; i++) {
CGRect frame = theScrollView.frame;
...
[[[self.childViewControllers objectAtIndex:i] view] setFrame:frame];
[theScrollView addSubview:[[self.childViewControllers objectAtIndex:i] view]];
}
}
So, I have as many subviews in theScrollview as there are objects in Lists. So far so good.
But now, I want to set the text of a label in one of these subviews. I want to accomplish that by pushing a UIButton on that very same instance of that myViewcontroller.
The question is: how do I set that myLable.title?
I hope this makes sense.
I think the REAL question is, that bothers me:
How do I know on what subview my UIButton resides. I could then send that metadata to other methods. Thanks.

I am assuming you have created outlets for your labels and when you push the button can't you just access the label and change its text in the button's IBAction method?
Here is what you need,
#import "MyViewcontroller.h"
#implementation MyViewcontroller
- (IBAction)myButtonAction:(id)sender {
_myLabel.text = #"My custom value";
}
#end
FYI, your InfoViewController your configureScrollView method should be like this. I don't see your scroll view content size adjusted in your code.
- (void)configureScrollView {
for (int i=0; i<self.childViewControllers.count; i++) {
CGRect frame = theScrollView.frame;
// scrolling vertically here
frame.origin.y = CGRectGetHeight(frame) * i;
UIView *view = [[self.childViewControllers objectAtIndex:i] view];
[view setFrame:frame];
[theScrollView addSubview:view];
}
theScrollView.contentSize = CGSizeMake(CGRectGetWidth(theScrollView.frame), CGRectGetHeight(theScrollView.frame) * self.childViewControllers.count);
}

Related

UIScrollView with many UITableVIew inside UIViewControllers disappear UITableViewCell's on tap

I need to make UIScrollView with UIViewController's inside, every UIViewController has UITableview.
When I tap to UITableview, all UITableViewCells are disappear.
How I initialise UIViewController inside UIScrollView?
- (void)viewDidLoad {
[super viewDidLoad];
int width = 0;
for (int i = 0; i < [self.dishes count]; i++) {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Order" bundle:nil];
OneDayDishViewController *myVC = (OneDayDishViewController *)[storyboard instantiateViewControllerWithIdentifier:#"OneDayDishViewController"];
myVC.dishes = self.dishes[i];
myVC.menuTitle = self.menuTitle;
[self.scrollView addSubview:myVC.view];
width += 375;
}
self.scrollView.contentSize = CGSizeMake(width,0);
}
After looking for in google & stack overflow I found this solution
So I done something like this
in my .h file (where I have UIScrollView):
#property (strong, nonatomic) OneDayDishViewController *myVC;
Than in my .m file:
- (void)viewDidLoad {
[super viewDidLoad];
int width = 0;
for (int i = 0; i < [self.dishes count]; i++) {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Order" bundle:nil];
self.myVC = [storyboard instantiateViewControllerWithIdentifier:#"OneDayDishViewController"];
self.myVC.dishes = self.dishes[i];
self.myVC.menuTitle = self.menuTitle;
[self.scrollView addSubview:self.myVC.view];
width += 375;
}
self.scrollView.contentSize = CGSizeMake(width,0);
}
Now I also have N elements in my scrollview, if I tap the last element - it's work fine, if I tap any other element - the problem is the same.
So what I do wrong or how I can create (strong) proper dynamically and is it good practice?
Thanks
UPDT:
Thank you #CZ54
my solution is add childviewcontroller so do
[self addChildViewController:myVC];
[self.scrollView addSubview:myVC.view];
[myVC didMoveToParentViewController:self];
instead of
[self.scrollView addSubview:myVC.view];
Adding the subview is not enough.
You have to add the entire controller using
addChildViewController: ( from https://developer.apple.com/documentation/uikit/uiviewcontroller/1621394-addchildviewcontroller )
And you have to retain every instance you are adding.
Change
#property (strong, nonatomic) OneDayDishViewController *myVC;
into
#property (strong, nonatomic) NSMutableArray<OneDayDishViewController*> *myVC;

How do I segue from programmatically created UIImageView

I have programmatically created UIImage instances which increases as the number of imageArray count increases and UIImage are set to them programmatically. Since those UIImageView are not visible in Storyboard, how can I segue from that UIViewController to another UIViewController containing an instance of UIImage to show image in detail. How to segue to another UIViewController when any of my UIImageView is touched.
Here is the code:
#import "FirstPageViewController.h"
#interface FirstPageViewController ()
#property (nonatomic, strong) UIImageView *imageView;
#property UIImage *image;
#property NSArray *imgArray;;
#property NSMutableArray *imgNameArray;
#property UIView *containerView;
#property UIView *containerView2;
#end
#implementation FirstPageViewController
for (NSString *img in imgArray) {
[imgNameArray addObject:img];
}
int Y = 0;
int X = 0;
for (int i = 0; i<imgNameArray.count; i++) {
NSString *imgName = imgNameArray[i];
UIImageView *imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:imgName]];
imageView.frame = CGRectMake(X, Y, 145, 109);
imageView.layer.cornerRadius = 2;
imageView.clipsToBounds = YES;
[imageView.layer setBorderWidth:2];
[imageView.layer setBorderColor:[[UIColor whiteColor]CGColor ]];
if ((i%2)==0) {
X = 154;
}else {
X = 0;
}
if ((i%2) ==0) {
Y = i * 59;
}
[containerView addSubview:imageView];
}
[self.scrollView addSubview: containerView];
self.scrollView.contentSize = CGSizeMake(320, imgNameArray.count * 67);
No matter how you've set up your view controller, the controller can always segue to another view controller using -performSegueWithIdentifier:sender:. So if you've set up your storyboard so that there's a segue with the identifier myDetailSegue leading from the image array view controller to the image detail view controller, the image array controller can do this:
[self performSegueWithIdentifier:#"myDetailSegue" sender:self];
So, one way to handle your task is to create an action in your image array controller:
-(IBAction)goToDetailController:(UIGestureRecognizer*)sender {
// get the image view from the gesture recognizer
UIImageView *tappedView = (UIImageView*)sender.view;
// save the image from the image view
self.detailImage = tappedView.image;
// start the detail segue
[self performSegueWithIdentifier:#"myDetailSegue" sender:self];
}
Now you just need to attach a gesture recognizer to each image view, setting it's target to the image array view controller and action to your new goToDetailController action. You'll also need a -prepareForSegue:sender: method just like you always do when using segues. That method can set the detail view controller's image to self.detailImage, since you wisely saved that in the action.
Add UITapGestureRecognizer to each of your UIImageview and define unique tag for each Imageview (as per your forloop).
In you gesture recognizer method, you can get tag by
[(UIGestureRecognizer *)sender view].tag
Use this tag to get perticular image from your array.
And performSegue.
You can use UICollectionView for show, the images. Each cell have a identifier (like indexPath from UITableview) so, for each cell that will touched you will take this value and reserve this like a ID for your images. Search the image connected for this ID and load in DetailViewController.
UICollectionView has a method that detects which cell has been touched.
You can share the imgNameArray variable using a Singleton. And using the same "ID" and send to DetailViewController, you can load the same image referenced.
This is one possible solution.
You can use UIButton like this below.
Set its BG image and put tag each button.
Then in its selector, check tag to determine which image to be passed.
UIButton *btn = [[UIButton alloc] initWithFrame:BUTTON_RECT];
[btn setBackgroundImage:YOUR_IMAGES forState:UIControlStateNormal];
[btn addTarget:self action:#selector(handlePushEvent:) forControlEvents:UIControlEventTouchUpInside];
[btn setTag:i]; // you can set your defined tag here plus int i in your loop
.
.
.
[self.scrollView addSubview:btn];
- (void) handlePushEvent:(UIButton *)sender
{
// PERFORM SEGUE HERE or YOU CAN ALSO PUSH THE VC
int btnTag = sender.tag;
for(int ctr=0; ctr<imgNameArray.count; ctr++)
{
if(ctr == btnTag) {
NextViewController *nextVC = [[NextViewController alloc] initWithNibName:nil bundle:nil];
nextVC.passedImage = imgNameArray[ctr]; // create a property in your next VC, then assign like this here
[self.navigationController pushViewController:nextVC animated:YES];
}
}
}

UnEven Behaviour of UIView when setHidden

I've created 5 UIView dynamically, which consists of one UILabel and one UIButton each. When I click button, the UIView will setHidden. But it works only on one not other four uiviews.
#interface ViewController : UIViewController
{
NSMutableArray *newViews;
}
#property(nonatomic,retain)IBOutlet UILabel *welcome;
#property(nonatomic,retain)CustomView *custom;
-(void)buttonPressed:(UIButton *)sender;
#end
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *name=#"string of length";
int length=[name length];
newViews = [NSMutableArray array];
NSMutableArray *myArray = [NSMutableArray arrayWithObjects:#"cricket", #"golf",#"wrestling", #"FootBall is good game", nil];
int yAxis=44;
int lengthOfArray=[myArray count];
for(int a=0; a<=lengthOfArray; a++){
self.custom= [[CustomView alloc]initWithFrame:CGRectMake(20, yAxis, 100, 44)];
yAxis=yAxis+50;
NSLog(#"yaxis is %i",yAxis);
self.custom.tag=200+a;
[newViews addObject:self.custom];
self.custom.Label = [[UILabel alloc]initWithFrame:CGRectMake(5,5, length+70, 30)];
self.custom.button=[[UIButton alloc]initWithFrame:CGRectMake(85,10,12,10)];
UIImage *btnImage = [UIImage imageNamed:#"button_droparrow.png"];
[self.custom.button setImage:btnImage forState:UIControlStateNormal];
[self.custom.button addTarget:self action:#selector(buttonPressed:)forControlEvents:UIControlEventTouchDown];
self.custom.button.tag=self.custom.button.tag+a;
self.custom.backgroundColor=[UIColor greenColor];
custom.Label.text=#"welcome";
custom.Label.backgroundColor = [UIColor yellowColor];
[self.custom addSubview:self.custom.button];
[self.custom addSubview:custom.Label];
[self.view addSubview:self.custom];
}
[self.custom.button addTarget:self action:#selector(buttonPressed:)forControlEvents:UIControlEventTouchDown];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
-(void)buttonPressed:(UIButton *)sender
{
[self.custom setHidden:YES];
}
#end
Kindly help me. I am new in iOS development. I need here to create UIView with differrnt reference and that reference assign to UIButton to close that particular UIView but I could not get result out.
You could use UISegmentedControl along with number of xib for each UIView.
In each UIView you can place the required UIControls and link the same.
In the delegate method of SegmentedControl 'indexDidChangeForSegmentedControl:(UISegmentedControl *)sender' on each index remove the earlier UIView and add the required UIView.
In the main header file add the IBOutlet for each UIView
#property (nonatomic, weak) IBOutlet UIView *view1;
#property (nonatomic, weak) IBOutlet UIView *view2;
In .m file in the delegate method 'indexDidChangeForSegmentedControl'
- (IBAction)indexDidChangeForSegmentedControl:(UISegmentedControl *)sender {
NSUInteger index = sender.selectedSegmentIndex;
if (UISegmentedControlNoSegment != index) {
if (currentIndex == index) {
return;
}
currentIndex = index;
switch (index) {
case 0:
{
[self.previousView removeFromSuperview];
[self.view addSubview:view1];
self.previousView = view1;
}
break;
case 1:
{
[self.previousView removeFromSuperview];
[self.view addSubview:view2];
self.previousView = view2;
}
break;
}
}
}
Hope this helps.
If you want to use properties, you will have to make a property for each view. Instead, if you want to create them dynamicaly you could store the references to each view in an array.
The next you should know/do is to add a tag to each button. A tag is just a number, which in this case should reference to its position in the Array.
Then based on the button tag (that you can retrieve from the sender) you can retrieve the proper view/button from the array and change the Hidden property on it.
For example (pseudo code/this wont compile):
Creating the views array
#property (nonatomic, strong) NSMutableArray *views;
In View did load create the views
views = [[NSMutableArray alloc] init];
int nrOfViews = 5;
for(int a=0; a<=nrOfViews; a++){
UIView *view = create UIView here.
UIButton *button = create button here.
[view addSubView: button];
[button setTag: a];
[views addObject: view];
}
reference to the view through the pointer retained in the array, find the right one based on the button tag.
-(void)buttonPressed:(UIButton *)sender
{
UIView *view = [views objectAtIndex: sender.tag]; //using the button tag to identify the right view.
[view setHidden: yes];
}
Try something like this:
- (void) buttonPressed: (UIButton*) sender
{
UIView* view = sender.superview;
view.hidden = YES;
}
You need to make some changes as follows
#property(nonatomic,strong)IBOutlet UILabel *welcome; // new arc code
#property(nonatomic,strong)UIView *custom; // new arc code
self.custom = [[UIView alloc]initWithFrame:CGRectMake(20, yAxis, 100, 44)];

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.

Pushing a view on storyboard for Page Control

I'm trying to implement a Page Control to show some pages with the following storyboard:
As you can see, I've the main view with a scroll view (ViewController3) and another view (PageViewController) that represents the one that I want to push on my scroll view.
On viewDidLoad of ViewController3 I call the following method:
- (void)loadScrollViewWithPage:(int)page
{
if (page < 0)
return;
if (page >= NUMBER_OF_PAGES)
return;
PageViewController *currentViewController = [viewControllers objectAtIndex:page];
if ((NSNull *)currentViewController == [NSNull null])
{
currentViewController = [[PageViewController alloc] init];
currentViewController.pageNumber = [NSString stringWithFormat:#"%d", page];
[viewControllers replaceObjectAtIndex:page withObject:currentViewController];
}
// add the controller's view to the scroll view
if (currentViewController.view.superview == nil)
{
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * page;
frame.origin.y = 0;
currentViewController.view.frame = frame;
currentViewController.view.backgroundColor = [UIColor yellowColor];
[self.scrollView addSubview:currentViewController.view];
self.scrollView.backgroundColor = [UIColor redColor];
NSDictionary *numberItem = [contentList objectAtIndex:page];
currentViewController.numberImage.image = [UIImage imageNamed:[numberItem valueForKey:IMAGE_KEY]];
currentViewController.numberTitle.text = [numberItem valueForKey:NAME_KEY];
}
}
If I run the project, views with yellow background are displayed with no labels, nor image views.
As you can see, I set this background color programmatically. From my understanding, this means that the new view is correctly added to ViewController3, but it is not linked to the one configured on the storyboard.
Do you have any suggestions on how to solve this issue?
Thanks in advance,
yassa
You have to instantiate PageViewController instance using [UIStoryboard instantiateViewControllerWithIdentifier:(NSString *)identifier].
http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIStoryboard_Class/Reference/Reference.html

Resources