Keep UICollectionViewCell centered after Zooming with UIPinchGestureRecognizer - uicollectionview

I'm having this issue. I change the scale and as well the transition of the view of a UICollectionViewCell, for doing zoom in the position of my fingers do the UIPinchGesture. But after that, the position of the view changes and the view go off the screen and its bounds. I want that the Gesture View get back to its correct position.
This is what is happening:
I have tried to assign a CGAffineTransformIdentity to the view if the center of the cell changes, but after the Scale and the Translate, its center always changes, so its frame as well.
The code in UIGestureRecognizerStateEnded:
if ([gesture state] == UIGestureRecognizerStateEnded){
//Get the Cell that is getting zoomed
CGPoint initialPinchPoint = [gesture locationInView:self.collectionView];
NSIndexPath* pinchedCellPath = [self.collectionView indexPathForItemAtPoint:initialPinchPoint];
SBQPhotosDetailCollectionViewCell *cell=[[SBQPhotosDetailCollectionViewCell alloc] init];
cell=(SBQPhotosDetailCollectionViewCell *)[self.collectionView cellForItemAtIndexPath:pinchedCellPath];
//Check ifs frame with the gesture of the Pinch
if ((cell.frame.origin.x != [gesture view].frame.origin.x) || (cell.frame.origin.y != [gesture view].frame.origin.y)){
[gesture view].transform = CGAffineTransformIdentity;
}
}
I would like to apply the CGAffineTransformIdentity only if the view of the Gesture change its center, position, but not if the view got zoomed.
Thanks

Related

Part of UIButton stops responding to touch after having its height increased

I have a view, embedded into a container that it itself inside a UIScrollView.
This view contains a text aligned to its edges as well as a button, again aligned to edges.
When launching the controller view, inside viewDidLayoutSubviews, I get the actual real height of the screen, then I call the view to be resized this way :
- (void)viewDidLayoutSubviews {
[self log:#"ViewDidLayoutSubviews"];
//::.. change scroll height according to main view ..::
float mainHeight = _subMainView.frame.size.height;
float scrollHeight = mainHeight - _scrollView.frame.origin.y;
_scrollView.frame = CGRectMake(_scrollView.frame.origin.x, _scrollView.frame.origin.y, _scrollView.frame.size.width, scrollHeight);
//::.. find buttons in child ..::
UIViewController *child = [self.childViewControllers lastObject];
//::.. Get only block views ::..
NSArray *blockViews = [myTools getAllSubviewsFromView:child.view ofClass:[UIView class] byTagFrom:1000 toTag:1010];
[self resizeViews:blockViews intoFrame:_scrollView.frame withVerticalPadding:16.0f andTopMargin:(31.0f+16.0f) andBottomMargin:0.0f andLeftMargin:16.0f andRightMargin:16.0f];
NSArray *buttons = [myTools getAllSubviewsFromView:child.view ofClass:[UIButton class]];
[self resizeViews:buttons intoFrame:_scrollView.frame withVerticalPadding:16.0f andTopMargin:(31.0f+16.0f) andBottomMargin:0.0f andLeftMargin:16.0f andRightMargin:16.0f];
for (UIButton *button in buttons) {
[button invalidateIntrinsicContentSize];
}
}
And here is the resize code in question :
+ (void)resizeViews:(NSArray *)views intoFrame:(CGRect)parentFrame withVerticalPadding:(float)verticalPadding andTopMargin:(float)topMargin andBottomMargin:(float)bottomMargin andLeftMargin:(float)leftMargin andRightMargin:(float)rightMargin {
float blockHeight = ((parentFrame.size.height - topMargin - bottomMargin) / views.count);
blockHeight -= verticalPadding;
float origin = topMargin;
for (UIView *aView in views) {
[aView layoutIfNeeded];
for (NSLayoutConstraint *constraint in aView.constraints) {
if (constraint.firstAttribute == NSLayoutAttributeHeight) {
constraint.constant = blockHeight;
break;
}
}
origin += blockHeight + verticalPadding;
[aView setNeedsUpdateConstraints];
[aView layoutIfNeeded];
}
}
The visual result is good because both views and there content (the buttons) are correctly resized (the button is aligned centered vertically and horizontally so it is easy to show the good alignment).
However, the first button has is whole area touchable where the second one, under it, can be touched only on its upper height, before its middle...
Can't understand how it is possible that a button, who's size is good, become untouchable on its whole part ?
Any help ? :)
Thanks a lot.

