Drag UIButton inside limits - iphone

I have searched around the web but haven't found a clear answer. I use a panGestureRecognizer to drag a slider button on the x axis, but I don't want to be able to drag if outside my slider track. I have managed to do some stuff, but it doesn't really work as it should. Here is my code
-(void) handleDrag:(UIPanGestureRecognizer*)panGestureRecognizer
{
if (panGestureRecognizer.state==UIGestureRecognizerStateBegan)
{
}
if (panGestureRecognizer.state==UIGestureRecognizerStateChanged)
{
CGPoint touchPoint=[panGestureRecognizer locationOfTouch:0 inView:self];
if (sliderButton.center.x > first.center.x-0.5f && sliderButton.center.x-0.5f < third.center.x && CGRectContainsPoint(sliderButton.frame, touchPoint) ) // if we are still in the slidertrack and the touch is on the sliderbutton
{
CGPoint newPoint=CGPointMake(touchPoint.x+0.5,sliderButton.center.y);
sliderButton.center=newPoint;
}
}
}
This is my slider
The first button is "Thu", the second one is "Fri" and the third is "Sat". I want my sliderButton to only move inside those boundaries.
Thank you.

Related

Can a gesture recogniser control iOS display brightness?

I'd like to let the user control the brightness in an iOS app using a gesture recogniser to swipe up and down. Can gestures even control brightness? I've done it before using a slider and the brightness property of UIScreen...
[UIScreen mainScreen].brightness = 0.5;
I want to be able to control the brightness as you would with a slider (like the iBooks app) but instead of a slider use a gesture recogniser. The idea is that the gesture continuously changes the brightness value as long as a touch is being recognised and the finger moves either up or down. I wasn't sure if I should use a pan gesture and limit the direction somehow to up or down, or use a swipe gesture (but obviously that detects one swipe and doesn't continuously update a value).
Perhaps moving a finger up a specified amount on the screen increments the 0.0 - 1.0 range of the brightness value. I'm not sure how to approach it so i'm just thinking out loud.
Any ideas? Thanks a lot.
EDIT: Ok so I found this code on another similar question
- (void)pan:(UIPanGestureRecognizer *)recognizer
{
if ((recognizer.state == UIGestureRecognizerStateChanged) ||
(recognizer.state == UIGestureRecognizerStateEnded))
{
CGPoint velocity = [recognizer velocityInView:self.view];
if (velocity.y >0) // panning down
{
self.brightness = self.brightness -.02;
NSLog (#"Decreasing brigntness in pan");
}
else // panning up
{
self.brightness = self.brightness +.02;
NSLog (#"Increasing brigntness in pan");
}
}
}
It seems to at least print an NSLog every time you gesture up or down, I guess I now just want to know if there's a way to use NSLog to find out the current brightness value rather than it just telling you if it detected a gesture (unless i'm being stupid and the NSLog i'm using already tells me that?). Thanks, this would be really useful to know because I can't run on the device. :-D
To Increase and decrease the brightness of the Screen
For Swift
1)How to Add PanGesture in View
let panGesture = UIPanGestureRecognizer.init(target: self, action: #selector(pan(recognizer:)))
panGesture.delegate = self
panGesture.minimumNumberOfTouches = 1
mp.view.addGestureRecognizer(panGesture)
2)Code to increase and Decrease the Brightness of Screen using PanGesture
func pan(recognizer:UIPanGestureRecognizer){
if recognizer.state == UIGestureRecognizerState.changed || recognizer.state == UIGestureRecognizerState.ended {
let velocity:CGPoint = recognizer.velocity(in: self.view)
if velocity.y > 0{
var brightness: Float = Float(UIScreen.main.brightness)
brightness = brightness - 0.03
UIScreen.main.brightness = CGFloat(brightness)
print("Decrease brigntness in pan")
}
else {
var brightness: Float = Float(UIScreen.main.brightness)
brightness = brightness + 0.03
UIScreen.main.brightness = CGFloat(brightness)
print("Increase brigntness in pan")
}
}
}
Yes! Just use a UIPanGestureRecognizer and adjust the brightness value accordingly as the pan gesture is called. Check the Apple docs.

UIPanGestureRecognizer Not Panning In One Direction

I've been battling with this for about an hour. I am trying to have my UIView to pans the same way the iOS Facebook app pans the main UIView and shows a navigation table at the left. So when you swipe to the right, it will pan all the way to the right and show you the navigation table. You can slide it back to the left. So it's basically like a slider.
I have a UIPanGestureRecognizer assigned to the UIView. And here is my selector for the gesture:
- (void)swipeDetected:(UIPanGestureRecognizer *)recognizer
{
CGPoint newTranslation = [recognizer translationInView:self.view];
NSLog(#"%f", newTranslation.x + lastTranslation.x);
// only pan appropriately when view is within correct bounds
if (lastTranslation.x + newTranslation.x >= 0 && lastTranslation.x + newTranslation.x <= 255)
{
self.navController.view.transform = CGAffineTransformMakeTranslation(newTranslation.x, 0);
if (recognizer.state == UIGestureRecognizerStateEnded) {
// if navcontroller is at less than 145px, snap back to 0
if (newTranslation.x + lastTranslation.x <= 145)
self.navController.view.transform = CGAffineTransformMakeTranslation(0, 0);
// else if its at more than 145px, snap to 255
else if (newTranslation.x + lastTranslation.x >= 145)
self.navController.view.transform = CGAffineTransformMakeTranslation(255, 0);
lastTranslation.x += newTranslation.x;
}
}
}
This works perfectly when sliding the UIView to the right. It will then stick at 255px so a part of it is shown on the screen, and so it does not disappear. However, when it's at the position, when I slide it back to the left, it jumps all the way to the origin instead of following the pan gesture.
Why is that? How can I fix it?
Thanks

UIScrollView ContentOffset not Reaching Edge of Screen

I'm having a problem with UIScrollView, not sure if it's a bug or not, but it's occurring when I implement a UIScrollView with its delegate and a zoomable / pannable image.
First off, when I pan the image, it's possible that the contentOffset can be a non integer value (.5). For certain zoomScales, when I pan the image all the way to the edge, it's falling a half pixel shy of reaching the edge because of this.
It's a very small thing, but in my app I have to drag objects around the screen, and if I drag an object to the corner, you can notice it.
I've implemented the following to try and correct the problem and make it so the contentOffset has to be a whole value:
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
if (targetContentOffset->x != ceilf(targetContentOffset->x))
{
if (velocity.x > 0)
{
targetContentOffset->x = ceilf(targetContentOffset->x);
}
else
{
targetContentOffset->x = floorf(targetContentOffset->x);
}
}
if (targetContentOffset->y != ceilf(targetContentOffset->y))
{
if (velocity.y > 0)
{
targetContentOffset->y = ceilf(targetContentOffset->y);
}
else
{
targetContentOffset->y = floorf(targetContentOffset->y);
}
}
}
However, it doesn't seem to be working as my targetContentOffset is completely different than the contentOffset property.
Does anyone a) why this bug is occurring or b) how to fix it using the above delegate method or some other means?
Alternatively this method implementation may work for you also.
-(void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
Looking at your comments below, you may have to implement multiple methods. The one above or the one stated in the other answer post for when it slows to a stop, just to make sure you touch your edge condition, and the method you already have to process for the velocity points.

How do you modify this sample code to stop Image Views from stacking?

http://developer.apple.com/library/ios/#samplecode/Touches/Introduction/Intro.html
I'm new to IOS development, and have been playing around with the IOS dev sample code, trying to learn how things work, etc... I came across this sample code (the classic version, not the gesture recognizers ver.) that does everything I'm looking for, except one thing. When the image views are dragged over another image view, they begin stacking up, and you have to double click the image to separate them.
I've spent forever trying to figure out how to make them not stack up. I think I have to store that a piece is getting being moved in an ivar, and stop it from getting the position of the other views... But I'm not sure how to go about doing it. If someone has the time to modify the sample code to not stack pieces, I'd really appreciate it! I'm dying to find out the solution after the forever I spent trying to do it!
I'll try to be a little specific with what I'm trying to do here... I've made 26 of these image views, making them each a letter of the alphabet. I have 13 image views in two rows. A-M & N-Z. Currently, if I drag the A tile down from the top row, moving it down to a "spelling area" I have to cross over the N-Z row. When I do, the "A" tile (image view) picks up any tile it hovers over. So if I drag the A straight down, it's going to pick up the N tile, because it's going to hover right over it, before getting down to the "spelling" area.
Thanks in advance for any help or direction you can give me!
Well you have this function in the sample code
// Checks to see which view, or views, the point is in and then calls a method to perform the closing animation,
// which is to return the piece to its original size, as if it is being put down by the user.
-(void)dispatchTouchEndEvent:(UIView *)theView toPosition:(CGPoint)position
{
// Check to see which view, or views, the point is in and then animate to that position.
if (CGRectContainsPoint([firstPieceView frame], position)) {
[self animateView:firstPieceView toPosition: position];
}
if (CGRectContainsPoint([secondPieceView frame], position)) {
[self animateView:secondPieceView toPosition: position];
}
if (CGRectContainsPoint([thirdPieceView frame], position)) {
[self animateView:thirdPieceView toPosition: position];
}
// If one piece obscures another, display a message so the user can move the pieces apart
if (CGPointEqualToPoint(firstPieceView.center, secondPieceView.center) ||
CGPointEqualToPoint(firstPieceView.center, thirdPieceView.center) ||
CGPointEqualToPoint(secondPieceView.center, thirdPieceView.center)) {
touchInstructionsText.text = #"Double tap the background to move the pieces apart.";
piecesOnTop = YES;
} else {
piecesOnTop = NO;
}
}
wich you can try to modify to
// Checks to see which view, or views, the point is in and then calls a method to perform the closing animation,
// which is to return the piece to its original size, as if it is being put down by the user.
-(void)dispatchTouchEndEvent:(UIView *)theView toPosition:(CGPoint)position
{
// Check to see which view, or views, the point is in and then animate to that position.
if (CGRectContainsPoint([firstPieceView frame], position)) {
[self animateView:firstPieceView toPosition: position];
}
if (CGRectContainsPoint([secondPieceView frame], position)) {
[self animateView:secondPieceView toPosition: position];
}
if (CGRectContainsPoint([thirdPieceView frame], position)) {
[self animateView:thirdPieceView toPosition: position];
}
// If one piece obscures another, display a message so the user can move the pieces apart
if (CGPointEqualToPoint(firstPieceView.center, secondPieceView.center) ||
CGPointEqualToPoint(firstPieceView.center, thirdPieceView.center) ||
CGPointEqualToPoint(secondPieceView.center, thirdPieceView.center)) {
if (firstPieceView.center.x == secondPieceView.center.x)
secondPieceView.center = CGPointMake(firstPieceView.center.x - 50, firstPieceView.center.y - 50);
if (firstPieceView.center.x == thirdPieceView.center.x)
thirdPieceView.center = CGPointMake(firstPieceView.center.x + 50, firstPieceView.center.y + 50);
if (secondPieceView.center.x == thirdPieceView.center.x)
thirdPieceView.center = CGPointMake(secondPieceView.center.x + 50, secondPieceView.center.y + 50);
touchInstructionsText.text = #"";
} else {
piecesOnTop = NO;
}
}
Let me know if it does what you want...

PagingEnabled for multiple pages in UIScrollView

Edit: See the answer below.
I finally give up and come here to ask you for my problem...
I'm using a UIScrollView for a scrolling menus with little icons.
On each page, with paging enabled, there's an icon in the center, and 2 and a half other visible icons on the left and right. I can move from one icon to its neighbour, and that is fine, but the point is that if I do a fast scrolling, it will not move from more than 3 icons, which is the width of the screen.
What I would want is to be able to scroll on more than 3 icons, and that the magnet behaviour is only triggered when it's slowing down.
I've tried to schedule the scroll view to calculate its velocity, and set the pagingEnabled attribute to NO when it's moving fast and YES again when it's slowing down, but as soon as it is set to YES, the view comes back very fast at its original position, as if it was not detecting that I had brought it to a new page. Would anyone know why it does this? And if I have a way to tell the view "ok, now the paging is enabled but look, you're 15 pages later. Just center on the current page, don't come back at the beginning."
Here's my update function (if it can help):
-(void)update:(ccTime)dt
{
float velocity = fabsf((self.previousOffset-self.scrollView.contentOffset.y)/dt);
self.previousOffset = self.scrollView.contentOffset.y;
CCLOG(#"Velocity: %f", velocity);
if(self.scrollView.pagingEnabled)
{
if(velocity > 100)
{
self.scrollView.pagingEnabled = NO;
}
}
else
{
if(velocity < 100)
{
self.scrollView.pagingEnabled = YES;
}
}
}
I finally found a solution, which was pretty obvious, but that I did not see at the beginning, by using setContentOffset on the scrollView.
Here is the new update function:
-(void)update:(ccTime)dt
{
float velocity = 1000;
if(self.previousOffset)
{
velocity = fabsf((self.previousOffset-self.scrollView.contentOffset.y)/dt);
}
self.previousOffset = self.scrollView.contentOffset.y;
if(velocity < 300)
{
CGSize screenSize = [[CCDirector sharedDirector] winSize];
float halfScreen = screenSize.width/2;
CCLayer *panel = (CCLayer *)[self getChildByTag:1];
SQScrollViewMenu *menu = (SQScrollViewMenu *)[panel getChildByTag:1];
SQMissionItem *currentItem = (SQMissionItem *)[menu getChildByTag:currentPage];
float contentOffsetY = [self.scrollView contentOffset].y;
CCLOG(#"Currentpage: %i ; currentoffsetY: %f", currentPage, contentOffsetY);
float distance = contentOffsetY + [currentItem position].x - halfScreen + panel.position.x + menu.position.x + panel.parent.position.x - 60;
CCLOG(#"Which gives a distance of: %f", distance);
[self.scrollView setContentOffset:CGPointMake(0, distance) animated:YES];
self.previousOffset = 0;
[self unschedule:#selector(update:)];
CCLOG(#"Is unscheduled");
}
}
And it is almost working... at least, it is on simulator. But as soon as I try it on my iPhone 4, it does not work anymore. It always go into that update function, but 7 times among 8, it just blocks the scrollView as it is and does not drags it back to the position I give it... but sometimes it does.
Would anyone have an idea? I found similar issues on the net, but none of them could resolve this...