Why does NSArray of UIImageViews follow a certain pattern? - ios

I have an array of 4 UIImageViews A, A2, A3 and A4. I want them to be dragged on to another imageView called answerA. Every time I drag one of them on the answer it should change the image on answerA to a number which tells how many were dragged on it. E.g. If i drag A on answerA then answerA image will change to number 1. If i drag one more A from the array then it will change to number 2. For some reason my array follows a strange pattern. The first one i drag changes to number 1, the second one does nothing, the third one will change to number 2 and the fourth will change it back to number 1. No matter in which order i drag them it will always be in same pattern.
This is my array of 4 imageViews
#property (strong, nonatomic) NSArray *letterA; //initialized in .h
self.letterA = #[A, A2, A3, A4];//initialized in .m
My method to check collision:
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
int intersectionCount = 0;
for (UIImageView *letter in letterA) {
if (CGRectIntersectsRect(letter.frame ,answerA.frame)) {
letter.userInteractionEnabled = NO;
letter.hidden = YES;
intersectionCount++;
}
}
if (intersectionCount == 1) {
UIImage *Pic1 = [UIImage imageNamed:#"number1.png"];
[correctCounterA setImage:Pic1];
}
else if (intersectionCount == 2) {
UIImage *Pic2 = [UIImage imageNamed:#"number2.png"];
[correctCounterA setImage:Pic2];
}
else if (intersectionCount == 3) {
UIImage *Pic3 = [UIImage imageNamed:#"number3.png"];
[correctCounterA setImage:Pic3];
}
else if (intersectionCount == 4) {
UIImage *Pic4 = [UIImage imageNamed:#"number4.png"];
[correctCounterA setImage:Pic4];
}
NOTE: correctCounterA is a small imageView on top of answerA so that only that small section would change the image to numbers.

You need to modified touchesEnded as like below. here you are finding drag image in wrong way. may this help you.
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UIImageView *letter in letterA) {
if (CGRectIntersectsRect(letter.frame ,answerA.frame)) {
letter.userInteractionEnabled = NO;
letter.hidden = YES;
intersectionCount++;
break;
}
}
if (intersectionCount == 1) {
UIImage *Pic1 = [UIImage imageNamed:#"number1.png"];
[correctCounterA setImage:Pic1];
}
else if (intersectionCount == 2) {
UIImage *Pic2 = [UIImage imageNamed:#"number2.png"];
[correctCounterA setImage:Pic2];
}
else if (intersectionCount == 3) {
UIImage *Pic3 = [UIImage imageNamed:#"number3.png"];
[correctCounterA setImage:Pic3];
}
else if (intersectionCount == 4) {
UIImage *Pic4 = [UIImage imageNamed:#"number4.png"];
[correctCounterA setImage:Pic4];
}
}
Edit : According to your requirement, you need to declare intersectionCount in .h file and in viewDidLoad, you need to assign as below.
int intersectionCount = 0;
and Change touchesEnded like as above.

Related

iOS how can I make undo action for rotating, scaling and adding UIView to UIIMageView

I have a UIImageView and I can add new items (as a subview) to this UIImageView or I can move & rotate the items in UIImageView.
I'm try to make undo actions for this items, so my code;
Before each new actions I get the copy of UIImageView and store them in NSMutableArray
[self.lastActions addObject:[self getCopy]];
I get the same UIImageView with different memory address. (I'm not sure this is the right approach)
-(UIImageView *)getCopy{
NSData *archivedViewData = [NSKeyedArchiver archivedDataWithRootObject:self.imageView];
id clone = [NSKeyedUnarchiver unarchiveObjectWithData:archivedViewData];
return clone;
}
And when I make the undo;
-(IBAction)undoButtonClicked:(id)sender{
UIImageView *lastImageView = [self.lastActions lastObject];
[UIView animateWithDuration:0.1 animations:^{
self.imageView = lastImageView;
}];
[self.lastActions removeObject:lastImageView];
}
But it does not change the UIImageView on screen.
Any ideas for whats wrong on my code ?
I am try your above idea. Not able to get the output. this is another idea to achieve the same.
I am using image to reveal the image change on the same imageview "undo" operation. I have implemented like below method.
its working fine in my side.
I hope this will help us.
// Undo button action
-(IBAction)undoButtonClicked:(id)sender{
UIImage *lastImageView = lastImageView = (UIImage *)[lastActions lastObject];
if( [lastActions count]!=0) {
[UIView animateWithDuration:0.2 animations:^{
self.imageView.image = lastImageView;
}];
[lastActions removeObject:lastImageView];
}
}
// Copy the image from public variable self.imageview
-(IBAction)copyButton:(id)sender{
[lastActions addObject:self.imageView.image];
}
// Random Orientation change to rotate the image.
-(UIImageOrientation )randonImageOrientation {
int min = 0 ;
int max = 3;
UIImageOrientation ori;
int randomNumber = min + rand() % (max-min);
switch (randomNumber)
{
case 0 :
ori = UIImageOrientationDown;
break;
case 1:
ori = UIImageOrientationLeft;
break;
case 2:
ori = UIImageOrientationRight;
break;
case 3:
ori = UIImageOrientationUp;
break;
default :
ori = UIImageOrientationUp;
break;
}
return ori;
}
// below method using to rotate the image
-(UIImage *)imageOrientation :(UIImageOrientation)imageOri image:(UIImage *)oriImage {
UIImage * LandscapeImage = oriImage;
UIImage * PortraitImage = [[UIImage alloc] initWithCGImage: LandscapeImage.CGImage
scale: 0.5
orientation: imageOri];
return PortraitImage;
}

Background Image setup issue (GHWalkThrough library on github)

this is a walkthrough open library on github that I want to use in my app.
https://github.com/GnosisHub/GHWalkThrough
there is a method to set up bg view:
- (UIImage*) bgImageforPage:(NSInteger)index
{
UIImage* image = [UIImage imageNamed:#"bgimage"];
return image;
}
And I wanted to add set different image for each index, so i did this:
- (UIImage*) bgImageforPage:(NSInteger)index {
UIImage* image;
if (index == 0) {
image = [UIImage imageNamed:#"screen 1"];
} else if (index == 1) {
image = [UIImage imageNamed:#"screen 2"];
} else if (index == 2) {
image = [UIImage imageNamed:#"screen 3"];
} else if (index == 3) {
image = [UIImage imageNamed:#"screen 4"];
}
return image;
}
Result:
whenever the view is loaded there is a clear bg, and if I swipe left to index 1 I get screen 1 > and if I swipe left for index 2, 3 & 4 the bg stays screen 1...
Can someone see what is wrong here?
i think you have minor mistak from code.
- (UIImage*) bgImageforPage:(NSInteger)index
{
NSString* imageName =[NSString stringWithFormat:#"bg_0%ld.jpg", index+1]; // you have manually add name but not increment index
UIImage* image = [UIImage imageNamed:imageName];
return image;
}
if you can't use bottom code & use upper code you got your result or same as use bottom code & use upper code then also you got same result.
- (UIImage*) bgImageforPage:(NSInteger)index
{
NSString* imageName =[NSString stringWithFormat:#"bg_0%ld.jpg", index+1];
UIImage* image;// = [UIImage imageNamed:imageName];
if (index == 0) {
image = [UIImage imageNamed:imageName];
} else if (index == 1) {
image = [UIImage imageNamed:imageName];
} else if (index == 2) {
image = [UIImage imageNamed:imageName];
} else if (index == 3) {
image = [UIImage imageNamed:imageName];
}
return image;
}
Please add image name in your app image folder like below.
(Note: your image name set below as in your project.)
Example Image Name :-
your condition wise you got new index but not getting images but when you set images name like same as upper images name & you got your images as index wise.
You don't seem to update index, which means it stays at 0.
If it stays at 0, the image will always be "screen 1".

How to access a random element from IBOutletCollection array

I need to access a random element from IBOutletCollection array. I have 4 letter imageViews that needs to be dragged on to another imageView and change the image depending on how many were dragged. Im testing with 2 at the moment. I have this but it doesn't seem to take random but a particular one of the 4.
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UIImageView *letter in letterA)
{
for (UIImageView *letter1 in letterA)
{
if (CGRectIntersectsRect(letter.frame ,answerA.frame))
{
UIImage *Pic1 = [UIImage imageNamed:#"number1"];
[correctCounterA setImage:Pic1];
letter.userInteractionEnabled=NO;
letter.hidden=YES;
}
else if (CGRectIntersectsRect(letter1.frame, answerA.frame)) //CGRectIntersectsRect(letter.frame, answerA.frame))
{
UIImage *Pic2 = [UIImage imageNamed:#"number2"];
[correctCounterA setImage:Pic2];
}
}
}
}

How to recognize particular image is animating during imageview animation?

I am creating a timer which is used to play a song for 6 seconds.But i want that whenever i clicked the button it will recognized the particular image which is animating at that particular instant.For that i used CALayer but it is not giving the image name.
This is my code:
-(void)playSong
{
timerButton.imageView.animationImages =[NSArray arrayWithObjects:[UIImage imageNamed:#"Timer6.png"],[UIImage imageNamed:#"Timer5.png"],
[UIImage imageNamed:#"Timer4.png"],[UIImage imageNamed:#"Timer3.png"],
[UIImage imageNamed:#"Timer2.png"],[UIImage imageNamed:#"Timer1.png"],
nil];
timerButton.imageView.animationDuration=6.0;
[self.player play];
[timerButton.imageView startAnimating];
}
- (void)handleLongPressGestures:(UILongPressGestureRecognizer *)sender
{
if (sender.state == UIGestureRecognizerStateBegan)
{
CALayer *player1 = timerButton.imageView.layer;
}
}
Please help me.
Unfortunately, you cannot get the image name from a UIImageView or UIImage object.
You could, however, set an accessibility identifier to a UIImage object that, in your case, could be it's file name.
Then simply doing someUIImageObject.accessibilityIdentifier should return the file name.
(refer answer)
Example:
UIImage *image = [UIImage imageNamed:#"someImage.png"];
[image setAccessibilityIdentifier:#"someImage"];
NSLog(#"%#",image.accessibilityIdentifier);
Now... you'd expect timerButton.imageView.image.accessibilityIdentifier to give you the image name but that's not how it works when the UIImageView is animating.
This time, we need to access it via the UIImageViews animationImages array property.
For this, we will need some custom logic to get the UIImage object from this animationImages array.
We'll first record the time we started animating the images and with some basic maths, we can calculate the index of the animationImages array that is currently being displayed in the UIImageView.
(refer answer)
Answer (code):
-(void)playSong
{
NSMutableArray *arrImages = [[NSMutableArray alloc] init];
for(int i = 6 ; i > 0 ; i--) {
//Generate image file names: "Timer6.png", "Timer5.png", ..., "Timer1.png"
NSString *strImageName = [NSString stringWithFormat:#"Timer%d.png",i];
//create image object
UIImage *image = [UIImage imageNamed:strImageName];
//remember image object's filename
[image setAccessibilityIdentifier:strImageName];
[arrImages addObject:image];
}
[timerButton.imageView setAnimationImages:arrImages];
[timerButton.imageView setAnimationDuration:6.0f];
[timerButton.imageView setAnimationRepeatCount:0];
[self.player play];
[timerButton.imageView startAnimating];
//record start time
startDate = [NSDate date]; //declare "NSDate *startDate;" globally
}
- (void)handleLongPressGestures:(UILongPressGestureRecognizer *)sender
{
if (sender.state == UIGestureRecognizerStateBegan) {
[self checkCurrentImage];
}
}
-(void)checkCurrentImage
{
//logic to determine which image is being displayed from the animationImages array
NSTimeInterval durationElapsed = -1 * [startDate timeIntervalSinceNow];
NSTimeInterval durationPerFrame = timerButton.imageView.animationDuration / timerButton.imageView.animationImages.count;
int currentIndex = (int)(durationElapsed / durationPerFrame) % timerButton.imageView.animationImages.count;
UIImage *imageCurrent = timerButton.imageView.animationImages[currentIndex];
NSString *strCurrentImage = imageCurrent.accessibilityIdentifier;
NSLog(#"%#",strCurrentImage);
}

iOS - drawRect in UIView : Suggestions to smoothen animation

The following is my code, it's working properly, it's just that the "animation" of a moving line in the line if (guidelineOn) is not smooth. The drawRect is being called every 0.01 seconds.
if (guideLineOn)
{
[self drawGuidanceLineAtPoint:CGPointMake((65+guideLineOffset)*scalingF, 98*scalingF) withAlpha:paramAlpha];
}
It's kind of laggy and sometimes interferes with the user input. How do I resolve this? New to this so open to suggestions.
Thanks in advance for your help.
Pier.
- (void)drawRect:(CGRect)rect
{
scalingF = 1.0; // default : iPhone
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
scalingF = IPAD_SCALING_FACTOR;
}
if (guideLineOn)
{
[self drawGuidanceLineAtPoint:CGPointMake((65+guideLineOffset)*scalingF, 98*scalingF) withAlpha:paramAlpha];
}
// draw staff line
[self drawStaffLineFrom:CGPointMake(65*scalingF, 98*scalingF) toPoint:CGPointMake(420*scalingF, 98*scalingF)];
[self drawStaffLineFrom:CGPointMake(420*scalingF,108*scalingF) toPoint:CGPointMake(420*scalingF, 50*scalingF)];
[self drawStaffLineFrom:CGPointMake(415*scalingF,108*scalingF) toPoint:CGPointMake(415*scalingF, 50*scalingF)];
// cycle through all the static images to draw tbd
float offSet = 0.0;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
offSet += 50.0; // to adjust the metronome down
}
if (metronomeImage)
{
[metronomeImage drawInRect:CGRectMake(410.0f*scalingF, 195.0f*scalingF+offSet, metronomeImage.size.width*scalingF, metronomeImage.size.height*scalingF)];
}
if (circlesImage)
{
[circlesImage drawInRect:CGRectMake(400.0f*scalingF, 255.0f*scalingF+offSet, circlesImage.size.width*scalingF, circlesImage.size.height*scalingF)];
}
for (Note * v in notesArray)
{
UIImage * noteImage = [UIImage imageNamed: v.imageName];
[noteImage drawInRect:CGRectMake(v.notePlacement.x*scalingF, v.notePlacement.y*scalingF, noteImage.size.width*scalingF, noteImage.size.height*scalingF)];
}
if (!clearDisplay)
{
// draw the arrows
for (int i=0; i < arrowsToDrawArray.count; i++)
{
Arrow * arrowObj = [arrowsToDrawArray objectAtIndex:i];
UIColor * colourOfArrow = [arrowObj colourOfArrow]; // colour determines whether right or wrong
CGPoint p = [arrowObj arrowPlacement];
p.x = p.x*scalingF;
p.y = p.y*scalingF;
// CGPoint p = [val CGPointValue];
[self drawRooftopAtTopPointof:p colour:colourOfArrow lineJoin:kCGLineJoinMiter];
}
// draw the ties
for (int j=0; j < tiePointsArray.count; j++)
{
CGPointPair * tiePairToDraw = [tiePointsArray objectAtIndex:j];
CGPoint firstPt = [tiePairToDraw firstPoint];
firstPt.x = firstPt.x *scalingF;
firstPt.y = firstPt.y *scalingF;
CGPoint secondPt = [tiePairToDraw secondPoint];
secondPt.x = secondPt.x *scalingF;
secondPt.y = secondPt.y *scalingF;
[self drawPseudoCurveFromPoint:firstPt toPoint:secondPt];
}
// bool perfect = true;
// int noOfNotesHit = 0;
// draw the tick/cross/arrow
for (int k=0; k < answerObjArray.count; k++)
{
Answer * ansObj = [answerObjArray objectAtIndex:k];
if (ansObj.hit)
{
// noOfNotesHit++;
if (ansObj.earlyOrLate == -1) // early, draw right pointing arrow
{
UIImage * arrowImage = [UIImage imageNamed: #"arrowright.png"];
[arrowImage drawInRect:CGRectMake((ansObj.xPosition-(0.5*arrowImage.size.width))*scalingF, 125*scalingF, arrowImage.size.width*scalingF, arrowImage.size.height*scalingF)];
// perfect = false;
}
else if (ansObj.earlyOrLate == 1) // late, draw left pointing arrow
{
UIImage * arrowImage = [UIImage imageNamed: #"arrowleft.png"];
[arrowImage drawInRect:CGRectMake((ansObj.xPosition-(0.5*arrowImage.size.width))*scalingF, 125*scalingF, arrowImage.size.width*scalingF, arrowImage.size.height*scalingF)];
//perfect = false;
}
else // perfect!
{
// draw a tick
UIImage * tickImage = [UIImage imageNamed: #"tick.png"];
[tickImage drawInRect:CGRectMake((ansObj.xPosition-(0.5*tickImage.size.width))*scalingF, 125*scalingF, tickImage.size.width*scalingF, tickImage.size.height*scalingF)];
}
}
else
{
// draw a cross
UIImage * crossImage = [UIImage imageNamed: #"cross.png"];
[crossImage drawInRect:CGRectMake((ansObj.xPosition-(0.5*crossImage.size.width))*scalingF, 125*scalingF, crossImage.size.width*scalingF, crossImage.size.height*scalingF)];
//perfect = false;
}
}
}
else
{
// draw nothing
clearDisplay = false;
}
}
Here's my Core Animation solution for those interested.
- (void) animateRedLine: (float) alphaParam
{
[self.view addSubview:self.redlineImageView];
/* Start from top left corner */
[self.redlineImageView setFrame:CGRectMake(65.0f*scalingF,
50.0f*scalingF,
self.redlineImageView.image.size.width*scalingF,
self.redlineImageView.image.size.height*scalingF*2)];
[self.redlineImageView setAlpha:alphaParam];
[UIView beginAnimations:#"redLineAnimation"
context:( void *)self.redlineImageView];
/* 3 seconds animation */
[UIView setAnimationDuration:noOfBeatsInBar*timeInSecondsForOneBeat];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
/* Receive animation delegates */
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:
#selector(imageViewDidStop:finished:context:)];
/* End at the bottom right corner */
[self.redlineImageView setFrame:CGRectMake((65.0f+LENGTH_OF_BAR)*scalingF,
50.0f*scalingF,
self.redlineImageView.image.size.width*scalingF,
self.redlineImageView.image.size.height*scalingF*2)];
//[self.redlineImageView setAlpha:0.0f];
[UIView commitAnimations];
}

Resources