ScrollRectToVisible function

I have an UIScrollview and which contains UIView as a subview like,
here i can able to drag the UIView inside the ScrollView, when the uiview goes to at END RIGHT or END LEFT the uiview disappears inside scrollview, after that i has to scroll the scrollview then i can able to see the uiview, here i need to SCROLL THE SCROLLVIEW when uiview comes at the rightside or left side, for that i used this code but not working.
[myscrollview scrollRectToVisible:myview.frame animated:YES];
Here I have used on UIButton (as it is already used in one of my application I dont need to write whole code again)
[cropRectangleButton addTarget:self action:#selector(imageMoved:withEvent:) forControlEvents:UIControlEventTouchDragInside];
The cropRectangleButton is one UIButton and the imageMoved:withEvent: method is as below
- (IBAction) imageMoved:(id)sender withEvent:(UIEvent *)event
{
CGPoint point = [[[event allTouches] anyObject] locationInView:self.view];
CGPoint prev = lastTouchDownPoint;
lastTouchDownPoint = point;
CGFloat diffX = point.x - prev.x;
CGFloat diffY = point.y - prev.y;
UIControl *button = sender;
CGRect newFrame = button.frame;
newFrame.origin.x += diffX;
newFrame.origin.y += diffY;
scrollView.contentSize = CGSizeMake(2*scrollView.frame.size.width, scrollView.frame.size.height);
[scrollView scrollRectToVisible:newFrame animated:YES];
button.frame = newFrame;
}
Here I change my contentSize of scrollView as it is very narrow to test that the scrollView is scrolling or not you don't need that line of code.
And when I drag the button left the scrollView is also automatically scrolled to the button frame to show the whole button try to implement this using UIView and if not possible just put one transparant UIButton on your view fully covered the view and you it to do the drag :)

Presenting a view by pulling from the top of the view

