I want to implement the functionality of pan gesture to a imageview, this imageview is a subview of a scroll view. the problem is when i try to scroll the scrollview the pan gesture of the imageview gets recognized, and the scrollview does not scroll.
please help me with this.
this is the code for initializing the pan to the uiimageview:
UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(move:)];
[panRecognizer setMinimumNumberOfTouches:1];
[panRecognizer setMaximumNumberOfTouches:1];
[panRecognizer setDelegate:self];
[[[scrollView subviews] objectAtIndex:i] addGestureRecognizer:panRecognizer];
the imageview has the user set to "YES"
and the action for it
-(void)move:(UIPanGestureRecognizer *)sender
{
[[[[[sender view] superview] superview] superview] bringSubviewToFront:sender.view];
if([(UIPanGestureRecognizer*)sender state] == UIGestureRecognizerStateBegan) {
if ([[[sender view] superview] superview] == itemView) // adds the imageview in the item scroll
{
int tag = [[sender view] tag] / 100;
UIScrollView *tempScroll = (UIScrollView *)[itemView viewWithTag:-tag];
CGRect frame = CGRectFromString([itemFrameDict objectForKey:[NSString stringWithFormat:#"%i",[[sender view] tag]]]);
CGAffineTransform transform = temp.transform;
UIImageView *tempImageView = [[UIImageView alloc] initWithImage: [(UIImageView *) [sender view] image]];
tempImageView.tag = [[sender view] tag];
//NSLog(#"[sender view] superview] : %#", [[sender view] superview]);
tempImageView.frame = frame;
[tempImageView setTransform:transform];
[tempImageView setFrame:frame];
[tempImageView setUserInteractionEnabled:YES];
[tempScroll addSubview:tempImageView];
UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(move:)];
[panRecognizer setMinimumNumberOfTouches:1];
[panRecognizer setMaximumNumberOfTouches:1];
[panRecognizer setDelegate:self];
[tempImageView addGestureRecognizer:panRecognizer];
UITapGestureRecognizer *singleTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
[singleTapGestureRecognizer setNumberOfTapsRequired:1];
[tempImageView addGestureRecognizer:singleTapGestureRecognizer];
}
}
if([(UIPanGestureRecognizer*)sender state] == UIGestureRecognizerStateChanged)
{
CGPoint translatedPoint = [sender locationInView:[[sender view] superview]] ;
newTranslatedPoint = [[[sender view] superview] convertPoint:translatedPoint toView:self.view];
if ([sender view].frame.size.width == 35 && [sender view].frame.size.height == 35)
[[sender view] sizeToFit];
[sender view].center = CGPointMake(newTranslatedPoint.x, newTranslatedPoint.y); //startFrame;
[self.view addSubview:[sender view]];
}
if([(UIPanGestureRecognizer*)sender state] == UIGestureRecognizerStateEnded)
{
CGPoint newPoint = [[[sender view] superview] convertPoint:newTranslatedPoint toView:itemView];
if (newPoint.y < 0)// || !viewUp)
{
//NSLog(#" baseView");
[baseView addSubview:[sender view]];
UITapGestureRecognizer *doubleTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleDoubleTap:)];
[doubleTapGestureRecognizer setNumberOfTapsRequired:2];
[[sender view] addGestureRecognizer:doubleTapGestureRecognizer];
UIPinchGestureRecognizer *pinchRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(scale:)];
[pinchRecognizer setDelegate:self];
[[sender view] addGestureRecognizer:pinchRecognizer];
UIRotationGestureRecognizer *rotationRecognizer = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:#selector(rotate:)];
[rotationRecognizer setDelegate:self];
[[sender view] addGestureRecognizer:rotationRecognizer];
}
else if (newPoint.y > 0)// && viewUp )
{
//NSLog(#" itemView");
int tag = [[sender view] tag] / 100;
UIScrollView *tempScroll = (UIScrollView *)[itemView viewWithTag:-tag];
CGRect frame = CGRectFromString([itemFrameDict objectForKey:[NSString stringWithFormat:#"%i",[[sender view] tag]]]);
CGAffineTransform transform = temp.transform;
[[sender view] setTransform:transform];
[[sender view] setFrame:frame];
[tempScroll addSubview:[sender view]];
}
}
}
I'm not sure I understand what you're trying to achieve exactly by using a UIPanGestureRecognizer on a UIImageView that is already in a UIScrollView. But from your description, it sounds like you want the UIScrollView to do it's thing and for the UIPanGestureRecognizer to not block that. I believe you need to implement this delegate method for your UIPanGestureRecognizer:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
Please read the UIGestureRecognizerDelegate Protocol reference in regards to allowing simultaneous gesture recognition. According to the documentation:
The default implementation returns NO—no two gestures can be
recognized simultaneously.
/* EDIT */
From UIPanGestureRecognizer - Only vertical or horizontal:
Implement just one direction for a UIPanGestureRecognizer. This is for a vertical pan:
- (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)panGestureRecognizer {
CGPoint translation = [panGestureRecognizer translationInView:someView];
return fabs(translation.y) > fabs(translation.x);
}
Related
I am trying to make a preferences view with lots of text. I cannot figure out why the text is blurry when i run the project, even though the interface builder is very sharp and clear. Here is a picture. [1]: http://i.stack.imgur.com/EQl6D.png
here is the code for the views:
#implementation SKMainWindowController
-(NSRect)newFrameForNewContentView:(NSView*)view {
NSWindow *window = [self window];
NSRect newFrameRect = [window frameRectForContentRect:[view frame]];
NSRect oldFrameRect = [window frame];
NSSize newSize = newFrameRect.size;
NSSize oldSize = oldFrameRect.size;
NSRect frame = [window frame];
frame.size = newSize;
frame.origin.y -= (newSize.height - oldSize.height);
return frame;
}
-(NSView *)viewForTag:(int)tag {
NSView *view = nil;
switch (tag) {
case 0: default:
view = welcome;
break;
case 1:
view = status;
break;
case 2:
view = power;
break;
case 3:
view = preferences;
break;
case 4:
view = about;
break;
}
return view;
}
- (BOOL)validateToolbarItem:(NSToolbarItem *)item {
if ([item tag] == currentViewTag) return NO;
else return YES;
}
-(void)awakeFromNib {
[[self window] setContentSize:[welcome frame].size];
[[[self window] contentView] addSubview:welcome];
[[[self window] contentView] setWantsLayer:NO];
}
-(IBAction)switchWelcome:(id)sender {
int tag = [sender tag];
NSView *view = [self viewForTag:tag];
NSView *previousView = [self viewForTag:currentViewTag];
currentViewTag = tag;
NSRect newFrame = [self newFrameForNewContentView:view];
[NSAnimationContext beginGrouping];
if ([[NSApp currentEvent] modifierFlags] & NSShiftKeyMask)
[[NSAnimationContext currentContext] setDuration:1.0];
[[[[self window] contentView] animator] replaceSubview:previousView with:view];
[[[self window] animator] setFrame:newFrame display:YES];
[NSAnimationContext endGrouping];
[welcomeButton setState:NSOnState];
[statsButton setState:NSOffState];
[powerButton setState:NSOffState];
}
I've tried changing the text fields into code by doing things like [textField setStringValue:#""];, but with no luck it is still blurry. Thanks for any help. PS: This is for cocoa, not iOS.
Found the answer, ended up being the stupid visual effect view not cooperating. Simple fix was to set the visual effect view to within the window, and set as inactive. (although there is now no point in having a visual effect view.)
I have 3 images in my array for this sample code it just animate without any style .I want to animate like fade in fade out style.
NSArray *imarray = [[NSArray alloc] initWithObjects:
[UIImage imageWithContentsOfFile:[NSString stringWithFormat:#"%#/lady1_open.png", path]],
[UIImage imageWithContentsOfFile:[NSString stringWithFormat:#"%#/lady1_open2.png", path]],
[UIImage imageWithContentsOfFile:[NSString stringWithFormat:#"%#/lady1_open3.png", path]],
nil];
bingo_girl.animationImages=imarray;
bingo_girl.animationDuration=5;
bingo_girl.animationRepeatCount=0;
[bingo_girl.layer addAnimation:transition forKey:nil];
[bingo_girl startAnimating];
You may animate images with transition manually for example using this category
#implementation UIImageView (AnimateTransition)
- (void) assignImage:(UIImage *)image withTransition:(NSString *)withTransition withDirection:(NSString *)withDirection{
if(image == nil)
{
[self setImage:nil];
return;
}
if ([UIImagePNGRepresentation(self.image) isEqualToData:UIImagePNGRepresentation(image)]) {
return;
}
CATransition *animation = [CATransition animation];
animation.duration = 0.2;
animation.type = withDirection;
animation.subtype = withDirection;
[[self layer] addAnimation:animation forKey:#"imageFade"];
[self setImage:image];
}
#end
I must be doing something wrong here:
My Cocoa app has a scrollview around a custom view which in turn has a textview. I only expect to see one "This is a " string but there the extra one up in the corner.
I have reduced the code to something very minimal and still do not understand what my error is, so here I am fishing for a clue.
The view controller for the custom view follows, but for simplicity here is a link to the project.
#import "TTTSimpleCtrlView.h"
#interface TTTSimpleCtrlView ()
#property (strong,nonatomic) NSTextView *tv1;
#property (strong,nonatomic) NSTextStorage *ts;
#end
#implementation TTTSimpleCtrlView
- (void) awakeFromNib {
NSFont *font = [NSFont fontWithName:#"Courier New Bold" size:20.0f];
NSMutableParagraphStyle *styleModel = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
[styleModel setLineHeightMultiple:1.0];
// [styleModel setLineSpacing:fontRect.size.height * 2];
NSDictionary *textAttrs = [NSDictionary dictionaryWithObjectsAndKeys: font, NSFontAttributeName,
[NSColor blackColor] ,NSForegroundColorAttributeName,
[NSColor whiteColor], NSBackgroundColorAttributeName,
styleModel, NSParagraphStyleAttributeName,
nil];
NSString *pilcrowStr = #"This is a test.";
NSAttributedString *s = [[NSAttributedString alloc] initWithString:pilcrowStr attributes:textAttrs];
NSRect rect = [s boundingRectWithSize:NSMakeSize(INFINITY,INFINITY)options:0];
NSLayoutManager *lm = [[NSLayoutManager alloc] init];
NSTextContainer *tc = [NSTextContainer new];
[tc setContainerSize:s.size];
[lm addTextContainer:tc];
_ts = [[NSTextStorage alloc] init];
[_ts setAttributedString:s];
[_ts addLayoutManager:lm];
[lm replaceTextStorage:_ts];
rect.origin.x = 10;
rect.origin.y = rect.size.height;
NSTextView *v = [[NSTextView alloc] initWithFrame:rect textContainer:tc];
[v setDrawsBackground:YES];
[self addSubview:v];
}
- (BOOL) isFlipped {
return YES;
}
- (void)drawRect:(NSRect)rect
{
NSLog(#"drawRect & %lu subviews",self.subviews.count);
for (NSTextView *v in self.subviews) {
if(CGRectIntersectsRect(v.frame, rect) || CGRectContainsRect(rect, v.frame)) {
[v drawRect:rect];
NSLog(#"frame = %#",NSStringFromRect(v.frame));
}
}
[super drawRect:rect];
}
You are calling:
[super drawRect:rect];
and you are drawing the text yourself in your draw function.
In effect you are drawing the text and cocoa is drawing the text for you as well.
So don't call super.
I'm working at a custom Window object that is displayed as child in a parent Window.
For this object I'd like to create an animation like that of an NSPopover.
My first idea is to create a Screenshot of the child Window, than animate it using Core Animation and finally showing the real Window.
Before begging the implementation I would like to know if exists a better method and what you think about my solution.
It's not trivial. Here's how I do it:
#interface ZoomWindow : NSWindow
{
CGFloat animationTimeMultiplier;
}
#property (nonatomic, readwrite, assign) CGFloat animationTimeMultiplier;
#end
#implementation ZoomWindow
#synthesize animationTimeMultiplier;
- (NSTimeInterval)animationResizeTime: (NSRect)newWindowFrame
{
float multiplier = animationTimeMultiplier;
if (([[NSApp currentEvent] modifierFlags] & NSShiftKeyMask) != 0) {
multiplier *= 10;
}
return [super animationResizeTime: newWindowFrame] * multiplier;
}
#end
#implementation NSWindow (PecuniaAdditions)
- (ZoomWindow*)createZoomWindowWithRect: (NSRect)rect
{
// Code mostly from http://www.noodlesoft.com/blog/2007/06/30/animation-in-the-time-of-tiger-part-1/
// Copyright 2007 Noodlesoft, L.L.C.. All rights reserved.
// The code is provided under the MIT license.
// The code has been extended to support layer-backed views. However, only the top view is
// considered here. The code might not produce the desired output if only a subview has its layer
// set. So better set it on the top view (which should cover most cases).
NSImageView *imageView;
NSImage *image;
NSRect frame;
BOOL isOneShot;
frame = [self frame];
isOneShot = [self isOneShot];
if (isOneShot) {
[self setOneShot: NO];
}
BOOL hasLayer = [[self contentView] wantsLayer];
if ([self windowNumber] <= 0) // <= 0 if hidden
{
// We need to temporarily switch off the backing layer of the content view or we get
// context errors on the second or following runs of this code.
[[self contentView] setWantsLayer: NO];
// Force window device. Kinda crufty but I don't see a visible flash
// when doing this. May be a timing thing wrt the vertical refresh.
[self orderBack: self];
[self orderOut: self];
[[self contentView] setWantsLayer: hasLayer];
}
// Capture the window into an off-screen bitmap.
image = [[NSImage alloc] initWithSize: frame.size];
[[self contentView] lockFocus];
NSBitmapImageRep* rep = [[NSBitmapImageRep alloc] initWithFocusedViewRect: NSMakeRect(0.0, 0.0, frame.size.width, frame.size.height)];
[[self contentView] unlockFocus];
[image addRepresentation: rep];
// If the content view is layer-backed the above initWithFocusedViewRect call won't get the content
// of the view (seems it doesn't work for CALayers). So we need a second call that captures the
// CALayer content and copies it over the captured image (compositing so the window frame and its content).
if (hasLayer)
{
NSRect contentFrame = [[self contentView] bounds];
int bitmapBytesPerRow = 4 * contentFrame.size.width;
CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
CGContextRef context = CGBitmapContextCreate (NULL,
contentFrame.size.width,
contentFrame.size.height,
8,
bitmapBytesPerRow,
colorSpace,
kCGImageAlphaPremultipliedLast);
CGColorSpaceRelease(colorSpace);
[[[self contentView] layer] renderInContext: context];
CGImageRef img = CGBitmapContextCreateImage(context);
CFRelease(context);
NSImage *subImage = [[NSImage alloc] initWithCGImage: img size: contentFrame.size];
CFRelease(img);
[image lockFocus];
[subImage drawAtPoint: NSMakePoint(0, 0)
fromRect: NSMakeRect(0, 0, contentFrame.size.width, contentFrame.size.height)
operation: NSCompositeCopy
fraction: 1];
[image unlockFocus];
}
ZoomWindow *zoomWindow = [[ZoomWindow alloc] initWithContentRect: rect
styleMask: NSBorderlessWindowMask
backing: NSBackingStoreBuffered
defer: NO];
zoomWindow.animationTimeMultiplier = 0.3;
[zoomWindow setBackgroundColor: [NSColor colorWithDeviceWhite: 0.0 alpha: 0.0]];
[zoomWindow setHasShadow: [self hasShadow]];
[zoomWindow setLevel: [self level]];
[zoomWindow setOpaque: NO];
[zoomWindow setReleasedWhenClosed: NO];
[zoomWindow useOptimizedDrawing: YES];
imageView = [[NSImageView alloc] initWithFrame: [zoomWindow contentRectForFrameRect: frame]];
[imageView setImage: image];
[imageView setImageFrameStyle: NSImageFrameNone];
[imageView setImageScaling: NSScaleToFit];
[imageView setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
[zoomWindow setContentView: imageView];
[self setOneShot: isOneShot];
return zoomWindow;
}
- (void)fadeIn
{
[self setAlphaValue: 0.f];
[self orderFront: nil];
[NSAnimationContext beginGrouping];
[[NSAnimationContext currentContext] setDuration: 0.3];
[[self animator] setAlphaValue: 1.f];
[NSAnimationContext endGrouping];
}
- (void)zoomInWithOvershot: (NSRect)overshotFrame withFade: (BOOL)fade makeKey: (BOOL)makeKey
{
[self setAlphaValue: 0];
NSRect frame = [self frame];
ZoomWindow *zoomWindow = [self createZoomWindowWithRect: frame];
zoomWindow.alphaValue = 0;
[zoomWindow orderFront: self];
NSDictionary *windowResize = #{NSViewAnimationTargetKey: zoomWindow,
NSViewAnimationEndFrameKey: [NSValue valueWithRect: overshotFrame],
NSViewAnimationEffectKey: NSViewAnimationFadeInEffect};
NSArray *animations = #[windowResize];
NSViewAnimation *animation = [[NSViewAnimation alloc] initWithViewAnimations: animations];
[animation setAnimationBlockingMode: NSAnimationBlocking];
[animation setAnimationCurve: NSAnimationEaseIn];
[animation setDuration: 0.2];
[animation startAnimation];
zoomWindow.animationTimeMultiplier = 0.5;
[zoomWindow setFrame: frame display: YES animate: YES];
[self setAlphaValue: 1];
if (makeKey) {
[self makeKeyAndOrderFront: self];
} else {
[self orderFront: self];
}
[zoomWindow close];
}
This is implemented in an NSWindow category. So you can call:
- (void)zoomInWithOvershot: (NSRect)overshotFrame withFade: (BOOL)fade makeKey: (BOOL)makeKey
on any NSWindow.
I should add that I haven't been able to get both animations to run at the same time (fade and size), but the effect is quite similar to how NSPopover does it. Maybe someone else can fix the animation issue.
Needless to say this code works on 10.6 too where you don't have NSPopover (that's why I have written it in the first place).
i have implemented the following viewDidLoad() Method:
- (void)viewDidLoad {
[super viewDidLoad];
// loading images into the queue
loadImagesOperationQueue = [[NSOperationQueue alloc] init];
AFOpenFlowView *openFlow = self.view;
theControl = [[UIControl alloc] initWithFrame:self.view.frame];
NSString *imageName;
btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.frame = CGRectMake(10, 10, 40, 40);
[btn addTarget:self action:#selector(testMethode) forControlEvents:UIControlEventTouchUpInside];
[btn setTitle:#"<<" forState:UIControlStateNormal];
[btn setHidden:YES];
[theControl addSubview:btn];
for (int i=0; i < 10; i++) {
imageName = [[NSString alloc] initWithFormat:#"cover_%d.jpg", i];
imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:imageName]];
UIImage *aktuellesImage = imageView.image;
UIImage *scaledImage = [aktuellesImage scaleToSize:CGSizeMake(100.0f, 100.0f)];
[openFlow setImage:scaledImage forIndex:i];
// [(AFOpenFlowView *)self.view setImage:scaledImage forIndex:i];
[imageName release];
[aktuellesImage release];
}
[theControl addSubview:openFlow];
[theControl setUserInteractionEnabled:YES];
[(AFOpenFlowView *)self.view setNumberOfImages:10];
}
And the following touchesEnded() Method:
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[btn setHidden:NO];
}
But the touchesEnded doesn't work, and the Button will not shown when i touch the picture, does anybody know what is the Problem???
Greetings Marco
Make sure your view has user interaction enabled in order to register touches. This can be set in your View Controller thusly:
self.view.userInteractionEnabled = YES;