Can't access a UIWebView apparently coming from storyboard - objective-c

There's a view with one UIWebview in Portrait and two smaller UIWebViews in landscape - In landscape the two views represent the pages of a book and there's some pageview stuff going on. I can not determine where the second UIWebView is coming from. When the superview is loaded in landscape I can only access one of the the view on the left. The view on the right displays perfectly with the correct data, but I can't access it from the code until something causes the screen to redraw such as the page being "turned" or the orientation changing. Does this sound familiar to anyone?
Also, my NSLog function isn't working anymore and I have no idea where to click to make it come back. Please help.
Edit
Here's some code
// this is the function which is not accessing the view.
-(void) setCurrentTextSize:(int)cts {
for(int pageViewIndex = 0; pageViewIndex < [arrayOfReaderViewControllers count]; pageViewIndex++) {
readerViewController *r = [self arrayOfReaderViewControllers:pageViewIndex];
[r setCurrentTextSize:cts];
[r webViewDidFinishLoad:r.webView];
}
}
//this function populates arrayOfReaderViewControllers
-(void)initializeArrayOfReaderViewControllers {
readerViewController *vcLeft;
if([self.delegate isFirstLoad]) {
//we don't care what happens here 'cause it's not being called.
} else {
vcLeft = [readerViewController new];
if ( lastPageNumber > currentPageNumber) {
currentPageNumber = lastPageNumber;
[arrayOfReaderViewControllers replaceObjectAtIndex:0 withObject:[self jumpToPageVC:vcLeft]];
if(self.isLandscape) {
vcLeft = [arrayOfReaderViewControllers objectAtIndex:0];
[arrayOfReaderViewControllers replaceObjectAtIndex:1 withObject:[self getNextPageViewController:vcLeft]];
}
}
}
[self.delegate doMoreInitialization];
}

Related

using two finger pinch to zoom in collectionView Xcode

