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];
}
}
}
Related
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);
}
I'm having a bit of trouble updating my UIImageView to contain subviews of buttons after I'm getting the CGPoint data from another class.
In my main VC, I've got an ImageView set as a subview to a UIScrollView that is a subview of the main ViewControllers view.
In viewDidLoad, I'm calling a method from an NSObject class to get the data for all the button locations from my database:
- (void)parseCoordinateData:(NSArray*)data {
NSLog(#"Processing Data");
mapVC = [[ViewController alloc]init];
for(NSArray *table in data) {
NSLog(#"Table: %#", table);
float xValue = [[NSString stringWithFormat:#"%#", [table[0]objectForKey:#"LocationX"]] floatValue];
float yValue = [[NSString stringWithFormat:#"%#", [table[0]objectForKey:#"LocationY"]] floatValue];
NSLog(#"Coordinates: (%f,%f)", xValue, yValue);
CGPoint buttonCoordinate = CGPointMake(xValue, yValue);
[mapVC placeButtonsFromDatabaseWithCoordinates:buttonCoordinate];
}
}
And in the method from the main VC where I'm placing the buttons:
- (void)placeButtonsFromDatabaseWithCoordinates:(CGPoint)point {
NSLog(#"Placing Button at point: %#", NSStringFromCGPoint(point));
UIButton *button = [[UIButton alloc] init];
[self.imageView addSubview:button];
button.frame = (CGRect){.origin = point, .size = CGSizeMake(20.0, 20.0)};
button.backgroundColor = [UIColor greenColor];
button.layer.cornerRadius = 10;
button.clipsToBounds = YES;
button.userInteractionEnabled = YES;
[self animateButton:button];
[self.imageView bringSubviewToFront:button];
}
But the buttons are not appearing on the image view.
Any idea how to get this to work?
EDIT
I've created a very small project to try and replicate this problem. I've created a view controller that calls to an NSObject class that will call back to the View Controller to draw a subview. I am getting an EXC BAD ACCESS error when attempting this.
However, if handling the call explicitly in the main thread, the app will not crash but the view will not draw.
I think this is what's happening when trying to add the button to the image as a subview.
Change
UIButton *button = [[UIButton alloc] init];
to
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
I am trying to pass an integer value between UIViewControllers, new to iOS and having problems.
In the UIViewController where the value is being set, there are no problems. But after the value is set NSLog is showing that the value is null in the second UIViewController.
My app is going to use the horizontal slider to determine the length of time in between a UIImage animationDuration in a different UIViewController.
This method is correctly receiving the value from the horizontal slider. I initialized an instance of the "other" UIViewController, imageview.somedata belongs to the other view controller. I know the value is being passed correctly because of the NSLogs below.
- (IBAction) changeButtonPressed:(id)sender {
imageView = [[GTImageView alloc] initWithNibName:#"GTImageView" bundle:nil];
NSLog(#"text value = %#", myTextField);
NSString *textValue = [myTextField text];
int value = [textValue floatValue];
if (value < 0) value = 0;
if (value > 100) value = 100;
mySlider.value = value;
sliderValue = &value;
NSLog(#"sliderValue = %d", *(sliderValue));
myTextField.text = [NSString stringWithFormat:#"%.1d", value];
if ([myTextField canResignFirstResponder]) [myTextField resignFirstResponder];
imageView.someData = *(sliderValue);
NSLog(#"imageView.someData = %d", imageView.someData);
}
This is the top of that implementation file
#import "GTSettingsVC.h"
#import "GTImageView.h"
#import "GTImageView.m"
#interface GTSettingsVC ()
#end
#implementation GTSettingsVC
#synthesize mySlider, myTextField;
#synthesize sliderValue;
That header file
#import "GTImageView.h"
#interface GTSettingsVC : UIViewController
{
IBOutlet UISlider *mySlider;
IBOutlet UITextField *myTextField;
GTImageView *imageView;
int *sliderValue;
}
#property (nonatomic) int *sliderValue;
The header file of the view controller I am trying to send the data to
#import <UIKit/UIKit.h>
#interface GTImageView : UIViewController
{
UIScrollView* scrollView;
UIPageControl* pageControl;
int *someData;
}
#property (nonatomic) int *someData;
The implementation file where I want the variable someData to have the value I gave it in the first controller. NSLog is returning null in this implementation.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
UIImageView *animatedImageView =
[[UIImageView alloc] i nitWithFrame:CGRectMake(0, 55, 400, 550)];
[self.view addSubview:animatedImageView];
animatedImageView.animationImages = [NSArray arrayWithObjects:
[UIImage imageNamed:#"IMG_0052.JPG"],
[UIImage imageNamed:#"IMG_0054.JPG"],
[UIImage imageNamed:#"IMG_0081.JPG"],
nil];
NSLog(#"some data = %#", someData);
// NSLog is returning null
int x = someData;
animatedImageView.animationDuration =
x * [animatedImageView.animationImages count];
[animatedImageView startAnimating];
[self.view addSubview: animatedImageView];
}
I believe you have yet to grasp the concept/idea for View Controller Life Cycle and also Model View Controller (MVC).
The GTImageView that you defined and initiated in changeButtonPressed for your First View Controller (GTSettingsVC) is a local object/instance for GTSettingsVC. If your view controller transition from GTSettingsVC to GTImageView, the data will not pass to there.
Since you are using UINavigationController, I believe you have Segue. The easiest way to pass data for UINavigationController is using prepareForSegue. You will have to prepare the data that you want to pass to the second view controller in this method before the transition to it.
You also make some mistake in GTImageView. someData is not an object, it should not have *. And also try not to use variable, use just the property in stead. It should be:-
#property (nonatomic) int someData;
In GTSettingsVC.M, add the following function:-
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
GTImageView * viewController = segue.destinationViewController;
viewController.someData = 99;
}
In GTImageView.H
#interface GTImageView : UIViewController
{
UIScrollView* scrollView;
UIPageControl* pageControl;
}
#property (nonatomic) int someData;
#end
In viewDidLoad in GTImageView.M
- (void)viewDidLoad
{
[super viewDidLoad];
UIImageView *animatedImageView =
[[UIImageView alloc] initWithFrame:CGRectMake(0,55, 400, 550)];
[self.view addSubview:animatedImageView];
animatedImageView.animationImages = [NSArray arrayWithObjects:
[UIImage imageNamed:#"IMG_0052.JPG"],
[UIImage imageNamed:#"IMG_0054.JPG"],
[UIImage imageNamed:#"IMG_0081.JPG"],
nil];
NSLog(#"some data = %d", self.someData);
int x = self.someData;
animatedImageView.animationDuration =
x * [animatedImageView.animationImages count];
[animatedImageView startAnimating];
[self.view addSubview: animatedImageView];
}
I added a sample project to Github for your reference:-
https://github.com/voyage11/PassingDataTest
There is no need to take int *. Replace it by int and assign the value directly rather than address.
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)];
If I create a UIImageView via Storyboard and add it as a #property into a ViewController.h, I can access that UIImageView from anywhere in the ViewController.m via [self UIImageView] or self.UIImageView.
But If I create the UIImageView programmatically from viewDidLoad as you see below, I seem to lose the ability to access it from outside viewDidLoad.
UIImageView *prevImgView = [[UIImageView alloc] init];
UIImageView *currImgView = [[UIImageView alloc] init];
UIImageView *nextImgView = [[UIImageView alloc] init];
NSArray *imageViews = [NSArray arrayWithObjects:prevImgView, currImgView, nextImgView, nil];
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
[self.view addSubview: scrollView];
CGRect cRect = scrollView.bounds;
UIImageView *cView;
for (int i=0; i<imageViews.count; i++) {
cView = [imageViews objectAtIndex:i];
cView.frame = cRect;
[scrollView addSubview:cView];
cRect.origin.x += cRect.size.width;
}
So later on if I want to modify the image that is being displayed in any one of the UIImageView I've created from viewDidLoad, I can't seem to access it. Does anyone know what I'm doing wrong?
You would need to create your UIImageView in your header file and then it would be available throughout the rest of the view. You will need to add it to the view in viewDidLoad though.
Header
UIImageView *image;
Main // ViewDidLoad
image = [UIImageView alloc] .....
[self.view addSubView image];
Main Function .....
[image setImage ....
The answer AgnosticDev is trying to say here is to add an ivar to your view controller's .h file... e.g.:
#implementation YHLViewController : ViewController
{
UIImageView * currImageView;
}
And then in your "viewDidLoad" method, you can allocate and initialize it via:
currImageView = [[UIImageView alloc] init];
and have access to it from anywhere else in your view controller.