So I am planning to do a different way to display history in my iPad app and I think user could pull up the history view from the bottom, should I just place UIView there and add gesture recognizer for it? Is there any "right" way to do this? I want to make the user actually able to drag the view from the bottom. If you don't understand, ask away and I will elaborate.
You have the right idea. You'd use a UIPanGestureRecognizer to update the view's frame. Keep in mind that you'll have to have something for the user to "pull" on visible at all times - I don't think you'll be able to hide the view completely off screen.
Something like this would go in the implementation of the object you choose to handle events from your gesture recognizer (this sample assumes it's your view controller):
- (void)handleDrag:(UIPanGestureRecognizer *)gesture {
if (gesture.state == UIGestureRecognizerStateChanged ||
gesture.state == UIGestureRecognizerStateEnded) {
CGPoint translation = [gesture translationInView:self.view];
CGRect newFrame = historyView.frame;
newFrame.origin.x = newFrame.origin.x + translation.x;
newFrame.origin.y = newFrame.origin.y + translation.y;
historyView.frame = newFrame;
// you need to reset this to zero each time
// or the effect stacks and that's not what you want
[gesture setTranslation:CGPointZero inView:self.view];
}
}

UIView cut off in landscape mode

I have several UIViews added as subViews to my main view controller. The way I have the views laid out looks fine in portrait mode, however, when it is tilted in to landscape mode, the bottom parts of the subviews gets cut off. I figured if I set the height of the frame, it would allow the screen to scroll and thus reveal the parts of the subViews that were cut off - but it doesn't.
- (void)didRotate:(NSNotification *)notification {
UIDeviceOrientation orientation = [[notification object] orientation];
if (orientation == UIDeviceOrientationLandscapeLeft) {
self.view.frame = CGRectMake(0.0, 0.0, 1024.0, maxHeight);
} else if (orientation == UIDeviceOrientationLandscapeRight) {
self.view.frame = CGRectMake(0.0, 0.0, 1024.0, maxHeight);
}
}
I also tried adding a UIScrollView to the main view, then adding the afore mentioned subViews to the scrollView
- (void)viewDidLoad
{
scrollView = [[UIScrollView alloc] initWithFrame:self.view.frame];
[self.view addSubview:scrollView];
//add views to scrollView
[super viewDidLoad];
}
How can I make the main view "scroll" if the sub-views exceed the screen size?
After you add your views to the scroll view, you must set the contentSize property of the scroll view so that the scroll view knows there's content to be scrolled to.

How to pass scrolling input to a different view

This site really is awesome.
I have what is hopefully a simple question this time. I would like to pass any scrolling input from the user (could be wheel, touchpad, etc) to an NSScrollView which contains my own subviews.
At the moment if the user scrolls just on the documentView (outside of my subviews' frames) the scroll works normally but if they scroll while the cursor is over a subview nothing happens. So basically I'd like to have the subview recognise the scroll event and pass it back to the scroll view.
Any help is greatly appreciated.
Cheers.
EDIT:
Here is the code I'm using to add the subviews to the documentView
_milestoneView and _activityView are both NSView subclasses which have a corresponding nib (created with instantiateNibWithOwner and objects hooked up accordingly) they contain a NSTextField, PXListView and some have a NSProgressIndicator.
-(void)useProject:(NSNumber *)projectId
{
[self resetView];
NSRect bounds = [[self view] bounds];
NSRect defaultFrame = NSMakeRect(20, NSMaxY(bounds)-93, NSMaxX(bounds)-20, 50);
//Prepare the milestone view
if (_milestoneView == nil)
_milestoneView = [MilestoneView milestoneViewFromNibWithFrame:defaultFrame withProject:[BCLocalFetch projectForId:projectId]];
[_milestoneView reloadList];
//Prepare the activity view
if (_activityView == nil)
_activityView = [ActivityView activityViewFromNibWithFrame:defaultFrame withProject:[BCLocalFetch projectForId:projectId]];
[self refresh];
}
I then use the refresh method to reposition them as the content sizes vary so I wanted to have a separate method.
-(void)refresh
{
//Position the milestones first
[_milestoneView setFrameOrigin:NSMakePoint(20, NSMaxY([[self view] bounds])-[_milestoneView frame].size.height-60)];
if ([[_milestoneView milestones] count] > 0)
[[self view] addSubview:_milestoneView];
//Now the activity view
[_activityView setFrameOrigin:NSMakePoint(20, [_milestoneView frame].origin.y-[_activityView frame].size.height-20)];
[[self view] addSubview:_activityView];
[self autosizeView];
}
-(void)autosizeView
{
//Resize the view to accommodate all subviews
NSRect oldFrame = [[self view] frame];
CGFloat lastY = [_activityView frame].origin.y;
if (lastY < 0) {
CGFloat newHeight = oldFrame.size.height + (-lastY);
[[self view] setFrameSize:NSMakeSize(oldFrame.size.width, newHeight)];
}
[[NSNotificationCenter defaultCenter] postNotificationName:#"BBContentDidResizeNotification" object:self];
}
Ok so I came back to the issue and finally got it worked out. The implementation was actually quite simple.
I added a property to PXListView to point to the NSScrollView that is to be scrolled.
I then implemented NSResponder's scrollWheel: method like this:
-(void)scrollWheel:(NSEvent *)theEvent
{
//Pass scrolling to the superview
[_scrollHandler scrollWheel:theEvent];
}
And all is well!