I have an app that has a collectionView inside a scrollView. I am using the following code to be able to zoom in and pan around.
-(void) viewDidLoad {
[super viewDidLoad];
twoFingerPinchA = [[UIPinchGestureRecognizer alloc]
initWithTarget:self
action:#selector(twoFingerPinch:)]
;
[self.view addGestureRecognizer:(twoFingerPinchA)];
}
-(void)twoFingerPinch:(UIPinchGestureRecognizer *)recognizer{
CGAffineTransform transform = CGAffineTransformMakeScale(twoFingerPinchA.scale, twoFingerPinchA.scale);
if (twoFingerPinchA.scale < 1) {
twoFingerPinchA.scale = 1;
}
if (twoFingerPinchA.scale >2) {
twoFingerPinchA.scale = 2;
}
self.scrolling.transform = transform;
}
This works well except when I am zoomed in and remove my fingers. When I put my two fingers back on the screen to zoom out or in again the view returns to not zoomed in. How can I get the view to stay zoomed in when I replace my two fingers on the screen to rezoom.
I have tried capturing the twoFingerPinchA.scale value which I can do. But I don't know how to set the initial value of the twoFingerPinchA.scale to that value as it alway returns to 1.
Any ideas?
So I am now trying to detect when two fingers touch the screen and when the two finger touch stops so I can save and insert the value of the twoFingerPinchA.scale.
However No matter what I put in I can't seem to detect the touches.
I have my controllers regular view, then I have a scroll view in it and then a collectionView inside of it.
I have enabled interaction and multiple touch for all views and tried to detect the touches in all view but don't get a call back. Here is my code.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"Event:%#",event);
// I don't even get this call back as a touch beginning on any view.
if ([[event touchesForView:self.view] count] >0) {
NSLog(#"touches");
}
}
So I figured this out.
First I used this code
-(void) viewWillAppear:(BOOL)animated{
NSString *pinchString = #"1.0";
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:pinchString forKey:#"pinchValue"];
}
//this was to make sure that the pinchValue key had a value when the app is first installed.
then I put this
switch ([twoFingerPinchA state]) {
case UIGestureRecognizerStatePossible:
{
}
break;
case UIGestureRecognizerStateBegan:
{
NSString *inPinch = [[NSUserDefaults standardUserDefaults] objectForKey:#"pinchValue"];
float Pinch = [inPinch floatValue];
twoFingerPinchA.scale = Pinch;
}
break;
case UIGestureRecognizerStateChanged:
{
}
break;
case UIGestureRecognizerStateEnded:
{
NSString *pinchString = [NSString stringWithFormat:#"%f",twoFingerPinchA.scale];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:pinchString forKey:#"pinchValue"];
}
break;
case UIGestureRecognizerStateCancelled:
{
}
break;
case UIGestureRecognizerStateFailed:
{
}
break;
}
in my
-(void)twoFingerPinch:(UIPinchGestureRecognizer *)recognizer{}
This stores the value of the twoFingerPinchA.scale in usersDefaults when the pinch ends
and
sets the twoFingerPinchA.scales to that stored value when it begins again. From there it adjust up and down /in and out according to this value.
Works great

Disabling NSView fade animation for NSView `setHidden:`

I am working on a project that has the concept of draggable controls, everything is working fine except that NSView seems to employ a fade in/out animation when calling setHidden:.
I have been able to work around the problem by changing the line session.animatesToStartingPositionsOnCancelOrFail = YES; to NO and implementing the image snapback myself with a custom animated NSWindow subclass. it looks great, but I know there must be an easier way.
I have tried:
using NSAnimationContext grouping with duration of 0 around the setHidden: calls
setting the view animations dictionary using various keys (alpha, hidden, isHidden) on the control and superview
overriding animationForKey: for both the control and its superview
I am not using CALayers and have even tried explicitly setting wantsLayer: to NO.
Does anybody know how to either disable this animation, or have a simpler solution then my animated NSWindow?
here is my stripped down altered code with the bare minimum to see what I'm talking about.
#implementation NSControl (DragControl)
- (NSDraggingSession*)beginDraggingSessionWithDraggingCell:(NSActionCell <NSDraggingSource> *)cell event:(NSEvent*) theEvent
{
NSImage* image = [self imageForCell:cell];
NSDraggingItem* di = [[NSDraggingItem alloc] initWithPasteboardWriter:image];
NSRect dragFrame = [self frameForCell:cell];
dragFrame.size = image.size;
[di setDraggingFrame:dragFrame contents:image];
NSArray* items = [NSArray arrayWithObject:di];
[self setHidden:YES];
return [self beginDraggingSessionWithItems:items event:theEvent source:cell];
}
- (NSRect)frameForCell:(NSCell*)cell
{
// override in multi-cell cubclasses!
return self.bounds;
}
- (NSImage*)imageForCell:(NSCell*)cell
{
return [self imageForCell:cell highlighted:[cell isHighlighted]];
}
- (NSImage*)imageForCell:(NSCell*)cell highlighted:(BOOL) highlight
{
// override in multicell cubclasses to just get an image of the dragged cell.
// for any single cell control we can just make sure that cell is the controls cell
if (cell == self.cell || cell == nil) { // nil signifies entire control
// basically a bitmap of the control
// NOTE: the cell is irrelevant when dealing with a single cell control
BOOL isHighlighted = [cell isHighlighted];
[cell setHighlighted:highlight];
NSRect cellFrame = [self frameForCell:cell];
// We COULD just draw the cell, to an NSImage, but button cells draw their content
// in a special way that would complicate that implementation (ex text alignment).
// subclasses that have multiple cells may wish to override this to only draw the cell
NSBitmapImageRep* rep = [self bitmapImageRepForCachingDisplayInRect:cellFrame];
NSImage* image = [[NSImage alloc] initWithSize:rep.size];
[self cacheDisplayInRect:cellFrame toBitmapImageRep:rep];
[image addRepresentation:rep];
// reset the original cell state
[cell setHighlighted:isHighlighted];
return image;
}
// cell doesnt belong to this control!
return nil;
}
#pragma mark NSDraggingDestination
- (void)draggingEnded:(id < NSDraggingInfo >)sender
{
[self setHidden:NO];
}
#end
#implementation NSActionCell (DragCell)
- (void)setControlView:(NSView *)view
{
// this is a bit of a hack, but the easiest way to make the control dragging work.
// force the control to accept image drags.
// the control will forward us the drag destination events via our DragControl category
[view registerForDraggedTypes:[NSImage imagePasteboardTypes]];
[super setControlView:view];
}
- (BOOL)trackMouse:(NSEvent *)theEvent inRect:(NSRect)cellFrame ofView:(NSView *)controlView untilMouseUp:(BOOL)untilMouseUp
{
BOOL result = NO;
NSPoint currentPoint = theEvent.locationInWindow;
BOOL done = NO;
BOOL trackContinously = [self startTrackingAt:currentPoint inView:controlView];
BOOL mouseIsUp = NO;
NSEvent *event = nil;
while (!done)
{
NSPoint lastPoint = currentPoint;
event = [NSApp nextEventMatchingMask:(NSLeftMouseUpMask|NSLeftMouseDraggedMask)
untilDate:[NSDate distantFuture]
inMode:NSEventTrackingRunLoopMode
dequeue:YES];
if (event)
{
currentPoint = event.locationInWindow;
// Send continueTracking.../stopTracking...
if (trackContinously)
{
if (![self continueTracking:lastPoint
at:currentPoint
inView:controlView])
{
done = YES;
[self stopTracking:lastPoint
at:currentPoint
inView:controlView
mouseIsUp:mouseIsUp];
}
if (self.isContinuous)
{
[NSApp sendAction:self.action
to:self.target
from:controlView];
}
}
mouseIsUp = (event.type == NSLeftMouseUp);
done = done || mouseIsUp;
if (untilMouseUp)
{
result = mouseIsUp;
} else {
// Check if the mouse left our cell rect
result = NSPointInRect([controlView
convertPoint:currentPoint
fromView:nil], cellFrame);
if (!result)
done = YES;
}
if (done && result && ![self isContinuous])
[NSApp sendAction:self.action
to:self.target
from:controlView];
else {
done = YES;
result = YES;
// this bit-o-magic executes on either a drag event or immidiately following timer expiration
// this initiates the control drag event using NSDragging protocols
NSControl* cv = (NSControl*)self.controlView;
NSDraggingSession* session = [cv beginDraggingSessionWithDraggingCell:self
event:theEvent];
// Note that you will get an ugly flash effect when the image returns if this is set to yes
// you can work around it by setting NO and faking the release by animating an NSWindowSubclass with the image as the content
// create the window in the drag ended method for NSDragOperationNone
// there is [probably a better and easier way around this behavior by playing with view animation properties.
session.animatesToStartingPositionsOnCancelOrFail = YES;
}
}
}
return result;
}
#pragma mark - NSDraggingSource Methods
- (NSDragOperation)draggingSession:(NSDraggingSession *)session sourceOperationMaskForDraggingContext:(NSDraggingContext)context
{
switch(context) {
case NSDraggingContextOutsideApplication:
return NSDragOperationNone;
break;
case NSDraggingContextWithinApplication:
default:
return NSDragOperationPrivate;
break;
}
}
- (void)draggingSession:(NSDraggingSession *)session endedAtPoint:(NSPoint)screenPoint operation:(NSDragOperation)operation
{
// now tell the control view the drag ended so it can do any cleanup it needs
// this is somewhat hackish
[self.controlView draggingEnded:nil];
}
#end
There must be a layer enabled somewhere in your view hierarchy, otherwise there wouldn't be a fade animation. Here is my way of disabling such animations:
#interface NoAnimationImageView : NSImageView
#end
#implementation NoAnimationImageView
+ (id)defaultAnimationForKey: (NSString *)key
{
return nil;
}
#end
The solution you already tried by setting the view animations dictionary should work. But not for the keys you mention but for the following. Use it somewhere before the animation is triggered the first time. If you have to do it on the window or view or both, I don't know.
NSMutableDictionary *animations = [NSMutableDictionary dictionaryWithDictionary:[[theViewOrTheWindow animator] animations];
[animations setObject:[NSNull null] forKey: NSAnimationTriggerOrderIn];
[animations setObject:[NSNull null] forKey: NSAnimationTriggerOrderOut];
[[theViewOrTheWindow animator] setAnimations:animations];
Or also just remove the keys if they are there (might not be the case as they are implicit / default):
NSMutableDictionary *animations = [NSMutableDictionary dictionaryWithDictionary:[[theViewOrTheWindow animator] animations];
[animations removeObjectForKey:NSAnimationTriggerOrderIn];
[animations removeObjectForKey:NSAnimationTriggerOrderOut];
[[theViewOrTheWindow animator] setAnimations:animations];
Ok. I figured out that the animation I'm seeing is not the control, the superview, nor the control's window. It appears that animatesToStartingPositionsOnCancelOrFail causes NSDraggingSession to create a window (observed with QuartzDebug) and put the drag image in it and it is this window that animates back to the origin and fades out before the setHidden: call is executed (i.e. before the drag operation is concluded).
Unfortunately, the window that it creates is not an NSWindow so creating a category on NSWindow doesn't disable the fade animation.
Secondly, there is no public way that I know of to get a handle on the window, so I can't attempt directly manipulating the window instance.
It looks like maybe my workaround is the best way to do this, after all its not far from what AppKit does for you anyway.
If anybody knows how to get a handle on this window, or what class it is I would be interested to know.

Image generator ( generateCGImagesAsynchronouslyForTimes method) doesn't give live results

Pretty new to cocoa development and really stuck with probably a fundamental problem.
So in short, my app UI looks like a simple window with a nsslider at the bottom. What I need is to generate N images and place them, onto N nsviews in my app window.
What it does so far:
I'm clicking on the slider (holding it) and dragging it. While I'm dragging it nothing happens to my views (pictures are not generated). When I release the slider the pictures got generated and my view get filled with them.
What I want:
- I need the views to be filled with pictures as I'm moving the slider.
I figured out the little check box on the NSSlider properties, which is continuous, and I'm using it, but my image generator still doesn't do anything until I release the slider.
Here is my code:
// slider move action
- (IBAction)sliderMove:(id)sender
{
[self generateProcess:[_slider floatValue];
}
// generation process
- (void) generateProcess:(Float64) startPoint
{
// create an array of times for frames to display
NSMutableArray *stops = [[NSMutableArray alloc] init];
for (int j = 0; j < _numOfFramesToDisplay; j++)
{
CMTime time = CMTimeMakeWithSeconds(startPoint, 60000);
[stops addObject:[NSValue valueWithCMTime:time]];
_currentPosition = initialTime; // set the current position to the last frame displayed
startPoint+=0.04; // the step between frames is 0.04sec
}
__block CMTime lastTime = CMTimeMake(-1, 1);
__block int count = 0;
[_imageGenerator generateCGImagesAsynchronouslyForTimes:stops
completionHandler:^(CMTime requestedTime, CGImageRef image, CMTime actualTime,AVAssetImageGeneratorResult result, NSError *error)
{
if (result == AVAssetImageGeneratorSucceeded)
{
if (CMTimeCompare(actualTime, lastTime) != 0)
{
NSLog(#"new frame found");
lastTime = actualTime;
}
else
{
NSLog(#"skipping");
return;
}
// place the image onto the view
NSRect rect = CGRectMake((count+0.5) * 110, 500, 100, 100);
NSImageView *iView = [[NSImageView alloc] initWithFrame:rect];
[iView setImageScaling:NSScaleToFit];
NSImage *myImage = [[NSImage alloc] initWithCGImage:image size:(NSSize){50.0,50.0}];
[iView setImage:myImage];
[self.windowForSheet.contentView addSubview: iView];
[_viewsToRemove addObject:iView];
}
if (result == AVAssetImageGeneratorFailed)
{
NSLog(#"Failed with error: %#", [error localizedDescription]);
}
if (result == AVAssetImageGeneratorCancelled)
{
NSLog(#"Canceled");
}
count++;
}];
}
}
If you have any thoughts or ideas, please share with me, I will really appreciate it!
Thank you
In order to make your NSSlider continuous, open your window controller's XIB file in Interface Builder and click on the NSSlider. Then, open the Utilities area
select the Attributes Inspector
and check the "Continuous" checkbox
under the Control header. Once you've done this, your IBAction sliderMove: will be called as the slider is moved rather than once the mouse is released.
Note: Alternatively, with an
NSSlider *slider = //...
one can simply call
[slider setContinuous:YES];

Creating a hidden UISegmentedControl in a UITableView

Like the iBooks app, when you pull down the tableview, a search bar and segmented control appear, to allow you to search and switch between two types of views.
It sticks in that position when you pull down far enough, and alternatively, gets hidden when you pull the tableview up enough.
I am trying to implement the same thing with a UISegmentedControl.
So far I have added a segmented control successfully as a subview to the table. (It has a negative Y frame so make it stick above the tableview).
I have also implemented this code:
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView {
float yOffset = scrollView.contentOffset.y;
if (yOffset < -70) {
[scrollView setContentOffset:CGPointMake(0.0f, -70.0f) animated:YES];
} else if (yOffset > -10) {
[scrollView setContentOffset:CGPointMake(0.0f, -11.0f) animated:YES];
}
}
This works great, until I try using the segmented control. Where the table will just act like it is scrolling, ignoring the segmented control altogether (i.e. if I tap on a segment, it doesn't even get selected, instead the table scrolls up, hiding the segmented control.
I did use the scrollViewDidScroll method but this made it buggy and the scrolling jumpy.
I also tried to make the segmented control's exclusiveTouch = YES, but this had no effect whatsoever.
I would be thankful for all help! thanks in advance!
Here is my code which works:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
//
// Table view
//
if ([scrollView isKindOfClass:[myTableView class]]) {
//
// Discover top
//
CGFloat topY = scrollView.contentOffset.y + scrollView.contentInset.top;
if (topY <= self.tableHeaderHeightConstraint.constant) {
[self setIsScrolledToTop:YES];
} else {
[self setIsScrolledToTop:NO];
}
}
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
//
// Table view
//
if ([scrollView isKindOfClass:[myTableView class]]) {
//
// Toggle favourite category
//
if ([self isScrolledToTop]) {
//
// Show
//
} else {
//
// Hide
//
}
}
}
Edited the above code to make it a bit more generic, but syntactically its correct

UIPageViewController black screen on iPad when loaded in landscape

I'm developing a UIPageViewController based app which works both on iPhone and iPad. With the iPhone there are no problems, since the spine location of the controller is always set to UIPageViewControllerSpineLocationMin. In the iPad however, I need to set the spine location to UIPageViewControllerSpineLocationMid when the device orientation is set to Landscape.
I have a strange issue only when i Load the controller in Landscape orientation, the following video will explain the situation..
YouTubeVideo
As you can see, everything works perfectly when i load the controller in portrait and also after i rotate the device when i load in landscape.
I really can't figure out where is the problem. Here is the code I use to load the controllers:
if (chapter.controllers) {
currentPage = [chapter bookPageForCharIndex:location];
//Load the correct controller for the bookmark page
NSArray *array = nil;
if (currentPage >= 0 && currentPage < chapter.controllers.count) {
if (UIDeviceOrientationIsLandscape([[UIDevice currentDevice]orientation]) && UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPad) {
[self setDoubleSided:YES];
if (chapter.controllers.count > currentPage+1) {
array = [[NSArray alloc]initWithObjects:[chapter.controllers objectAtIndex:currentPage],[chapter.controllers objectAtIndex:currentPage+1],nil];
}
else {
array = [[NSArray alloc]initWithObjects:[chapter.controllers objectAtIndex:currentPage],[[[LSBookPageViewController alloc]init]autorelease],nil];
}
}
else {
array = [[NSArray alloc]initWithObjects:[chapter.controllers objectAtIndex:currentPage],nil];
}
}
else {
return;
}
[self playSoundsOfChapter:chapter];
if (isRestarting) {
[self setViewControllers:array
direction:UIPageViewControllerNavigationDirectionReverse
animated:YES
completion:nil];
isRestarting = NO;
}
else {
[self setViewControllers:array
direction:UIPageViewControllerNavigationDirectionForward
animated:YES
completion:nil];
}
[array release];
}
I think the error is in the first else clause. You should set a breakpoint after checking for device orientation and device, and step through the code. I would guess that your array comes back empty.